Java相同类型的两个对象比较属性值,得到不同属性的名称和对应的值,附代码实例
假设现在有需求如下:比较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相同类型的两个对象比较属性值,得到不同属性的名称和对应的值,附代码实例相关推荐
- java double类型保留两位小数的几种方法
java double类型保留两位小数的几种方法 返回double类型的(转换比较方便) ①能四舍五入 double d = 114.145; d = (double) Math.round(d * ...
- Java 集合排序---常用的2种排序方式、附代码实例(大师兄亲测)
Java API针对集合类型排序提供了两种支持: java.util.Collections.sort(java.util.List) java.util.Collections.sort(java. ...
- java double类型保留两位小数4种方法
4种方法,都是四舍五入,例:import java.math.BigDecimal;import java.text.DecimalFormat;import java.text.NumberForm ...
- java 反射 protected_Java反射机制设置对象里的private、protected属性值
public class ReflectUtil { private ReflectUtil() { } /** * 直接设置对象属性值,无视private/protected修饰符,不经过sette ...
- java搜索文件夹中文件是否存在_java中判断文件文件夹是否存在的方法(附代码)...
1.判断文件夹是否存在,不存在则创建:(java相关视频教程推荐:java视频教程)File folder = new File("d:est1est2"); if (!folde ...
- 收藏了两年的嵌入式AI资源学习笔记,今天全分享给大家(附代码/资料/视频/学习规划)...
当前乃至未来5-10年,嵌入式开发者还有哪些风口?" 画外音:风口的本质,其实就是一段时间的人才供需不平衡.说白了就是由于行业突变,敏锐的资本快速进入,导致短时间内行业大量扩张,需要大量开发 ...
- java怎么判断类相同_java中如何判定两个对象属于同一类 两个对象是不是类的相同实例,即用“===”是什么意思...
导航:网站首页 > java中如何判定两个对象属于同一类 两个对象是不是类的相同实例,即用"==="是什么意思 java中如何判定两个对象属于同一类 两个对象是不是类的相同实 ...
- 比较两个对象 取最大值 并返回对象
import java.math.BigDecimal; import java.util.ArrayList; import java.util.List;/*** 比较两个对象 取最大值 并返回对 ...
- java复制两个对象报异常_Java中复制两个不同类的对象的属性
Apache的开源包BeanUtils用来复制两个对象的属性,要使用这个Apache的开源包,要先去官网下载commons-beanutils-1.X.jar包,http://www.apache.o ...
最新文章
- 编译-C++支持iOS静态库的脚本学习
- 演练GridView控件显示目录图片
- Asp.Net Core 404处理
- 分享12306抢票心得-终极秒杀思路篇
- Android loading进度条使用简单总结
- ASP.NET Core 5 在IIS,Nginx,Caddy下的性能测试
- centos mysql单向同步,虚拟机下实现Centos5.6下Mysql双向同步配置
- 与数据绑定相关的接口(转)
- 【转】【Python】Python网络编程
- setup factory 结束进程
- ICON 文件构成 及 制作工具
- 导航上显示某个地点已关闭什么意思_想要玩好iPhone手机,6个关闭、4个开启,要牢记...
- 局域网内通过ip获取主机名
- Java实现微信小程序校验图片是否含有违法违规内容
- python发送短信验证码登录_python发送短信验证码
- 光格科技将于12月6日上会:拟募资6亿元,姜明武为实控人
- 【考研政治】马哲常考的50个成语哲学原理总结 快码上!
- 适合婚礼上唱的歌曲 流行情歌大串烧
- 假设检验:p-value,FDR,q-value
- 全鲸董事长韩耀宁受邀出席第十九届中国科学家论坛,发表重要演讲