Статьи

Общие ошибки в Java

обзор

Java — это минималистский язык с преднамеренно меньшим количеством функций, чем у других языков, тем не менее, он имеет крайние случаи, которые приводят к странным эффектам, и даже некоторые распространенные случаи с удивительными эффектами, чтобы сбить с толку неосторожных. Если вы привыкли читать на другом языке, вы можете легко читать Java неправильно, оставляя замешательство.

Переменные являются только ссылками или примитивами

Это верно, переменные не являются объектами. Это означает, что когда вы видите следующее, s не является объектом , это не строка, это ссылка на строку

1
String s = "Hello";

Это отвечает многим областям путаницы, таким как;

  • Q: Если String является неизменным, как я могу изменить его. например, s + = «!»;
  • A: Вы не можете в обычной Java, вы можете только изменить ссылку на строку.

== сравнивает ссылки, а не их содержание.

Чтобы добавить к путанице, использование == иногда работает. Если у вас есть два одинаковых неизменных значения, JVM может попытаться сделать ссылки одинаковыми. например

1
2
String s1 = "Hi", s2 = "Hi";
Integer a = 12, b = 12;

В обоих этих случаях используется пул объектов, поэтому ссылки в конечном итоге остаются одинаковыми. s1 == s2 и a == b имеют значение true, поскольку JVM сделала ссылки на один и тот же объект. Однако немного измените код, чтобы JVM не объединяла объекты, а == возвращает false, возможно, неожиданно. В этом случае вам нужно использовать равные.

1
2
String s3 = new String(s1);
   Integer c = -222, d = -222;
1
2
3
4
5
6
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 передает ссылки по значению

Все переменные передаются по значению, даже ссылки. Это означает, что когда у вас есть переменная, которая является ссылкой на объект, эта ссылка копируется, но не объект. например

1
2
3
4
public static void addAWord(StringBuilder sb) {
     sb.append(" word");
     sb = null;
}
1
2
3
4
StringBuilder sb = new StringBuilder("first ");
addWord(sb);
addWord(sb);
System.out.println(sb); // prints "first word word"

Указанный объект может быть изменен, но изменения в скопированной ссылке не влияют на вызывающего.

В большинстве JVM Object.hashCode () не имеет никакого отношения к расположению памяти

HashCode () должен оставаться постоянным. Без этого факта коллекции хешей, такие как HashSet или ConcurrentHashMap, не работали бы. Тем не менее, объект может находиться в любом месте памяти и может изменить свое местоположение, если ваша программа не будет знать, что это произошло. Использование местоположения для хэш-кода не будет работать (если у вас нет JVM, где объекты не перемещаются)

Для OpenJDK и JSM HotSpot hashCode () генерируется по требованию и сохраняется в заголовке объекта. Используя Unsafe, вы можете увидеть, был ли установлен hashCode (), и даже изменить его более чем

Object.toString () делает что-то удивительное, а не полезное

Поведение по умолчанию для toString () заключается в печати внутреннего имени для класса и hashCode ().

Как уже упоминалось, hashCode не является ячейкой памяти, даже если он напечатан в шестнадцатеричном формате. Также имя класса, особенно для массивов, сбивает с толку. Например; строка [] печатается как [Ljava.lang.String; [Означает, что это массив, буква L означает, что это класс, созданный на «языке», а не байт типа примитива, в котором BTW имеет код B. и; означает конец класса. Например, скажем, у вас есть массив как

1
2
String[] words = { "Hello", "World" };
System.out.println(words);

напечатать что-то вроде

1
[Ljava.lang.String;@45ee12a7

К сожалению, вы должны знать, что класс является массивом объектов, например, если у вас есть только слова Object, у вас есть проблема, и вы должны знать, чтобы вместо этого вызывать Arrays.toString (words). Это плохо нарушает инкапсуляцию и является источником путаницы в StackOverflow.

Я спрашивал об этом у разных разработчиков в Oracle, и у меня сложилось впечатление, что сейчас это слишком сложно исправить.

Справка: общие сведения о Java от нашего партнера по JCG Питера Лоури из блога Vanilla Java .