Получение NullPointerException в расширенных методах - Java
Есть 4 класса в моем UiAutomator
тестовый проект:
1:
public class A {
protected E e;
public T t = null;
protected String m ,v;
protected long L;
public A(){
t = new T();
}
public A(E e, String m, String v, String tf)
{
this.e = e;
this.m = m;
this.v = v;
t = t.loadXML(tf);
}
2:
public class B extends A {
public B(E e, String m, String v, String tf)
{
this.e = e;
this.m = m;
this.v = v;
t = t.loadXML(tf);
}
3:
public class C {
private B b = null;
private D d = null;
private E e = null;
public C(B b, E e, D d)
{
this.b = b;
this.e = e;
this.d = d;
}
4:
public class D extends B{
public D (E e, String m, String v, String tf)
{
super(e, m, v, tf);
this.e = e;
this.m = m;
this.v = v;
t = t.loadXML(tf);
}
Я получаю NullPointerException
когда программа пытается использовать методы класса D (у класса C есть метод, который использует A, B, D).
Там нет проблем в A, B, C.
Методы в D вызывают методы из B, и я думаю, что у меня есть некоторые проблемы с расширением? Кроме того, как я могу использовать методы B в D без расширения класса? Спасибо!
2 ответа
Несколько вещей: несмотря на t
будучи общим, вы предполагаете, что T
есть метод loadXML()
; тем не менее, нет никаких ограничений на то, что T
может быть.
Кроме того, вот где ваш NullPointerException
является:
D
конструктор вызывает конструктор для B
, но конструктор для B
не вызывает конструктор по умолчанию для A
, который инициализирует T
, поскольку t
не инициализируется, вы получаете NullPointerException
,
Посмотрите Конструкторы по умолчанию и наследование в Java для получения дополнительной информации о конструкторах по умолчанию и наследовании в Java.
Я не уверен, что вы делаете, чтобы получить исключение NullPointerException, но я укажу на ошибки, которые я заметил до сих пор.
В конструкторе А вы пишете:
t = t.loadXML(tf);
в этот момент t еще не инициализирован, поэтому он равен null, и попытка вызвать метод для него вызовет исключение NullPointerException. Это не должно вызывать исключение NullPointerException в D в вашем коде, как это происходит в настоящее время (поскольку B вызывает конструктор A по умолчанию, который инициализирует t; см. Пояснения ниже). Есть 2 способа решить эту проблему (в зависимости от того, что вы хотели, чтобы произошло): 1. Вызвать другой конструктор А (который инициализирует t):
public A(E e, String m, String v, String tf)
{
this();
this.e = e;
this.m = m;
this.v = v;
t = t.loadXML(tf);
}
Передайте аргумент t типа T в конструктор и используйте его, чтобы помочь инициализировать t
public A (E e, Строка m, Строка v, Строка tf, T прошло T) { this(); this.e = e; this.m = m; this.v = v; t = passT.loadXML(tf); }
Другие заметки. Вы можете сэкономить некоторую работу в B, вызвав конструктор A:
public B(E e, String m, String v, String tf)
{
super(e,m,v,tf)
}
Это будет делать все те же назначения, которые вы в настоящее время делаете в конструкторе B, так как он вызывает конструктор A и выполняет там код. В настоящее время конструктор B будет беззвучно вызывать конструктор A по умолчанию (без аргументов). Явно это выглядит так:
public B(E e, String m, String v, String tf)
{
super();
this.e = e;
this.m = m;
this.v = v;
t = t.loadXML(tf);
}
Я предполагаю, что вы добавили оператор super в D, потому что в противном случае возникла ошибка: B не определил конструктор без аргументов, поэтому D не может вызвать его и выдаст ошибку компиляции. При этом конструктор D также может быть упрощен до:
public D (E e, String m, String v, String tf)
{
super(e, m, v, tf);
}
Я не вижу особых проблем с расширением, за исключением того, что вы забыли повторно использовать конструкторы родительских классов.
Чтобы ответить на ваш последний вопрос, вы можете использовать методы B в D, просто вызывая их, как если бы они были определены в самом D. Пример:
public class B extends A {
//I left out your constructors for readability
public String getMAndV(){
return m + v;
}
}
public class D extends B {
//I left out your constructors for readability
public String getGivenStringAndMAndV(String givenString){
return givenString + getMAndV(); //so just call it as if it's defined in the class itself
}
}