使用java输出参数时'空指针访问'

时间:2011-02-23 18:47:34

标签: java eclipse parameters

我在java工作,想要使用输出参数之类的东西。这是一个例子:

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

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

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

我正在使用Eclipse,我遇到的问题是日食显示警告:
 Null pointer access. The variable objA can only be null at this location当我到达职位(1)时

由于java中没有out参数的概念,我有点难过

=============================================== ===================
编辑:我已经有几个人提到改变方法返回我的对象​​而不是布尔。但是,如果我需要一种方法来改变几个对象呢? 例如:

 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 
}  

我该怎么做?我不想为每种返回对象的风格制作一个自定义类吗?

感谢,
斯蒂芬妮

7 个答案:

答案 0 :(得分:5)

  

因为没有out的概念   java中的参数......

引用obj是引用objA的副本,因此将新对象分配给obj不会更改objA。这意味着java不支持使用obj作为out参数。

因此,java方法只能返回一个值。以下是可能的解决方案/解决方法。

解决方案1:异常而不是布尔值(仅当布尔表示错误时)

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

解决方案2:出现错误时返回null。

ClassA objA = null;  

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

解决方案3:使用Pair返回多个值

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();
}

答案 1 :(得分:3)

Java是按值传递的。在myMethod中为obj指定值时,可以为调用代码的指针的副本分配新值。调用代码的指针继续指向其初始对象,该对象为null。这就是Eclipse警告你的原因:你试图使用objA,无论你在myMethod中做什么都是null。

答案 2 :(得分:3)

你不能真正做你在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中是不可能的。每个人都说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()方法中的分配对valNullval0引用的内容没有影响。

如果您确实需要单个方法的多个“输出”参数,则必须将它们包装在其他对象中,或者重新考虑您的设计。也许您可以创建引用成员变量而不是本地变量,并让您的方法直接修改它们:

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 :(得分:1)

obj内为myMethod分配值不会更改objA的值。在Java中,引用按值传递。如果您希望myMethod初始化ClassA的实例,则应将该逻辑移动到ClassA的构造函数或工厂方法中。

要发出错误信号,您将抛出异常而不是返回布尔值。

答案 4 :(得分:1)

我很确定Java不支持这种行为;即你不能这样做。返回你的对象或null而不是bool。

答案 5 :(得分:1)

基本上,你不能用Java做到这一点。当您调用方法时,您正在传递对该对象的引用,您没有传递方法可以写入的内存位置。你可以做的是传入一个对象并允许该函数操纵该对象。然后当函数返回时,您可以访问被操作的字段但函数。

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

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

答案 6 :(得分:1)

实际上,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 Language Specification的这一部分中阅读这个领域中Java的语义,但是从代码片段中可能已经很明显地发生了什么。