假设现在有需求如下:比较2个相同类型的不同对象,找到这2个对象的不同的地方,并展示记录一下。当然说的是相互对应的属性啦。

带着这个需求,看下面的例子。(我写代码的都不嫌弃长,你看代码的就也别嫌弃咯。)

package com.lxk.test;import com.google.common.collect.Lists;
import com.lxk.model.Car;
import com.lxk.model.Dog;import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;/*** Compare the difference between two objects* <p>* Created by lxk on 2017/3/12*/
public class CompareObject {public static void main(String[] args) {Dog dog1 = new Dog("大师兄的dog", true, true);Dog dog2 = new Dog("大师兄的dog", false, false);List<Dog> dogs = Lists.newArrayList();List<Dog> myDogs = Lists.newArrayList();dogs.add(dog1);myDogs.add(dog2);List<String> boys = Lists.newArrayList("tom", "jerry", "jack");//List<String> myBoys = Lists.newArrayList("tom", "jerry", "jack");//这行注释打开,下行代码注释掉,则boys属性就相同了List<String> myBoys = Lists.newArrayList("tom hanks", "gery", "pul");Car car1 = new Car("q7", 182, dogs, boys);Car car2 = new Car("a6", 152, myDogs, myBoys);contrastObj(car1, car2);}private static void contrastObj(Object obj1, Object obj2) {if (obj1 instanceof Car && obj2 instanceof Car) {Car pojo1 = (Car) obj1;Car pojo2 = (Car) obj2;List<String> textList = Lists.newArrayList();try {Class clazz = pojo1.getClass();Field[] fields = pojo1.getClass().getDeclaredFields();for (Field field : fields) {PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);Method getMethod = pd.getReadMethod();Object o1 = getMethod.invoke(pojo1);Object o2 = getMethod.invoke(pojo2);String s1 = o1 == null ? "" : o1.toString();//避免空指针异常String s2 = o2 == null ? "" : o2.toString();//避免空指针异常//思考下面注释的这一行:会bug的,虽然被try catch了,程序没报错,但是结果不是我们想要的//if (!o1.toString().equals(o2.toString())) {if (!s1.equals(s2)) {textList.add("不一样的属性:" + field.getName() + " 属性值:[" + s1 + "," + s2 + "]");}}} catch (Exception e) {System.out.println(e.getMessage());}for (Object object : textList) {System.out.println(object);}}}
}

代码里面使用的两个model,也是极为重要的。

Car的bean如下:

package com.lxk.model;import java.util.List;public class Car implements Comparable<Car> {private String sign;private int price;private List<Dog> myDog;private List<String> boys;public Car(String sign, int price) {this.sign = sign;this.price = price;}public Car(String sign, int price, List<Dog> myDog) {this.sign = sign;this.price = price;this.myDog = myDog;}public Car(String sign, int price, List<Dog> myDog, List<String> boys) {this.sign = sign;this.price = price;this.myDog = myDog;this.boys = boys;}//getter and setter}

Dog的bean如下:

package com.lxk.model;/*** 测试boolean属性的getter和setter* <p>* Created by lxk on 2016/12/23*/
public class Dog {private String name;private boolean isLoyal;//是忠诚的private boolean alive;//活蹦乱跳的public Dog(boolean isLoyal, boolean alive) {this.isLoyal = isLoyal;this.alive = alive;}public Dog(String name, boolean isLoyal, boolean alive) {this.name = name;this.isLoyal = isLoyal;this.alive = alive;}//getter and setter//@Override//public boolean equals(Object o) {//    if (this == o) return true;//    if (!(o instanceof Dog)) return false;//    Dog dog = (Dog) o;//    return Objects.equal(getName(), dog.getName());//}////@Override//public int hashCode() {//    return Objects.hashCode(getName());//}
}

先不要在意,我为什么把Dog bean的hashcode和equal方法给注释啦先。

如上代码的执行结果 图,如下:

从代码的执行情况看,可以得到,我们要的不同的属性的名称,当然你是可以把这些sign price myDog  boys这些属性,再次转化成你要的文字。

注意后面的对应的属性值。类型是String 或者int 或者List<String>这些类型,直接使用toString()方法就可以把他转化成字符串了,但是看到myDog属性,这个自定义对象的list的toString()的时候,却是两个地址,对,这个就是他们的内存堆地址吧。可以看到,2个集合所指向的引用是不一样的。

现在,看第二种情况,就是把Dog bean里面的注释,打开。其他地方的代码不动。

然后指向结果如下图:

可以看到,现在 myDog属性的值,竟然一样啦。但是,我们可以清楚的看到,我们的两个Car对象里面包含的Dog对象是不一样的。只是,这2个Car对象的两个Dog对象的name属性是一样的,都是:大师兄的dog。

因为,你在Dog bean里面已经重写了hashcode和equal两个方法,那么在new对象的时候,他就会只根据这个name属性去生成hashcode,他决定放在堆内存的什么位置。

那么就算,在我们看起来,那两个Car对象里面的两个Dog对象是不同的,但是计算机内存却认为是相同的。而且,toString()方法得到的结果也是跟他的内存地址有关系的。所以,比较结果,就是一样的。

这就是意外。

在实际开发中,我们也会有这种情况,可能因为某种需要,我们把某个bean的hashcode和equal方法给重写了。就像我这里 的这个Dog类,但是这个类又在其他地方被使用了。他的不同也决定另外一个对象是不是相同的,就比如我要判断两个Car对象是不是相同的。用如上方法的话,那么就判断失败啦。

怎么应对呢?一般,当你发现你判断失败了,多半是自己测试出来的,我表示我当时就是自己测试出来的,后来发现就是写入hashcode和equal方法的属性相同了,他才相同,就想到了这一点。那么就直接再重写下toString()方法,把你要比较的属性,都写在toString方法里面,这么一来。那个list类型的属性在toString之后就会变得不是内存地址啦

下面是我重写了toString()方法的代码,以及又一次的执行结果。

    @Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", isLoyal=" + isLoyal +", alive=" + alive +'}';}

这样,刚刚判断失败的地方,现在就完美的错过啦。

最后,总结一下。

要想搞明白这个,你得知道:

1,为什么要重写 hashcode和equal,以及这2个方法的作用到底 是什么。

2,正确重写hashcode和equal的姿势。上面的是可以预防空指针的哟。哦,虽然是还是这个guava的工具包里面的东西。

(这个guava包这个方法被jdk1.7借鉴了,在java.util包里面也有这个方法,可以试一下)

2,当然了,这个重点还是反射的简单应用,我上面的那个问题,只是自己试验出来的问题,算是扩展问题。

关于代码里面的Lists 就是一个guava,Google的一个工具包,感兴趣的,可以查查,也是很涨姿势的。哦,也行你已经知道啦。

Java相同类型的两个对象比较属性值,得到不同属性的名称和对应的值,附代码实例相关推荐

  1. java double类型保留两位小数的几种方法

    java double类型保留两位小数的几种方法 返回double类型的(转换比较方便) ①能四舍五入 double d = 114.145; d = (double) Math.round(d * ...

  2. Java 集合排序---常用的2种排序方式、附代码实例(大师兄亲测)

    Java API针对集合类型排序提供了两种支持: java.util.Collections.sort(java.util.List) java.util.Collections.sort(java. ...

  3. java double类型保留两位小数4种方法

    4种方法,都是四舍五入,例:import java.math.BigDecimal;import java.text.DecimalFormat;import java.text.NumberForm ...

  4. java 反射 protected_Java反射机制设置对象里的private、protected属性值

    public class ReflectUtil { private ReflectUtil() { } /** * 直接设置对象属性值,无视private/protected修饰符,不经过sette ...

  5. java搜索文件夹中文件是否存在_java中判断文件文件夹是否存在的方法(附代码)...

    1.判断文件夹是否存在,不存在则创建:(java相关视频教程推荐:java视频教程)File folder = new File("d:est1est2"); if (!folde ...

  6. 收藏了两年的嵌入式AI资源学习笔记,今天全分享给大家(附代码/资料/视频/学习规划)...

    当前乃至未来5-10年,嵌入式开发者还有哪些风口?" 画外音:风口的本质,其实就是一段时间的人才供需不平衡.说白了就是由于行业突变,敏锐的资本快速进入,导致短时间内行业大量扩张,需要大量开发 ...

  7. java怎么判断类相同_java中如何判定两个对象属于同一类 两个对象是不是类的相同实例,即用“===”是什么意思...

    导航:网站首页 > java中如何判定两个对象属于同一类 两个对象是不是类的相同实例,即用"==="是什么意思 java中如何判定两个对象属于同一类 两个对象是不是类的相同实 ...

  8. 比较两个对象 取最大值 并返回对象

    import java.math.BigDecimal; import java.util.ArrayList; import java.util.List;/*** 比较两个对象 取最大值 并返回对 ...

  9. java复制两个对象报异常_Java中复制两个不同类的对象的属性

    Apache的开源包BeanUtils用来复制两个对象的属性,要使用这个Apache的开源包,要先去官网下载commons-beanutils-1.X.jar包,http://www.apache.o ...

最新文章

  1. 编译-C++支持iOS静态库的脚本学习
  2. 演练GridView控件显示目录图片
  3. Asp.Net Core 404处理
  4. 分享12306抢票心得-终极秒杀思路篇
  5. Android loading进度条使用简单总结
  6. ASP.NET Core 5 在IIS,Nginx,Caddy下的性能测试
  7. centos mysql单向同步,虚拟机下实现Centos5.6下Mysql双向同步配置
  8. 与数据绑定相关的接口(转)
  9. 【转】【Python】Python网络编程
  10. setup factory 结束进程
  11. ICON 文件构成 及 制作工具
  12. 导航上显示某个地点已关闭什么意思_想要玩好iPhone手机,6个关闭、4个开启,要牢记...
  13. 局域网内通过ip获取主机名
  14. Java实现微信小程序校验图片是否含有违法违规内容
  15. python发送短信验证码登录_python发送短信验证码
  16. 光格科技将于12月6日上会:拟募资6亿元,姜明武为实控人
  17. 【考研政治】马哲常考的50个成语哲学原理总结 快码上!
  18. 适合婚礼上唱的歌曲 流行情歌大串烧
  19. 假设检验:p-value,FDR,q-value
  20. 全鲸董事长韩耀宁受邀出席第十九届中国科学家论坛,发表重要演讲

热门文章

  1. 【人工智能】谓词表示法与产生式知识表示实验
  2. Pygame中blit( )方法讲解(Surface对象)
  3. java中如何将十进制转换为二进制
  4. 计算机在教育中的应用的基本现状,现代教育技术应用的现状与发展
  5. Ubuntu Server 18.04 WiFi配置静态ip
  6. 电脑可以连接别的手机热点,唯独连接不上某个手机热点怎么办法?
  7. 等了十年的微信功能终于成真
  8. tcp checksum 0xffff instead of 0x0000 see rfc 1624
  9. fiddler抓包小红书app(简易版)
  10. TouchWX 入门教程(1)