本文主要是介绍2021春软件构造-lab2小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 前言
- Equality
- == 与 equals
- @Override作用
- @Override equals的一般模板
- 可变对象的相等关系
- 有些时候会有迷惑的现象:
- 原理
- 结论
- AutoBoxing 与 Equality
- 小结
前言
在lab2对图的vertices方法测试时(代码段如下),涉及到两个集合是否相等的问题,故采用了Set的equals方法,发现集合的相等是分别调用每个元素的equals方法进行逐对比较,现对java中的equals方法进行总结。
@Testpublic void testvertices(){Graph<String> g = emptyInstance();g.add("a");g.add("b");Set<String> vertices = new HashSet<>();vertices.add("a");vertices.add("b");assertEquals(vertices,g.vertices());Graph<String> g2 = emptyInstance();assertEquals(new HashSet<String>(),g2.vertices());}
Equality
== 与 equals
equals方法比较的是对象的相等性,继承于object类的equals方法,默认就是java中的“==“运算符,该运算符比较的是两个对象的地址相等性,即是否为相同的对象,这是有本质区别的。
@Override作用
在重写equals方法中体现的特别明显,重写要求参数列表的类型必须是一致的,而参数列表不一致则变成了重载,这样子类中存在两个equals方法,不一定能按需调用。
@Override equals的一般模板
以lab3中interval为例
注:这里的getclass会返回子类型,即运行时类型,满足多态性。
public class Interval<L> {private long start;private long end;private final L label;// AF:时间段开始时刻:start,终止时刻:end,时间段对应标签label。由这三元组映射到一个唯一的时间段。
// RI:start>=0,end>=0,label非空
// safety from RE:private访问权限控制,label引用不可变,label自身是不可变类型。@Overridepublic boolean equals(Object obj) {if (this == obj) //若同一个对象,定相等return true;if (obj == null)return false;if (getClass() != obj.getClass()) //不是同一个类型return false;Interval other = (Interval) obj; //同类型比较if (end != other.end) //按需比较return false;if (label == null) {if (other.label != null)return false;} else if (!label.equals(other.label))return false;if (start != other.start)return false;return true;}
}
可变对象的相等关系
往往采用严格的观察等价性。如:List之间的相等关系表现为两个list包含相同顺序的元素,equals才返回true。
有些时候会有迷惑的现象:
public static void main(String[] args) {// TODO Auto-generated method stubList<String> list = new ArrayList<>();list.add("a");Set<List<String>> s = new HashSet<>();s.add(list);System.out.println(s.contains(list)); //truelist.add("b");System.out.println(s.contains(list)); //false}
一个已经add的链表却不在集合内部了,看起来内外两个list不相等了。
原理
contains方法机制:这里的Set用HashSet实现,自然采用散列值进行存储。第一次链表只有元素a,与第二次的散列值一定不同,HashSet的内部实现并不会根据可变对象的变化去调整所在bucket的位置。因此,第二次再查找时自然也就找不到了。
结论
可变对象被用作集合中的元素时,集合的行为会表现出不确定性,应谨慎使用。
AutoBoxing 与 Equality
java是OOP语言,每个基本数据类型也有相应的封装类,下以Integer为例:
public static void main(String[] args) {// TODO Auto-generated method stubInteger x = new Integer(3);Integer y = new Integer(3);System.out.println(x==y); //false 不是同一个对象System.out.println(x.equals(y)); //true override过System.out.println((int)x == (int) y); //true 转换基本数据类型后,指向同一个地址Map<String,Integer> a = new HashMap<>(), b = new HashMap<>();a.put("a", 130);b.put("a", 130);System.out.println(a.get("a") == b.get("a")); //falsea.put("b", 1);b.put("b", 1);System.out.println(a.get("b") == b.get("b")); //trueInteger m = 2;Integer n = 2;System.out.println(m == n); //true}
在上述代码中,后半段创建了两个字典,put过程中发生了自动打包,所以取出的是Integer对象,进而两个不同对象输出false。为什么当打包1时,又变成相同对象了呢?java实现机制中,-128-127的对象是唯一的,打包时放入的都是对其的引用,因此是相同的对象。这在接下来m与n的自动打包中也得到了证实,2是被打包成Integer-2,m与n都是指向这一对象的引用。
小结
equals是一个非常重要的方法,因此也放在object类中。多数情况下,我们应该override它,来实现满足我们需求的相等性判断。然而相等性也存在着一些较为复杂晦涩的情况,应当具体分析,谨慎使用。
这篇关于2021春软件构造-lab2小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!