首页 > 试题广场 >

指出下列程序运行的结果:

[单选题]
指出下列程序运行的结果:
public class Example{
    String str=new String("tarena");
    char[]ch={'a','b','c'};
    public static void main(String args[]){
        Example ex=new Example();
        ex.change(ex.str,ex.ch);
        System.out.print(ex.str+" and ");
        System.out.print(ex.ch);
    }
    public void change(String str,char ch[]){
   //引用类型变量,传递的是地址,属于引用传递。
        str="test ok";
        ch[0]='g';
    }
}

  • tarena and abc
  • tarena and gbc
  • test ok and abc
  • test ok and gbc
string和char数组都是引用类型,引用类型是传地址的,会影响原变量的值,但是string是特殊引用类型,为什么呢?因为string类型的值是不可变的,为了考虑一些内存,安全等综合原因,把它设置成不可变的; 不可变是怎么实现的?Java在内存中专门为string开辟了一个字符串常量池,用来锁定数据不被篡改,所以题目中函数中的str变量和原来的str已经不是一个东西了,它是一个局部引用,指向一个testok的字符串,随着函数结束,它也就什么都没了,但是char数组是会改变原值的
发表于 2017-05-14 00:51:50 回复(6)
其实前面有几个答案说的已经很清楚了,足够我们理解这一道题。有一些东西可能还不是很清楚,导致这种题容易发生混乱。记住几点就可以了:1.为什么string字符串的值是不可变的?当我们new一个字符串,给它赋值之后,那么当前对象的值就固定了,永远不会改变。比如String str=new String("test"),那么str的值就是test,这是因为在String源码当中是用char数组来按顺序存储字符串中的每一个字符的,并且这个char数组是用final修饰的,这意味着一旦我们给字符串赋值之后,这个对象的值就永远不会改变。2.可是当我们在一个类当中的某个方法里面,给这个对象str赋值了一个新的字符串,它这时候的值是多少呢?比如这时str="good",str的值就是good,(你可以在这个方法里面写输出语句,输出这个引用,就知道怎么回事了)可不是说引用的值不可以改变么?这里改变的不是引用的值,而是引用str指向的常量不一样了而已,而这个引用的生命周期和当前方法的一样的,也就是方法结束,引用被杀死,也结束了,那么它刚才指向good的这个引用,就结束了,所以在这个方法结束之后,再输出引用str的值,自然就是引用str之前指向的值了,也就是test。
发表于 2017-08-15 20:53:52 回复(17)
以下几点如有误请大家指正: 1.java中只有值传递。 2.方法exchange接收的参数是引用的副本。即都是地址的复制值。 3.方法中str副本指向了一个新的字符串,但是并没有改变原本的str指向的字符串。 4.方法中ch虽然也是一个副本,但方法利用它修改了它所指向的字符数组中的第一个元素。 5.方法结束后,所有副本弹出结束,但是我们的成员变量str和ch还存在,它们依然是之前的地址。所以str的内容不变,ch第一个元素被改变。
发表于 2017-05-06 10:02:20 回复(12)
我的思路、不知道对不对,欢迎指正
由于string和char数组都是引用类型,调用方法时传递的是引用,如下图所示

按道理修改str和ch时会影响原来的值,但是由于string是不可变的,对string的修改实际上是new了一个新对象(这也是string和stringbuffer的区别,stringbuffer的底层是char数组,所以可以直接修改),而对char数组的修改则会影响原值。所以如下图。


发表于 2018-06-05 19:02:35 回复(3)
我查了一下,看了看别人的技术博客  浅谈一下理解 :Java中没有引用传递 只有值传递 或者说副本传递    运行change()方法时,str和ch这两个实参 引用的地址被复制一份副本作为change的形参传入,这时候原本和副本指向同一个地址
1.str=“test OK”;因为字符串是对象 这相当于在常量池创建一个新的字符串常量 把这个常量的地址给了形参  所以实参和形参指向不同地址  对形参的改变不影响实参 因为方法结束 栈帧回收  这个形参死亡;
2 ch[0]='g';  明显实参和形参还是指向同一个地址  把元素  字符g赋值给地址相同的ch数组   形参改变  实参也改变;
有的兄弟说是String的不可变  我也没想明白到底有影响么  但是我把String改为可变的StringBuilder  结果并没有变化
编辑于 2019-05-30 14:32:35 回复(10)
选B
这个题考察了两个点:
    1. 值传递和引用传递(数组是对象,属于引用传递)
    2. 不可变类(如String和包装类)

本身String属于引用类型,应该走引用传递,但是由于字符串常量池的原因,导致其不可变,所以形参和实参一开始就没指向一个内存地址。所以形参的变化并不会影响到实际参数。
发表于 2018-07-05 09:26:55 回复(4)
(1)基本数据类型传值,对形参的修改不会影响实参; (2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象; (3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。
发表于 2018-01-04 15:15:34 回复(1)
其实我也不知道这题确切思路 因为我也写错了
发表于 2017-04-30 14:40:28 回复(0)
java的参数传递规则:
1.八种基本数据结构是直接传值,在函数内部改变传入的值,跳出函数域后该值复原,也即不能通过函数改变传入的参数值;
2.对象数据传地址(包括string和数组),在函数内部改变传入的地址,跳出函数域后该地址复原,既不能通过函数改变这个地址,但是可以改变地址指向的对象;
(实际上这两种情况逻辑上是统一的,因为地址也是一串数值,同样满足“不能通过函数改变传入的参数值”的要求
本题,传入str时候,str 是对象,所以传的是地址(是指向String("tarena")的地址值),在函数内部str="test ok" 实际上是把str指向了一个新的地址,根据规则2,跳出函数域后该地址值会复原回指向String("tarena")的地址值。
传数组ch[]的时候,ch[]是数组对象,传的也是地址。但是在函数内部,通过这个地址改变了ch[]对象第一个元素的值,java只能保证指向的地址还是ch[]的地址,但ch[]对象保存的是什么就不能保证不变了。
发表于 2019-01-24 11:22:58 回复(0)

我讲讲我的理解:

Str是存放着地址,它指向堆中的String变量,该变量又指向StringPool的“tarena”,由于String是final static的,因此堆中String变量指向的StringPool中“tarena”是一定无法改变的,但str的指向是可以改变的(理解成C++的指针),但调用change方法是新增了一个Str,它是copy了原str的地址,因此它最终指向是“tarena”,由于赋值语句改变了新str的指向,因此新str指向StringPool中的“test good”,但别忘了,新Str是旧str的copy,因此并未改变旧str的最终指向。
但为什么char数组可改变???
因为字符对象的指向的值被新的字符对象由a改成了g,所以改变了char数组的值。

all in all:为什么String不变,char【】变了?String还是那个原配,但char【】换老婆了。所以char数组是花心的,我们要唾弃它,多用String

发表于 2020-04-08 23:39:42 回复(1)
说一下题外话吧,Java没有引用传递,但这个说法却在很多Java书上频频出现~哎,当我得知这个事实时,我是难受的,感觉世界观崩塌了,就像1+1不等于2那样,感觉白学了。关于这方面的资料有很多人讨论的,上网搜一下就有~
发表于 2019-03-23 15:35:18 回复(0)
我是这样理解的:其实不管是String 还是char 他两的指向内存的地址都是没变的,只是char修改了内存中的值,如果有方法可以修改str内存的值,str也会变吧
发表于 2022-01-30 10:19:09 回复(1)
如有不对请指正
    java中引用传值传的其实是它的一个副本并不是本体,change方法中的两个参数其实是副本,str="test ok"是让副本str指向了一个新的地址来改变值,原值并未变"test ok"相当于新对象),而ch副本是将引用指向的对象本身进行了修改,原值也是指向这个对象,所以原值就发生了改变。
发表于 2021-09-02 16:56:41 回复(0)
我个人的理解:
              String str=new String("tarena"); 
语句执行的时候,首先会检查字符串常量池有没有“tarena”,如果没有,就在字符串常量池创建一个“tarena”,然后根据字符串常量池的“tarena”,在堆中创建一个“tarena”对象,这个str指向堆中的“tarena”对象;如果字符串常量池有“tarena”,就直接在堆中创建一个“tarena”对象。
总的来说,就是在堆中有一个str成员变量,指向堆中的一个地址A,地址A中的值是“tarena”。且由于字符串底层是final类型的数组实现,那么这个地址A的值“tarena”是不变的。str的值始终是“tarena”,除非将str指向其他地址。

          
 char[]ch={'a','b','c'};


同样,上面语句在堆中创建一个成员变量ch,并创建一个地址B,B中的值是数组的元素:‘a’、‘b’、‘c’,该成员变量ch指向地址B

              
 public void change(String str,char ch[]){
              //引用类型变量,传递的是地址,属于引用传递。
                str="test ok";
                ch[0]='g';
               }


上面语句执行的时候,在栈中创建2个局部变量str、ch,局部变量str被赋予A地址的副本,指向A地址。而局部变量ch被赋予地址B的副本,指向地址B。
当 
str="test ok";  

 执行的时候,我们知道地址A的内容是不会变的,那么即使局部变量str指向地址A,它的值变化也不会引起地址A的值变化,而是在栈中开辟一个地址C,地址C的值是“test ok”,局部变量str指向地址C,而成员变量str仍然指向地址A,且值是“tarena”。
当 
ch[0]='g';

  指向的时候,由于地址B的值可变,那么局部变量ch的值的变化,会导致地址B的值的变化,地址B第一个值就从‘a’变为‘g’,因此成员变量ch指向地址B,它的值也变化,为
['g','b','c']


发表于 2020-04-08 15:22:07 回复(1)
字符串的实例存在字符串常量池中,是不可变的。str的指向只是在change方法中发生了改变,而在主方法中,str的指向是没有发生改变的
发表于 2020-03-23 11:20:18 回复(0)
达内已经那么牛了吗
发表于 2020-02-23 21:34:50 回复(1)
Java为string开辟一个字符串常量池,String源码里面有一个final的char数组,是不可变的,在change函数里面str指向改变了,但是是局部引用,跳出函数生命周期也就结束了,str的指向还是以前那个
发表于 2019-03-02 15:10:01 回复(1)
形参,实参
发表于 2018-09-14 08:20:18 回复(1)
我来回答吧,String其实相当于Character同等于char基本类型的包装类(如果有疑惑,可以去找下源码,源码中翻译过来就是这样的),包装类作为参数传递其实相当于基本类型的传递,基本类型的传递就相当于传递原值的副本,对副本进行改变,原值不变。
char类型的数组相当于对象,对除包装类对象以外的其他对象作为参数传递传递的是地址,有两种情况:
(1)如果在调用的方法中没有创建新的地址,即引用变量原地址没有变的情况下,我们相当于直接在对象上进行操作,一改全改。
(2)如果在调用的方法中创建了新的地址,即产生了两个地址,我们是在新地址上进行操作,原地址上的内容不变。跳出方法后,新地址会被释放掉,就相当于没有出现过一样,我们输出的仍然是原地址中的内容!
编辑于 2018-08-31 10:20:33 回复(0)
达内毕业的,表示做错了
发表于 2017-05-27 13:32:45 回复(7)