java陷阱常见面试题
总览
Java是一种极简主义的语言,具有比其他语言故意更少的功能,尽管如此,Java仍然具有产生奇怪效果的边缘情况,甚至具有令人惊讶的效果的一些常见情况也会使您轻而易举。 如果您习惯于阅读另一种语言,则可以轻松地以错误的方式阅读Java,而不会感到困惑。
变量仅是引用或原语
没错,变量不是对象。 这意味着当您看到以下内容时,s 不是一个对象 ,它不是一个String,它是对String的引用
String s = "Hello";
这回答了许多混乱的领域,例如;
- 问:如果String是不可变的,该如何更改。 例如 s + =“!”;
- 答:您不能使用普通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
对于Integer,对象池从-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(),甚至可以通过
Object.toString()做一些令人惊讶的事,而不是有用的事
toString()的默认行为是为类和hashCode()打印内部名称。
如前所述,hashCode不是存储位置,即使它以十六进制打印也是如此。 而且,类名,特别是对于数组,令人困惑。 例如; String []打印为[Ljava.lang.String; [表示它是一个数组,L表示它是一个“语言”创建的类,而不是像BTW这样具有代码B的字节之类的基元。 表示课程结束。 例如说你有一个像
String[] words = { "Hello", "World" };
System.out.println(words);
打印类似
[Ljava.lang.String;@45ee12a7
不幸的是,您必须知道该类是一个对象数组,例如,如果您只有对象字,那么您将遇到问题,并且必须知道调用Arrays.toString(words)。 这种中断封装的方式非常糟糕,并且在StackOverflow上经常造成混乱。
我曾问过Oracle公司的其他开发人员这件事,我的印象是现在很难修复它。
翻译自: https://www.javacodegeeks.com/2014/03/common-gotchas-in-java.html
java陷阱常见面试题