以前看过一些资料说:
java 方法传递参数时,
如果参数类型是基本类型,java采用值传递,方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值;
如果参数类型为对象类型,java采用引用传递,也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。但今天本人遇到了一个问题,很迷惑,请各位解释下,问题:public class Book { private String name = null; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}public class ParseHtml {


public void bookxiugai(Book book){
book = new Book();
}

public static void main(String[] args) {
ParseHtml p = new ParseHtml();
Book book = null;
p.bookxiugai(book);//方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为非null,
System.out.println(book);

}
}问题:p.bookxiugai(book);//方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为非null,可是打印却为null,为什么?
请高手不吝赐教!!!!

解决方案 »

  1.   

    public void bookxiugai(Book book){
    book = new Book();
    }你给new出来了
      

  2.   

    public void bookxiugai(Book book){
    book = new Book();
    }
    不是传递的问题,是作用域的问题。book的定义,你在一个方法内定义。
    代码的写的有问题,变量的作用域。
      

  3.   


    不是new不new的问题。
    你在这个方法体内,输出week,它不是空的。
    他传得这个对象的引用,充当了方法体内的变量。
    作用域的问题。
      

  4.   

    Because you forget to initialise the values to book;the book class need a constructor,which will store the values;i.e.
    // this is the contructor of Book class
    public Book(String bookName)
    {
      this.name = bookName
    }
    // main class
    public static void main (String [] args){   Book book = new Book("Harry Porter");
     }//  understand?
      

  5.   

    因为你的private String name = null;
    你再看看Object的toString方法就知道了
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    如果不是按引用传递,应该报空指针的。
      

  6.   

    new 关键字,是指新创建一个对象。1. 声明对象
    book = null;
    这个时候,book这个引用对应的是一个空地址2. 在方法里,你使用new Book();
    这个时候,你复制参数book引用地址发生了变化,而你原来的那个book地址是没有发生变化的,依然是null。
      

  7.   

    对不起,理解错误。java类传递是引用的拷贝,既不是引用本身,更不是对象。所以这句话的理解就知道你这个原因了,book在方法调用前是指向一个为null的地址,而book在方法中用new了,那形参又重新分配地址了。其实这里两个book指向的不是同一个地址了。所以为null可以理解了。总结起来,实际上引用传递是要在对象为非null的情况下。像下面:
    class Book { private String name = null; public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    }



    }public class ChanSu { public void bookxiugai(Book book) {
    book.setName("affff");
    } public static void main(String[] args) {
    ChanSu p = new ChanSu();
    Book book = new Book();
    p.bookxiugai(book);// 方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为非null,
    System.out.println(book.getName());
    }
    }结果打印出:affff就知道这个形参的改变影响了实参的。
      

  8.   

    我觉得还有问题,
    如果按照“实际上引用传递是要在对象为非null的情况下。”
    public static void main(String[] args) {
    ParseHtml p = new ParseHtml();
    Book book = new Book();
    p.bookxiugai(book);//方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为非null,
    System.out.println(book);
    }
    那么p.bookxiugai(book),这句话就有问题了,地址给他了不是空的,而且我又新new了一个对象给他,
    对象的引用理所应当会被改变。
    那么在main方法体内的,book是指向同一对象吗?
    答案则不是。
    当形参传入后,在方法体内当做变量使用的时候,它的性质就改变了,它就变成了,这个方法体内的一个
    引用。
      

  9.   

    而且重要的是 name这个变量是全局变量啊。
      

  10.   

    java声明一个对象后(未实例化)就在栈内存中开辟了一个类似指针的空间(引用)
    也就是说,
    当形参传入后,作为变量使用的时候,它就重新的开辟了一个空间(引用),
    这跟 空 和 非空 没有关系。
    主要的是,在内存中,不是同一空间。 引用也会分配内存的。
      

  11.   

    我确定是这个原因。我现在有个问题,一个方法体内的形参(这个形参是空引用),作为变量来使用的时候,比如:
    public static void main(String args[]) {
      ParseHtml p = new ParseHtml(); 
      Book book = null;
      p.param(book);
    }
    public void param(Book book) {
      book = null;
    }
    在空引用的情况下,如何确认这两个空引用,不是在内存的同一空间中。 我知道是因为作用域的问题,可是我就像明白,怎么证明。
      

  12.   

    我的认为是:
    变量在堆栈上,出了作用域就被销毁了。
    main 方法体内的book的作用域只在main 方法中。当方法
    public void param(Book book) {
     book = new Book();//当作为一个变量存放在方法体内的话,book的引用已经被销毁了。而book作为了一个变量,则有了自己的内存空间。则是一个新的引用。
    }其实说了半天,都是作用域的问题。
    建议好好看一下java的变量内存分布。
      

  13.   


    地址传递的前提是计算机语言支持指针java不支持指针,谈不上地址传递引用传递就是引用传递,引用是别名,也就类似于硬链接
      

  14.   

    我遇到过类似的问题,
    把你的代码改如下
    更容易理解public class Book {
    private String name = null;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    }public class ParseHtml {
      private Book book;
    public void bookxiugai(Book book){
       this.book = book;
       this.book = null;
    }
    public static void main(String[] args) {
    ParseHtml p = new ParseHtml();
    Book book = new Book();
    p.bookxiugai(book);
    /*方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为null*/
    System.out.println(book);}
    }
      

  15.   

    也就是说可以改对象的属性,但不能改引用地址(new一个或赋值为null是不会改变对象的)
      

  16.   

    public void bookxiugai(Book book){
    book = new Book();
    }
      你把申明 出来的book做参数传进去之后 是栈中的book 只想null  然后在new  book 在指向new的对象
      方法结束后 book 系统回收 . new 的对象没有引用  也等着GC回收. So 最后book 就是null  了
      

  17.   

    我觉得楼主可能有两方面理解有问题。
    第一方面是变量作用域方面的,上面已经有人讲解过了。
    另一方面是对引用变量和对象的理解。
    Book book = null;
    你只是声明了一个Book类型的引用变量,并且没有用它指向任何对象。
    你传进去了以后,显然它还是什么都没有指。
    然后就是作用域的问题了。你在bookxiugai里面new出来的那个对象,在这个函数结束后就出作用域了,然后就被GC回收了。
    另外楼主的英语要加强啊修改可以用modify,哪怕change也比直接用拼音好呀~~
    学软件你很有可能要参考很多英文资料。英文不好的话会影响你的进一步发展的。
    建议你以后写代码的时候打开个有道词典之类的东西,单词不会的话就花个半分钟去查一下。
    如果你看了《代码大全》你会知道用拼音去命名是绝对禁止的。
      

  18.   

    public void bookxiugai(Book book)与main()里面的book是两个不同的对象了
      

  19.   

    是作用域的问题,这样改一下,将Book book = null;拿到方法外面,当做全局变量public class Book {    private String name = null;    public String getName() {
            return name;
        }    public void setName(String name) {
            this.name = name;
        }
    }public class ParseHtml {
        public Book book = null;    public void bookxiugai(Book _book){
            _book = new Book();
        }    public static void main(String[] args) {
            ParseHtml p = new ParseHtml();
            p.bookxiugai(book);//方法参数是对象,按说应该是引用传递,方法的修改应该影响实际参数book,打印结果应该为非null,
             System.out.println(book);
        }
    }
      

  20.   

    正因为是传递的是引用,你传进去的null,在这个函数是中不能改变这个引用的,传出来的任然是null
    public void bookxiugai(Book book){
    book = new Book();
    }
      

  21.   

    首先纠正一点,java中其实都是值传递基本数据类型情况如下:
    例如,int a = 0; 这种情况下 假如a的内存地址是 0x00001 但这个地址存放的值是 0
    假如将这个值传入一个方法
    void test(int a){}
    test(a);
    在这个方法内部 接受到的 a的内存地址可能是 0x00002 但是它的值保存的是 0x00001这个地址保存的值,也就是0
    这个时候你去修改 a = 1 实际上修改的是 0x00002 这个地址对应的值,所以方法外面的值是不会改变的对象引用传递:
    例如 Object obj = new Object(); 假如obj的内存地址是 0x00001 但这个内存中存放的值是另外一个内存地址,也就是obj对象对应在堆中的地址 假如为 0x00003
    加入将obj传入一个方法
    void test(Object obj){}
    test(obj);
    这个时候,在方法内部接收到的 obj的内存地址可能是 0x00004(绝对不会是0x00001,0x00003) 但传入的值是0x00003
    然后在方法内不些 obj = new Object(); 这个时候创建的对象在堆中地址假设是 0x00008
    这条语句也就会设置 0x00004 的值为0x00008 ,实际上修改不了 0x00001也就是你传入进来的参数说的不是太清楚,不知道你是否能理解
      

  22.   

    感谢大家的积极回复,很抱歉时隔很久才对这个问题做个总结,我在提出这个问题后自己也在思考其原因。以下是我的思考:
    首先:以下说法本人认为是正确的。
    java 方法传递参数时,
    如果参数类型是基本类型,java采用值传递,方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值;
    如果参数类型为对象类型,java采用引用传递,也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。其次:
    如果参数类型为对象类型,java采用引用传递,也称为传地址......影响实际参数的值;其意思说的是:影响的是对象的内容,和对象的引用改变是两码事;Book book = null; 和 book = new Book();的区别改变的是引用的值改变了,book 变量开始指向 null(暂且这样理解)后来指向 Book 对象的堆内存。所以:
    Book book = null; 和 book = new Book();  和 Book 对象内容的改变是两码事;是我刚开始理解错了。希望大家能够理解。本人结贴!