«Нулевой указатель доступа» при использовании выходных параметров Java - PullRequest
0 голосов
/ 23 февраля 2011

Я работаю в Java и хочу использовать что-то вроде выходных параметров. Вот пример:

ClassA objA = null;  
if(myMethod(objA))  
{  
   // position (1)
   //use objA somehow  
} 

======================

public bool myMethod(ClassA obj)   
{   
     obj = .....   
}  

Я использую Eclipse, и у меня проблема в том, что Eclipse показывает предупреждение:
Null pointer access. The variable objA can only be null at this location когда я достигну позиции (1)

Поскольку в Java нет понятия out параметров, я немного запутался

=============================================== ===================
РЕДАКТИРОВАТЬ: я получил несколько человек, чтобы поменять метод для возврата моего объекта вместо bool. Но что, если мне нужен метод для изменения нескольких объектов? например:

 ClassA objA = null;  
  ClassB objB = null;
    if(myMethod(objA, objB))  
    {  
       // position (1)
       //use objA and objB somehow  
    } 

======================

public bool myMethod(ClassA obj, ClassB obj2)   
{   
     //do stuff 
}  

Как я могу это сделать? Я не хочу делать пользовательский класс для всех возможных возвращаемых объектов?

спасибо,
Stephanie

Ответы [ 7 ]

5 голосов
/ 23 февраля 2011

Так как нет понятия о параметры в java ...

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

Из-за этого метод java может возвращать только одно значение. Ниже приведены возможные решения / обходные пути.

Решение 1: исключение вместо логического (только если логическое указывает на ошибку)

ClassA objA = null;  
try{
   objA = myMethod();
   //DO something with objA
}catch(MyException ex){
}

Решение 2: вернуть ноль в случае ошибки.

ClassA objA = null;  

   objA = myMethod();
  if(objA != null)
{ //DO something with objA
}

Решение 3: использовать пару для возврата нескольких значений

MyPair mp = myMethod();
if(mp.first){
}

MyPair myMethod(){
   MyPair ret = new MyPair();
   mp.first = ...;//boolean
   mp.second = new ClassA();
   return ret;
}

class MyPair {
   boolean first;
   ClassA second;
}

Soultion 4: использовать одноэлементные массивы - безобразно использовать только в крайних случаях

ClassA[] objA = new ClassA[1];
if(myMethod(objA))
{
}

boolean myMethod(ClassA[] obj){
   obj[0] = new ClassA();
}
3 голосов
/ 23 февраля 2011

На самом деле вы не можете делать то, что пытаетесь сделать в Java, поскольку, как вы говорите, Java не поддерживает выходные параметры.

Параметры метода являются локальными переменными, поэтому при назначении имникакого эффекта вне рамок метода.Другими словами, это:

public void foo(Object obj) {
    obj = new Object();
}

фактически эквивалентно (с точки зрения кода, вызывающего foo (Object)), как это:

public void foo() {
    Object obj = new Object();
}

Бессмысленно, так как созданообъект будет отброшен, как только foo() вернется.

Вероятно, вы хотите изменить свой метод так, чтобы он возвращал объект, который создает ваш метод:

public ClassA myMethod() {
   ClassA obj = ....
   ...
   return obj;
}

Затем в вашем вызывающем коде:

ClassA objA = myMethod();
if (objA != null) {
    ...
}

В качестве альтернативы, вы можете создать экземпляр ClassA вне вашего метода и передать это значение и заставить метод каким-либо образом изменить его:

public boolean myMethod(ClassA obj) {
    obj.setValue(...);
    return true;
}

...

ClassA objA = new ClassA();
if (myMethod(objA) {
   Object val = objA.getValue();
   ...
}

Не зная большеЧто касается вашей конкретной проблемы, трудно сказать, какой дизайн лучше.

ОБНОВЛЕНИЕ:

Добавленный вами многопараметрический пример, к сожалению, совершенно невозможен.Все говорят, что java - это передача по ссылке, но на самом деле это больше похоже на передачу по ссылке.Метод может модифицировать объекты , переданные ему, но он не может изменить то, на что ссылаются переменные в вызывающей области.Если вы пришли из фона C ++, ссылки на объекты в java больше похожи на указатели (без арифметики указателей), чем на ссылки на C ++.

Чтобы сделать это более конкретным, рассмотрим следующий класс:

public class ParameterPassing {
    public static void setParams(Integer value1, Integer value2) {
        System.out.println("value1 before: " + value1);
        System.out.println("value2 before: " + value2);
        value1 = new Integer(1);
        value2 = new Integer(2);
        System.out.println("value1 after: " + value1);
        System.out.println("value2 after: " + value2);
    }

    public static void main(String[] args) {
        Integer valNull = null;
        Integer val0 = new Integer(0);
        System.out.println("valNull before: " + valNull);
        System.out.println("val0 before: " + val0);

        setParams(valNull, val0);

        System.out.println("valNull after: " + valNull);
        System.out.println("val0 after: " + val0);
    }
}

Когда вы запустите это, вы получите следующий вывод:

valNull before: null
val0 before: 0
value1 before: null
value2 before: 0
value1 after: 1
value2 after: 2
valNull after: null
val0 after: 0

Как видите, назначения внутри метода setParams() не влияют на то, что valNull и val0 см.

Если вам действительно нужно несколько «выходных» параметров для одного метода, вам придется обернуть их в какой-то другой объект или переосмыслить свой дизайн.Возможно, вы могли бы сделать ссылки на переменные-члены, а не на локальные, и сделать так, чтобы ваш метод изменил их напрямую:

public class MyClass {
    private ClassA objA;
    private ClassB objB;

    ...

    private boolean initObjects() {
        objA = ...;
        objB = ...;
        return true;
    }

    public void otherMethod() {
        ...
        if(initObjects() {
            // Use objA, objB
        }
    }
}
3 голосов
/ 23 февраля 2011

Java передается по значению. Когда вы присваиваете значение obj в myMethod, вы назначаете новое значение для копии указателя вызывающего кода. Указатель вызывающего кода продолжает указывать на его начальный объект, который является нулевым. Вот почему Eclipse предупреждает вас: вы пытаетесь использовать objA, который является нулевым, что бы вы ни делали в myMethod.

1 голос
/ 23 февраля 2011

На самом деле Eclipse прав в этом случае.Рассмотрим следующий код:

public class NullThing {
  private static class ClassA {
    public int x;
  }

  public static boolean myMethod(ClassA obj) {
    obj = new ClassA();
    obj.x = 5;
    return obj.x == 5;
  }

  public static void main(String[] args) {
    ClassA objA = null;
    if (myMethod(objA)) {
      System.out.println(objA.x);
    }
  }

}

Если вы скомпилируете это с javac, чтобы избежать предупреждения Eclipse, вы получите:

adrian:~/ $ javac NullThing.java                                                                                                                      [14:05:47]
adrian:~/ $ java NullThing                                                                                                                            [14:06:43]
Exception in thread "main" java.lang.NullPointerException
    at NullThing.main(NullThing.java:15)

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

1 голос
/ 23 февраля 2011

В принципе, вы не можете сделать это с Java. Когда вы вызываете метод, вы передаете ссылку на объект, вы не передаете область памяти, в которую может записать метод. Что вы можете сделать, это передать объект и позволить функции манипулировать объектом. Затем, когда функция возвращается, вы можете получить доступ к полям, которые были обработаны, но функция.

ClassA objA = new ClassA();  
if(myMethod(objA))  
{  
   objA.getValue();
}

public boolean myMethod(ClassA obj)   
{   
     obj.assignValue(1);
     return true;
}  
1 голос
/ 23 февраля 2011

Я почти уверен, что поведение не поддерживается в Java; то есть ты не можешь этого сделать. Верните ваш объект или null вместо bool.

1 голос
/ 23 февраля 2011

Присвоение значения obj в пределах myMethod не изменит значение objA. В Java ссылки передаются по значению. Если вы хотите, чтобы myMethod инициализировал экземпляр ClassA, вы должны переместить эту логику либо в конструктор ClassA, либо в метод фабрики.

Чтобы сообщить об ошибке, вы должны вызвать исключение, а не возвращать логическое значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...