Java 是一种极简主义的语言,它故意比其他语言少一些功能,但它的边缘情况会产生奇怪的效果,甚至一些常见的情况会产生令人惊讶的效果,从而使粗心大意的人绊倒。如果您习惯于阅读另一种语言,则很容易以错误的方式阅读 Java,从而造成混乱
变量只是引用或原语
String s = "Hello";
这回答了许多令人困惑的领域,例如;
问:如果 String 是不可变的,我该如何更改它。例如。s += "!";
A:你不能在普通的Java中,你只能改变一个对String的引用。
== 比较引用,而不是它们的内容。
更令人困惑的是,有时使用 == 是可行的。如果您有两个相同的不可变值,JVM 也可以尝试使引用相同。例如
String s1 = "Hi", s2 = "Hi";
Integer a = 12, b = 12;
在这两种情况下,都使用了对象池,因此引用最终是相同的。s1 == s2 和 a == b 都是真的,因为 JVM 已经对同一个对象进行了引用。但是,稍微改变一下代码,这样 JVM 就不会汇集对象,并且 == 返回 false,这可能是出乎意料的。在这种情况下,您需要使用 equals。
String s3 = new String(s1);
Integer c = -222, d = -222;
s1 == s2 // is true
s1 == s3 // is false
s1.equals(s3) // is true
a == b // is true
c == d // is false (different objects were created)
c.equals(d) // is true
对于整数,对象池从 -128 开始到至少 127(可能更高)
Java 按值传递引用
所有变量都按值传递,甚至引用。这意味着当您有一个引用对象的变量时,会复制此引用,但不会复制对象。例如
public static void addAWord(StringBuilder sb) {
sb.append(" word");
sb = null;
}
StringBuilder sb = new StringBuilder("first ");
addWord(sb);
addWord(sb);
System.out.println(sb); // prints "first word word"
用的对象可以更改,但对复制的引用的更改对调用者没有影响。
在大多数 JVM 中,Object.hashCode() 与内存位置没有任何关系
hashCode() 必须保持不变。如果没有这个事实,HashSet 或 ConcurrentHashMap 之类的哈希集合将无法工作。但是,该对象可以位于内存中的任何位置,并且可以在您的程序不知道发生这种情况的情况下更改位置。使用 hashCode 的位置是行不通的(除非你有一个不移动对象的 JVM)
对于 OpenJDK 和 HotSpot JVM,hashCode() 按需生成并存储在对象的标头中。使用 Unsafe 您可以查看 hashCode() 是否已设置,甚至可以通过 over 更改它
Object.toString() 做了一些令人惊讶而不是有用的事情
toString() 的默认行为是打印类的内部名称和 hashCode()。
如前所述,hashCode 不是内存位置,即使它以十六进制打印。类名,尤其是数组的类名也令人困惑。例如; String[] 打印为 [Ljava.lang.String; [ 表示它是一个数组, L 表示它是一个“语言”创建的类,而不是像字节一样的原始类型,顺便说一句,它的代码是 B。 ; 表示类的结束。例如说你有一个像
String[] words = { "Hello", "World" };
System.out.println(words);
打印类似的东西
[Ljava.lang.String;@45ee12a7
不幸的是,您必须知道该类是一个对象数组,例如,如果您有 justObject 单词,那么您就有问题,您必须知道调用 Arrays.toString(words)。这种破坏封装的方式相当糟糕,也是 StackOverflow 上常见的混淆
最后,有兴趣想要学习相关资料的朋友点赞三连+关注后私信后回复《555》即可免费获取