Буквально самый простой способ исправить NullReferenceExeption имеет два пути. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (rigidbody), эта переменная начнет пустую, когда вы начнете игру. Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.
В качестве примера я буду использовать переменную RigidBody. Мы можем добавить данные действительно легко на самом деле несколькими способами:
rb = GetComponent<Rigidbody>();
. Эта строка кода работает лучше всего под ваши функции Start()
или Awake()
. rb = AddComponent<RigidBody>();
Дальнейшие заметки: если вы хотите, чтобы единство добавлялось компонент для вашего объекта, и вы, возможно, забыли добавить его, вы можете ввести [RequireComponent(typeof(RigidBody))]
над объявлением класса (пробел ниже всех ваших приложений). Наслаждайтесь и получайте удовольствие от игр!
Попробуйте создать свой публичный конструктор
private Singleton() {
if( Singleton.singleton != null ) {
throw new InstantiationError( "Creating of this object is not allowed." );
}
}
Perfect Singleton Class, который может избежать создания экземпляра во время сериализации, клонирования и отражения.
import java.io.Serializable;
public class Singleton implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private static volatile Singleton instance;
private Singleton() {
if (instance != null) {
throw new InstantiationError("Error creating class");
}
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
return new Singleton();
}
}
}
return null;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
Object readResolve() {
return Singleton.getInstance();
}
}
Определите синглтон следующим образом:
public enum Singleton {
INSTANCE
}
Here Reflection not work
package com.singleton.nonbreakable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
class FullySingletonClass {
public static void main(String[] args) {
SingletonImpl object1 = SingletonImpl.getInstance();
System.out.println("Object1:" + object1);
try {
FileOutputStream fos = new FileOutputStream("abc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
FileInputStream fis = new FileInputStream("abc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingletonImpl object2 = (SingletonImpl) ois.readObject();
System.out.println("Object2" + object2);
} catch (Exception e) {
// TODO: handle exception
}
try {
Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will not destroy the singleton pattern
constructor.setAccessible(true);
SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
System.out.println("Object3:" + Object3);
break;
}
} catch (Exception ew) {
}
}
}
package com.singleton.nonbreakable;
import java.io.Serializable;
class SingletonImpl implements Cloneable, Serializable {
public static SingletonImpl singleInstance = null;
private static class SingletonHolder {
public static SingletonImpl getInstance() {
if (null == singleInstance) {
singleInstance = new SingletonImpl();
}
return singleInstance;
}
}
private SingletonImpl() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return singleInstance;
};
public Object readResolve() {
System.out.println("Executing readResolve again");
return SingletonImpl.getInstance(); // FIXME
}
public static SingletonImpl getInstance() {
return SingletonHolder.getInstance();
}
}
Output :
Object1:com.singleton.nonbreakable.SingletonImpl@15db9742
Executing readResolve again
Object2com.singleton.nonbreakable.SingletonImpl@15db9742
private Singleton() {
if (Singleton.singleton != null) {
throw new RuntimeException("Can't instantiate singleton twice");
}
}
Еще одна вещь, которую вы должны посмотреть - это метод readResolve(..)
, потому что ваш класс реализует Serialiable
. Там вы должны вернуть существующий экземпляр.
Но самый простой способ использования синглонов - перечислить - вы не беспокоитесь об этом.
Как насчет проверки в конструкторе:
private Singleton() {
if (singleton != null) {
throw new IllegalStateException("Singleton already constructed");
}
}
Конечно, это не может действительно остановить его - если кто-то возится с рефлексией для доступа к закрытым членам, они может быть в состоянии задать поле для нулевого значения. Вы должны спросить себя, что именно вы пытаетесь предотвратить, и как это стоит.
(EDIT: Как отметил Божо, окончательные поля могут быть недоступны даже при отражении. удивился, если есть некоторые способы сделать это через JNI и т. д., хотя ... если вы дадите людям достаточно доступа, они смогут делать почти все ...)
В качестве альтернативы синглтону вы можете взглянуть на шаблон моностата . Затем создание экземпляра вашего класса больше не является проблемой, и вам не нужно беспокоиться о любом перечисленных вами сценариях.
В шаблоне monostate все поля в вашем классе static
. Это означает, что все экземпляры класса имеют одно и то же состояние, как с одним синглоном. Более того, этот факт прозрачен для вызывающих; им не нужно знать о специальных методах, таких как getInstance
, они просто создают экземпляры и работают с ними.
Но, как и при использовании singleton, это форма скрытого глобального состояния; который очень плохой .
Просто отметим, что с Java 8 и в соответствии с моей проверкой невозможно создать экземпляр Singleton через Reflections, если у него есть частный конструктор.
Вы получите это исключение:
Exception in thread "main" java.lang.IllegalAccessException: Class com.s.Main can not access a member of class com.s.SingletonInstance with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at com.s.Main.main(Main.java:6)
Чтобы преодолеть проблему, вызванную рефлексией, используются перечисления, поскольку java обеспечивает внутренне, что значение перечисления создается только один раз. Поскольку java Enums доступны по всему миру, их можно использовать для одиночных игр. Его единственный недостаток заключается в том, что он не является гибким, и это не допускает ленивой инициализации.
public enum Singleton {
INSTANCE
}
public class ReflectionTest
{
public static void main(String[] args)
{
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println("instance1 hashcode- "
+ instance1.hashCode());
System.out.println("instance2 hashcode- "
+ instance2.hashCode());
}
}
JVM обрабатывает создание и вызов конструкторов enum внутри. Поскольку перечисления не дают определение своего конструктора программе, мы не можем получить к ним доступ также с помощью Reflection.
I Thing Ниже код будет работать.
class Test {
static private Test t = null;
static {
t = new Test();
}
private Test(){}
public static Test getT() {
return t;
}
public String helloMethod() {
return "Singleton Design Pattern";
}
}
public class MethodMain {
public static void main(String[] args) {
Test t = Test.getT();
System.out.println(t.helloMethod());
}
}
output: Singleton Design Pattern