小弟最近做项目遇到了这样一个问题:
按照如下的方式初始化一个对象public class Test {
public Test(){
MyObject cs = null;
if(init(cs)){
cs.getA();
}
}

private boolean init(MyObject cs){
cs  = new MyObject();
return true;
}

public static void main(String[] args){
Test test = new Test();
}
}
public class MyObject {
int a = 1; MyObject() {
a = 2;
} public int getA() {
return a;
}}编译器会在cs.getA()处提示Null pointer access: The variable cs can only be null at this location。可是按照我的理解,此处Test()将一个MyObject的引用交给init函数,init应该能够替他完成初始化 啊?
请高人指点

解决方案 »

  1.   

    init方法起不到作用,注意java在传参数的时候只有pass by value就明白了。
    结合这个例子理解一下:
    public class Test {
    public static void main(String[] args){
    StringBuilder builder = new StringBuilder("Hello");
    System.out.println(builder);
    testPassByValue(builder);
    System.out.println(builder);
    }

           //该方法起不到修改的作用
    public static void testPassByValue(StringBuilder builder){
    builder = new StringBuilder("World");
    }
    }
      

  2.   

    可是JAVA里确实应该有传递引用的啊,如下代码public class Test {
    public Test(){
    MyObject cs = new MyObject();
    change(cs);
    System.out.println(cs.getA());
    }

    private void change(MyObject cs){
    cs.setA(100);
    }

    public static void main(String[] args){
    Test test = new Test();
    }
    }
    public class MyObject {
    int a = 1; MyObject() {
    a = 2;
    } public int getA() {
    return a;
    }

    public void setA(int m){
    a = m;
    }}如上例所示,确实传了引用过去,并通过该引用修改了对象的属性啊
    求解释~~~
      

  3.   

    看你方法里面是使用的可以修改对象内容的方法(你例子里的setA方法)还是=。
      

  4.   

    Test里的cs改成成员变量就行了
      

  5.   

    Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的
      

  6.   

    看你方法里面是使用的可以修改对象内容的方法(你例子里的setA方法)还是=。
      

  7.   


    这个也算是老问题了这里严格来讲不能叫传引用,而是传引用的拷贝(pass by value就体现在了这里)
    原引用与引用拷贝都指向同一个对象,自然可以改变对象值了
      

  8.   

    Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的
    这里严格来讲不能叫传引用,而是传引用的拷贝(pass by value就体现在了这里)
    原引用与引用拷贝都指向同一个对象,自然可以改变对象值了
      

  9.   


        public Test(){
            MyObject cs = null;
            if(init(cs)){
                cs.getA();
            }
        }
        //关键问题在这里,这个是作用域问题
        private boolean init(MyObject cs){
            cs  = new MyObject();
            return true;
        }MyObject cs在方法的参数定义了一个MyObject对象的变量cs(局部变量)并且在方法里面实例化了
    但是构造方法也有一个MyObject cs,你在传递过去的时候是传递值不是引用...
    所以你过去之后返回的CS还是null,而实际上实例化的是方法参数上的cs希望回答对你有帮助
      

  10.   


    如果代码改成全局变量...public class Test {
    private static StringBuilder builder=new StringBuilder("Hello");
        public static void main(String[] args){
            System.out.println(builder);
            testPassByValue(builder);
            System.out.println(builder);
        }
        public static void testPassByValue(StringBuilder bu1){
         builder = new StringBuilder("World");
        }
    }
    就会有效果了
      

  11.   

    java都是值传递,也就是都是传递的拷贝。所谓的引用传递,不过是传递的是地址的拷贝罢了。
      

  12.   

    public class Test {
        public Test(){
            MyObject cs = null;
            if(init(cs)){
                cs.getA();
            }
        }
        
        private boolean init(MyObject cs){
            //改变cs的引用
            cs  = new MyObject();

            return true;
        }
        
        public static void main(String[] args){
            Test test = new Test();
        }
    }上面的代码是企图在init里改变构造方法cs的引用是不可行的,也就是说,在init里改变cs的引用是局部的,出了init方法cs的引用也就恢复了,但是你可以在init可能使用cs的引用,增,删,改cs的值,如下代码:
    public class Test {
        public Test(){
            MyObject cs = new MyObject();
            change(cs);
            System.out.println(cs.getA());
        }
        
        private void change(MyObject cs){
            //改变cs引用的值,没有改变cs的引用
            cs.setA(100);

        }
        
        public static void main(String[] args){
            Test test = new Test();
        }
    }
      

  13.   

    对 同意楼上的  JAVA 都是 值传递
      

  14.   

    个人理解如下:就像楼上好多人都说是传值,的确,因为就算是一个引用,那么这个引用其实可以当成C中的指针,所谓指
    针,也不过是一个数值,不过这个数值代表某个内存的地址编号值。通过这个值,我们的CPU运行时就可
    以转到对应的某个内存去读取所需要的数据。说的简单点:
    当你调用init(cs)时,传进去的值只是cs值的一份拷贝,当被方法调用完后,这份拷贝就被回
    收了,所以你的Test()中的cs仍然为空,就算你在init()中创建了一个对象,但是cs的值是null,而不是这个对象的地址值。说详细点如下:
    那么楼主的程序为什么无法改变呢?我的认识如下:
    (1)首先理解程序加载Test()方法时发生的事情:
    进入到这个函数时,系统为这个函数在栈中分配一块内存,然后,再在这块内存中为局部变量cs
    分配一块空间,因为cs只是存一个地址值,那么它被分配4Byte(因为它是一个int类型)的空间;接着后面的
    程序也会分配空间。
    (2)通过程序我们看到,你给这个变量的赋值为null,那么cs分配到的内存中的数据仍然保持为分配空间
    时系统给它赋的初值(其实这就可以解释为什么我们在C中读到数组以外的内存时,读出来的字就是那些看
    似乱码一样的字符,其实那是初始化的那些Byte转换出来的),所以这块内存不指向任何地方(这里说的”
    指向“其实是逻辑上的”指向“,而不是真正的有个连接,相信楼主能够理解),当你调用
    init(cs)时,其实此时发生的是传递了cs的一份拷贝,那么此时就把系统给的这个初始值赋给被调用的这个
    函数的这个参数,而这个参数其实就是被调用方法中的一个局部变量。
    (3)接着,你在init()方法中创建了一个MyObject的实例,并把这个实例的引用给里面局部变量cs,此时
    init()方法中的cs的确保存了一个地址值,这个地址值是MyObject()对象在堆中的起始地址(因为通过new
    方法创建对象时,对象是放入堆中的)。但是请楼主思考,在return true;之前,我们的Test()方法中的cs
    的值是多少?cs==null吧。而现在init()方法中的cs是多少?cs==某个地址值吧。
    (4)当init()方法调用完毕后,该方法所分配到的内存全部回收,也就是你没法再读这段内存中的数据了
    ,当返回后,将回到Test()方法,可是,此时我们的cs==null,也就是说cs并未指向我们在init()方法中创
    建的那个对象(当init()方法返回后,这个在堆里面的对象就已经成了垃圾了),所以,进入你的if后,你
    的cs仍为null,所以会报出那样的错误。接着,我要解释,你举的那个例子又为什么可以改变cs对象的内部状态(此时就是改变它的属性值):你调用change(cs),此时这个参数cs的值仍然是 MyObject cs = new MyObject();中的这个cs值的一份拷贝,进入你那个change(cs)方法后,你的cs调用 cs.setA(100);方法改变了cs引用指向的对象的内部状态,当你的方法调用完后,change(cs)方法分配的内存被回收,但是,我们在Test()中创建的那个MyObject对象还在堆中,而且不是垃圾,为什么?因为,当返回Test()方法后,在这个方法里面不是有个cs引用嘛,而且它现在是指向堆中的这个对象的,如果我们再用这个cs来读取它所指向的对象的信息时,我们会发现这个对象的内部状态有所改变。对比这两个例子,第一个例子中Test()的cs的值一直为null,即使init()方法创建了一个对象,它也无法指向这个对象;第二个例子中Test()的cs值一直都是被创建对象的一个引用(或地址值吧),当你在init()方法中改变这个对象时,其实就是改变了Test()方法中cs指向的那个对象。所以你再用cs去看这个对象的状态时,就看到,它指向的对象的状态改变了。
      

  15.   

    这个也算是老问题了这里严格来讲不能叫传引用,而是传引用的拷贝(pass by value就体现在了这里)
    原引用与引用拷贝都指向同一个对象,自然可以改变对象值了