Java的传值与传引用

面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 

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

在Java语言中基本类型和String都是标准的值传递,而对象(包括数组)也是值传递,不过他们传递的值是地址的副本,无论形参如何变化,这个地址是不会改变的,改变的是这个地址所存储的内容。


在Java中,当基本类型(包括String)作为参数传入方法时,无论该参数在方法内怎样被改变,外部的变量原型总是不变的。

这就叫做“值传递”,即方法操作的是参数变量(也就是原型变量的一个值的拷贝)改变的也只是原型变量的一个拷贝而已,而非变量本身。所以变量原型并不会随之改变。


对于一个对象作为形式参数时,传递的其实是这个实参的地址值,所以形参内容改变,实参的内容也就改变了,因为他们指向同一个地址,有个特别要注意的地方,如果形参中有两个对象参数A,B,在方法中把B=A,实际是把A的地址赋值给了B,这时候形参B如果发生内容改变,实际是改变的A地址的内容,与实参B的地址内容就没有关系了:可以参考下面的例子:

    static void aMethod(StringBuffer sf1, StringBuffer sf2) {
        sf1.append(sf2);
        sf2 = sf1;
        sf2.append("s");
    }


    public static void main(String[] args) {
        StringBuffer sf1 = new StringBuffer("A");
        StringBuffer sf2 = new StringBuffer("B");
        Test.aMethod(sf1, sf2);
        System.out.println(sf1 + ":" + sf2);
    }


输出结果为  :ABs:B

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

String s1="accp" ;
String s2="accp"
Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为s1的对String类对象引用变量:String s1;
(2)在栈中查找有没有存放值为"accp"的地址,如果没有,则开辟一个存放字面值为"accp"的地址,接着创建一个新的String类的对象o,并将o 的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"accp"的地址,则查找对象o,并返回o的地址。所以当栈中存在你想创建的变量的值的时候,其实是引用已经存在栈中的地址,不是新建的。

所以s1==s2true


String str = "hello" 如果之前有String对象是hello的值的话那str直接就指向之前的那个对象了,不再重新new一个对象了
String str = new String("hello");无论以前有没有都重新new一个新的

==========================new String()创建几个对象关问问题=================================

  1. String str=new String("aaa");  

这行代码究竟创建了几个String对象呢?答案是2个,而不是3个。由于new String("aaa")相当于"aaa"与一个就是创建出来的放在堆时原实例对象,而另一个就是放在常量池中的 "aaa" 对象,当然这里的str本身只是一个引用,放在栈里,用来指向堆中创建出来的对象。

常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

Java代码   
  1. String str="aaa"  

只创建1个对象。这里涉及到字符串常量池,在JVM中有一个字符串池,它用来保存很多可以被共享的String对象,这样如果我们在使用同样字面字符串时,它就使用字符串池中同字面的字符串。当然我们可以使用String对象的intern()方法来访问String对象在字符串池中所对应的常量对象。

上面这行代码被执行的时候,JVM先到字符串池中查找,看是否已经存在值为"aaa"的对象,如果存在,则不再创建新的对象,直接返回已存在对象的引用;如果不存在,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。

 

Java代码   
  1. String str1="aaa"  
  2. String str2="aaa"   

也只创建1个对象。能过上面的解释这个就更清楚了,在执行第二行代码时,aaa字符串对象在池中已存在,所以直接返回池中已存在的那个字符串对象。

Java代码   
  1. String str="aaa"+"bbb"  

还是只创建1个对象。由于常量字符串是在编译的时候就也被确定的,又因"aaa"和"bbb"都是常量,因此变量str的值在编译时就可以确定。这行代码编译后的与String str="aaabbb";是一样的,这与我们平时好像不太一样啊?一般使用“+”连接两个字符串都会产生另一个新的字符对象。下面我们看一下例子就明白了:

Java代码   
  1. String str1 "aaa" 
  2. String str2 "bbb" 
  3. String str3 "aaabbb" 
  4.   
  5. String str4 "aaa" "bbb";//不会产生新的字符串对象  
  6. System.out.println(str3 == str4);//true  
  7.   
  8. str4 str1 "bbb";//会产生新的字符串对象  
  9. System.out.println(str3 == str4);//false  
  10.   
  11. str4 str1 str2;//会产生新的字符串对象  
  12. System.out.println(str3 == str4);//false  

从上面例子我们就可以得出:使用“+”连接的两个字符串本身就是字面常量字符串时,如果池中存在这样连接后的字符串,则是不会重新创建对象,而是直接引用池中的字符串对象;如果“+”连接的两字符串中只要有一个不是字面常量串(即定义过的),是会产生新的字符串对象。
凡事也有例外,这个也不例外:如果“+”连接的字符串中两个或一个不是“字面常量”,但如果定义成常量字符串时,情况又有变化:

Java代码   
  1. final String str1 "aaa" 
  2. final String str2 "bbb" 
  3. String str3 "aaabbb" 
  4.   
  5.   
  6. String str4 str1 str2;  
  7. System.out.println(str3 == str4);//true  

但如果先定义final字符串,但未在定义处初始化,而初始化在块中,如下:
   

Java代码   
  1.  //此时str1与str2相当于变量,而不是常,因为块是在运行时才能确定,在编译时不能确定  
  2. final static String str1;    
  3.     final static String str2;    
  4.     static    
  5.         str1 ="aaa"   
  6.         str2 ="bbb"   
  7.      
  8.     public static void main(String[] args){    
  9.         String str3 str1 str2;  
  10.         String str4 ="aaabbb"   
  11.         System.out.println(str3==str4);   //输出为false  
  12.        
  13. String str=";与String str=new String();  
  14. str="会放入池中,但new String()不会放入池中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值