Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
До версии 2.8 вам приходилось выбирать между пакетами и объектами. Проблема с пакетами заключается в том, что они не могут содержать методы или значения самостоятельно. Таким образом, вы должны поместить все это в другой объект, который может стать неловким. Обратите внимание:
object Encrypt {
private val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = encryptInt(ii.next)
}
}
Теперь вы можете import Encrypt._
и получить доступ к методу encryptInt
, а также к классу EncryptIterator
. Удобно!
Напротив,
package encrypt {
object Encrypt {
private[encrypt] val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
}
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = Encrypt.encryptInt(ii.next)
}
}
Это не огромная разница , но это заставляет пользователя импортировать как encrypt._
, так и encrypt.Encrypt._
или должен сохранять писать Encrypt.encryptInt
снова и снова. Почему бы просто не использовать объект вместо этого, как в первом шаблоне? (На самом деле нет никакого снижения производительности, поскольку вложенные классы на самом деле не являются внутренними классами Java; насколько это известно JVM, это просто обычные классы, но с причудливыми именами, которые говорят вам, что они вложенные.)
В 2.8 вы можете получить свой торт и съесть его: назовите вещь как объект пакета, и компилятор перезапишет код для вас, так что на самом деле он выглядит как второй пример под капотом (за исключением объекта Encrypt
] на самом деле называется package
внутренне), но ведет себя как первый пример с точки зрения пространства имен - значения vals и def находятся тут же, без необходимости дополнительного импорта.
Таким образом, проекты, которые были начаты до 2.8, часто используют объекты, чтобы заключить в них множество вещей, как если бы они были пакетом. После 2.8 одна из основных мотиваций была удалена. (Но, чтобы быть ясным, использование объекта по-прежнему не повредит; более того, он концептуально вводит в заблуждение, а не отрицательно влияет на производительность или что-то в этом роде.)
(PS Пожалуйста, не пытайтесь фактически зашифровать что-либо таким образом, кроме как в качестве примера или шутки!)
Это может быть и другое. Среди прочего, экземпляр внутреннего класса / свойства имеет доступ к переменным своего родителя. Внутренние классы должны быть созданы с родительским экземпляром, который является экземпляром внешнего типа.
В других случаях это, вероятно, просто способ группировки тесно связанных вещей, как в вашем object
примере. Обратите внимание, что признак LocParam
запечатан, что означает, что все подклассы должны находиться в одном и том же модуле / файле компиляции.