A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

阿磊

  • 黑马币:18

  • 帖子:218

  • 精华:0

© 阿磊   /  2014-8-5 00:06  /  3283 人查看  /  57 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

LFW 中级黑马 2014-8-5 10:51:13
21#
fantacyleo 发表于 2014-8-5 10:15
还是我打的那个比方:假定有个数组int[] a = {1,2,3}  你(a)的考卷({1,2,3})做好了交给老师批改(swap) ...

能改变对象内存里边的东西,却不能改变引用所指的内存地址?例如a = {1,2,3},调用swap可以让a ={2,1,3},其实是操作了a引用所指的内存地址(如0x1122)中的元素,但是a引用所指的地址值只能是0x1122?
回复 使用道具 举报
LFW 发表于 2014-8-5 10:51
能改变对象内存里边的东西,却不能改变引用所指的内存地址?例如a = {1,2,3},调用swap可以让a ={2,1,3}, ...

是的。还有疑问吗?

点评

不敢说全部,但随口就能说出来名字的编程语言都只有值传递,没有引用传递一说。引入引用传递的概念只会让初学者更迷惑  发表于 2014-8-5 12:06
那样说只是为了他能够理解,因为他好像并不明白值传递和引用传递……  发表于 2014-8-5 11:55
回复 使用道具 举报
楼上们的都是详解
回复 使用道具 举报
如果你两个String在main里new出来的呢
回复 使用道具 举报
用数组就可以传了,String比较特殊,操作参数不能改变变量本体的值,因为你把参数传过去的时候,方法里的参数会重新划分一块内存出来储存传来的值,你改变的也只是新划分的内存中储存的值,而不是原来变量指向的内存中的值。下面是用数组传参交换数据。
  1. class  Test
  2. {
  3.         public static void main(String[] args)
  4.        {
  5.                     String [] str={"abcde","abc"};      
  6.                swap(str);
  7.                 System.out.println("str1="+str[0]+"::"+"str2="+str[1]);//输出结果    str1=abcde::str2=abc
  8.                 if(str[0].length()>str[1].length()){
  9.                         String temp = str[0];
  10.                         str[0] = str[1];
  11.                         str[1] =  temp;
  12.                 }        
  13.                System.out.println("str1="+str[0]+"::"+"str2="+str[1]);
  14.         
  15.        }
  16.         public static void swap(String [] str){
  17.                
  18.                  if(str[0].length()>str[1].length()){
  19.                  String temp = str[0];
  20.                  str[0] = str[1];
  21.                  str[1] =  temp;
  22.          }      
  23.         }

  24. }
复制代码

点评

这跟String不可变无关。本质是参数值传递  发表于 2014-8-5 11:46
回复 使用道具 举报
LFW 中级黑马 2014-8-5 11:35:36
26#
fantacyleo 发表于 2014-8-5 10:59
是的。还有疑问吗?

我把if定义在getMaxSubString函数时,能调换的原因是?
回复 使用道具 举报
LFW 发表于 2014-8-5 11:35
我把if定义在getMaxSubString函数时,能调换的原因是?

原因是你只互换了getMaxSubString函数中的两个string,就像你在swap中一样能看到效果,但对getMaxSubString无效。同样,你在getMaxSubString中的互换,对getMaxSubString的调用者无效。
回复 使用道具 举报
看到前面的回答,总结一下:
首先,Java中引用数据类型的变量被传进到方法中,并且被做了改动之后结果会被保存下来。而基本数据类型(数字、字符、布尔值)是 按值传递的,String是引用类型。
其次,关于string类型是不可改变的问题:  string类型确实是是不可改变的,我感觉这也不是String不能改变的原因,也不是申明方式不同的原因,因为在main函数和调用swap函数之后,在swap函数里面打印的时候也是换了的,代码和运行结果如下:
public class  Demo {
    public static void main(String[] args) {
        String str1 = new String("abcde");
        String str2 = new String("abc");
        swap(str1,str2);
        System.out.println("--调用swap之后---str1="+str1+"::"+"str2="+str2);
        //输出结果    str1=abcde::str2=abc
        if(str1.length()>str2.length()) {
            String temp = str1;
            str1 = str2;
            str2 =  temp;
        }
        System.out.println("main函数中---str1="+str1+"::"+"str2="+str2);
        //输出结果  str1=abc::str2=abcde

    }
    public static void swap(String str1,String str2) {
        System.out.println("wap函数中,还没变化---str1="+str1+"::"+"str2="+str2);
        if(str1.length()>str2.length()) {
            String temp = str1;
            str1 = str2;
            str2 =  temp;
        }
        System.out.println("wap函数中变化之后---str1="+str1+"::"+"str2="+str2);
    }

}
结果:
wap函数中,还没变化---str1=abcde::str2=abc
wap函数中变化之后---str1=abc::str2=abcde
--调用swap之后---str1=abcde::str2=abc
main函数中---str1=abc::str2=abcde

所以,真正的原因到底是什么呢?

点评

原来是这样呀  发表于 2014-8-5 17:17
String虽然是引用类型,也是一个特殊的值类型,传参的时候用的是值传递,不是引用传递。  发表于 2014-8-5 12:24
回复 使用道具 举报
本帖最后由 怀念黑海岸 于 2014-8-5 12:07 编辑

可以简而概之:当我们往一个方法里面传递参数时,如果这个参数是基本数据类型包括String,那么实际上传递进去的只是这个基本数据类型的一个复制品而已,因此在这个方法内对这个参数的操作其实都只是对这个复制品的操作,而这个参数如果是引用类型,即一个对象的话,那么传递进去的是这个对象的引用,那么在这个方法内对这个参数的操作都是操作这个对象本身。例如下面的例子:
class TestSwap{
                public static void main(String []args){
                        int a=1,b=3;
                        Person p1=new Person("Li");                                
                        Person p2=new Person("Du");
                        System.out.println("Before swap-->"+a+","+b);
                        swap(a,b);
                        System.out.println("After swap-->"+a+","+b);
                        System.out.println("---------------------------");
                        String str1="abc";
                        String str2="def";
                        System.out.println("Before swap-->"+str1+","+str2);
                        swap(str1,str2);
                        System.out.println("After swap-->"+str1+","+str2);
                        System.out.println("---------------------------");
                        System.out.println("Before swap-->"+p1.name+","+p2.name);
                        swap(p1,p2);
                        System.out.println("After swap-->"+p1.name+","+p2.name);
        }
        public static void swap(String str1,String str2){  
                System.out.println("Before swap-->"+str1+","+str2);
                String temp =str1;
                str1=str2;
                str2=temp;
                System.out.println("After swap-->"+str1+","+str2);
        }
        public static void swap(int a,int b){  //对于基本数据类型,传入a,b实际上是将a,b复制一份后对复制的a,b进行操作。
                System.out.println("Before swap-->"+a+","+b);
                int temp =a;
                a=b;
                b=temp;
                System.out.println("After swap-->"+a+","+b);
        }
        public static void swap(Person p1,Person p2){//对于引用数据类型,传入的引用地址,实际上的操作就是对对象本身的操作
                String temp=p1.name;
                p1.name=p2.name;
                p2.name=temp;
        }
}
class Person{
        String name;
        Person(String name){
                        this.name =name;
                }
        }
运行结果:
Before swap-->1,3
Before swap-->1,3
After swap-->3,1
After swap-->1,3
--------------------------
Before swap-->abc,def
Before swap-->abc,def
After swap-->def,abc
After swap-->abc,def
--------------------------
Before swap-->Li,Du
After swap-->Du,Li
回复 使用道具 举报
fantacyleo 发表于 2014-8-5 10:59
是的。还有疑问吗?

C#里面就可以用ref将值传递变为引用传递……
回复 使用道具 举报
fxwb2005 发表于 2014-8-5 12:18
C#里面就可以用ref将值传递变为引用传递……

我知道,ref就跟C中的&和pascal中的var一样,其实都是值传递,只不过传递的是变量的地址值而已。引用传递这个概念当然是可以定义的,我只是认为一个值传递概念就足以涵盖加与不加ref、&、var的情况,而且可以将Java和其他语言的参数传递进行统一解释。多一个概念对初学者来说可能会适得其反
回复 使用道具 举报
这个问题你如果学过c的话就特别好理解。在子方法里所有变化的值只限于子方法里面。在主函数里还是原来的值。
在c中,如果你想在子方法里把主函数的值变化的话,就只能加指针,是传参数的时候,传的引用对象。
回复 使用道具 举报
6楼正解。。。
回复 使用道具 举报
各种分析各种回复各种比喻
回复 使用道具 举报
使用swap函数,传入的值只是原来值的一个拷贝,在函数中并没有改变原来的值,如改变原来的值使用传地址值方式,
回复 使用道具 举报
怀念黑海岸 发表于 2014-8-5 12:05
可以简而概之:当我们往一个方法里面传递参数时,如果这个参数是基本数据类型包括String,那么实际上传递进 ...

这个例子的话有点了解了,但是还不全懂  呵呵,就是对于数据类型和String都是不可能改变地址值的,但是对于一个对象的话就是可以的
回复 使用道具 举报 1 0
本帖最后由 怀念黑海岸 于 2014-8-5 17:27 编辑
阿磊 发表于 2014-8-5 17:17
这个例子的话有点了解了,但是还不全懂  呵呵,就是对于数据类型和String都是不可能改变地址值的,但是对 ...

你不管字符串数据是引用类型还是基本类型,原因主要在于他们都是存储于常量池中的,而对象都是存在于堆内存中的,用这个方法来区分对待这个问题,你就能轻松的理解了。
你只需记住,调用函数时往函数里面传参数,其实都传的是具体的数值,不同在于对于基本数据类型和字符串,是直接将传入的数据先复制一份,然后再将复制的这份传进去,你怎么修改穿进去的数据都是修改复制版本,他本身是不会改变的。而传递的是引用数据类型的话就是传递这个对象的地址,那么你方法里的任何对对象操作都会导致你会直接修改传进去的这个对象。
回复 使用道具 举报
本帖最后由 Darkhorse′Xa 于 2014-8-5 17:35 编辑

了解一下值传递和引用传递就懂了.
但是Java里头只有值传递
回复 使用道具 举报
fantacyleo 发表于 2014-8-5 11:49
原因是你只互换了getMaxSubString函数中的两个string,就像你在swap中一样能看到效果,但对getMaxSubStri ...

貌似有点懂了,但是还是希望你给个图哈  晚上等你消息,让我更加明白:lol
回复 使用道具 举报
swap方法中的str1和str2跟主方法中的两个字符串名字相同,但是它们不是同一个字符串。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马