Некоторые люди спрашивают: как синглтон может вернуть нулевой указатель?
Я отвечаю на этот вопрос. (Я не могу ответить в комментарии, потому что мне нужно отправить код.)
Может возвращать значение null между двумя событиями: (1) класс загружен и (2) объект этого класса создан. Вот пример:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Давайте запустим код:
$ javac A.java
$ java A
x:X@a63599 y:Y@9036e
x:null y:null
Вторая строка показывает, что Y.xinstance и X.yinstance равны null ; они являются нулевыми, потому что переменные X.xinstance ans Y.yinstance были прочитаны, когда они были нулевыми.
Можно ли это исправить? Да,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
и этот код не показывает аномалию:
$ javac A.java
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e
НО это не вариант для объекта Android Application
: программист не контролирует время его создания.
Еще раз: разница между первым и вторым примерами заключается в том, что второй пример создает экземпляр, если статический указатель равен нулю. Но программист не может создать объект приложения Android, пока система не решит это сделать.
UPDATE
Еще один удивительный пример, когда инициализированные статические поля бывают null
.
Main.java
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
И вы получите:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Обратите внимание, что вы не можете переместить объявление статической переменной на одну строку выше, код не будет компилироваться.