项目场景:
做MIT软件构造实验:Problem Set 2: Poetic Walks,实现Graph的implement
问题描述:
问题是这样的,我定义了如下的一个类Edge,
class Edge<L> {
// TODO fields
private final L sou;
private final L tar;
private final Integer wei;
// Abstraction function:
// sou is the source, tar is the target, wei is the weight on the directed edge from source to target
// Representation invariant:
// true
// Safety from rep exposure:
// the fields are all private final
// TODO constructor
public Edge(L source,L target,Integer weight) {
sou=source;
tar=target;
wei=weight;
checkRep();
}
// TODO checkRep
public void checkRep() {
assert wei>0;
assert sou!=null;
assert tar!=null;
}
// TODO methods
//防御式拷贝
public L getSource() {
checkRep();
return sou;
}
public L getTarget() {
checkRep();
return tar;
}
public Integer getWeight() {
checkRep();
return wei;
}
// TODO toString()
public String toString() {
checkRep();
return this.sou+"->"+this.tar+" weight:"+this.wei+"\n";
}
}
现在我定义了一个List,里面的元素都是Edge,但是我想要比较两个Edge的source是否是一样的,发现如果直接用==,得到的结果永远是false,只有用equals方法才可以正确比较。
//first version always false
if(edges.get(i).getSource()==source)
//second version wright answer
if(edges.get(i).getSource().equals(source) )
而且最玄学的是,我在test里面跑的时候没有问题,但是将Graph作接口引入到了poem代码里面的时候这个问题才发现。
现在想想,这是因为我Junit测试的时候,输入的L都是常字符串,就是"a","b"这种直接赋值的,这种好像是= =里面可以正常判断的。部分测试代码如下。
@Test
public void testSourcesAndTarget() {
Graph<String> g=emptyInstance();
String a="a";
String b="b";
String c="c";
g.add(a);
g.add(b);
g.add(c);
g.set(a, b, 1);
g.set(a, c, 1);
g.set(c, b, 1);
Map<String, Integer> res=g.targets(a);
assertEquals(true,1==res.get(b));
assertEquals(true,1==res.get(c));
Map<String, Integer> res1=g.sources(b);
assertEquals(true,1==res1.get(a));
assertEquals(true,1==res1.get(c));
}
原因分析:
后来我在想,为什么会发生这种事情呢?
经过调查,我发现,由于我在poem里面应用的是String代替L。
String可以用= =和equals()方法比较,==是比较两个字符串的首地址,equals()方法是比较两个字符串的内容。所以对于两个不同的Edge里面的String类型的source,当然用= =方法比较不出来的了。所以,以后比较String相等,保险起见,还是都用equals()吧
简单的测试用例(来源)
String s1,s2,s3 = "abc", s4 ="abc" ;
s1 = new String("abc");
s2 = new String("abc");
System.out.println("s1==s2:"+(s1==s2));//false
System.out.println("s1==s3:"+(s1==s3));//false
System.out.println("s3==s4:"+(s3==s4));//true
System.out.println("s1.equals(s2):"+(s1.equals(s2)));//true
System.out.println("s1.equals(s3):"+(s1.equals(s3)));//true
System.out.println("s3.equals(s4):"+(s3.equals(s4)));//true
拓展
注意:对于s3和s4来说,有一点不一样要引起注意,由于s3和s4是两个字符,串常量所生成的变量,其中所存放的内存地址是相等的,所以s3==s4是true(即使没有s3=s4这样一个赋值语句)
另外对于int等基本类型比较,只能用==,没有equals()方法
对于基本类型的包装类型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的(equals()被重写了)。
对于object函数,equals()也是比较首地址,可以在object函数里面重写equals方法,来达到比较的目的