判等
1. string判等
Java的字符串存在字符串常量池机制;
设计目的:节省内存。
字符串常量池机制:当创建新的字符串时,会将引用放入字符串常量池,并返回该引用,称为是字符串驻留或池化;如果存在相同的内容的字符串对象的引用,则将这个引用返回。如果不想利用常量池,那么通过new String()创建新对象。
String a = "1";
String b = "1";
logger.info("\nString a = "1";\n" +
"String b = "1";\n" +
"a == b ? {}", a == b); //true
String c = new String("2");
String d = new String("2");
logger.info("\nString c = new String("2");\n" +
"String d = new String("2");" +
"c == d ? {}", c == d); //false
也可以使用intern()走常量池。
String e = new String("3").intern();
String f = new String("3").intern();
logger.info("\nString e = new String("3").intern();\n" +
"String f = new String("3").intern();\n" +
"e == f ? {}", e == f); //true
String g = new String("4");
String h = new String("4");
logger.info("\nString g = new String("4");\n" +
"String h = new String("4");\n" +
"g == h ? {}", g.equals(h)); //true
附: 因为如果放在字符串中将密码这一字符串存放于字符串池中,即使我们不再使用密码这一变量了,这个结果仍然会存放在字串池中一段时间,并且对于字符串来说,它是不会改变的。这样的们存储密码带来很大的安全隐患。
建议使用字符数组来存储返回的密码,因为字符数组是可以改变其中的元素的。当我们使用完这个密码之后、应该立刻用一个填充值来覆盖数组元素,这样就大大地降低了密码的安全隐患。
Java的在 Java中将字符串常量全部放在公共的存储池中,字符串变量指向存储池中相应的位置。
2. integer判等
在Java中判等可以通过equals或者==进行判等操作。其中equals为方式,==为操作符。
== 比较的是直接值,当比较基本类型时比较的是数值,因为基本类型的值就是数值。比较引用类型时,比较的是地址,因为引用类型的直接值是内存地址。
equals比较的是内容,因此比较引用类型时,比较的是对象的内容。
但在比较Integer、String等时,有时==也能使用。运行以下代码
Integer a = 127; //Integer.valueOf(127)
Integer b = 127; //Integer.valueOf(127)
logger.info("\nInteger a = 127;\n" +
"Integer b = 127;\n" +
"a == b ? {}",a == b); // true
Integer c = 128; //Integer.valueOf(128)
Integer d = 128; //Integer.valueOf(128)
logger.info("\nInteger c = 128;\n" +
"Integer d = 128;\n" +
"c == d ? {}", c == d); //false
查看Integer的valueOf方法,Integer在(-128,127)之间,可以通过修改参数-XX:AutoBoxCacheMax=1000修改默认缓存值。
static final int low = -128;
static final int high;
@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
另外如果不想走Integer的缓存,那么可以通过new Integer()创建新对象。比较缓存对象和新对象时,结果肯定不是相同对象
Integer e = 127; //Integer.valueOf(127)
Integer f = new Integer(127); //new instance
logger.info("\nInteger e = 127;\n" +
"Integer f = new Integer(127);\n" +
"e == f ? {}", e == f); //false
Integer g = new Integer(127); //new instance
Integer h = new Integer(127); //new instance
logger.info("\nInteger g = new Integer(127);\n" +
"Integer h = new Integer(127);\n" +
"g == h ? {}", g == h); //false
Integer i = 128; //unbox
int j = 128;
logger.info("\nInteger i = 128;\n" +
"int j = 128;\n" +
"i == j ? {}", i == j); //true
}
Integer如果和int比,Integer会拆箱后进行比较
Integer i = 128; //unbox
int j = 128;
logger.info("\nInteger i = 128;\n" +
"int j = 128;\n" +
"i == j ? {}", i == j); //true
自定义判等
若要实现自定义对象的equals可以按照以下顺序进行实现:
- 如果对象同一个返回true
- 另一对象判空,如果空对象和自身比较,那么结果false
- 判断两个对象的类型,如果类型不同,那么直接return false
- 对象类型相同的情况下再进行属性的类型强制转换,逐一判断所有字段。
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
//getClass和instanceOf方法区别
// getClass()方法比较的是运行时实例的类型
// instanceof判断是否是某个类或其派生类
PointRight that = (PointRight) o;
return x == that.x && y == that.y;
}
还需要重写hashCode()方法。因为HashSet进行查找时,会通过hashCode()方法,如果没有自定义那么会使用超类Object的默认实现。
HashSet points = new HashSet<>();
points.add(p1);
logger.info("points.contains(p2) ? {}", points.contains(p2));
//hashCode实现
@Override public int hashCode() {
return Objects.hash(x, y);
}
自定义类型,要实现Comparable,要记得equals、hashCode、 compareTo三者逻辑一致性。
3. if判等
在Java和C++中同样执行以下代码,输出结果不同
char a = 0xFF;
if (a == 0xFF) {
cout << "a == 0xFF = " << a;
}
if (a == (char)0xFF) {
cout << "a == (char)0xFF = " << a;
}
C++中仅输出第二段,强转char后判断的输出语句
Java中两段均可输出