java参数传递机制浅析

标签: java 参数 | 发表时间:2014-04-28 17:46 | 作者:RowandJJ
出处:http://blog.csdn.net
欢迎转载,转载请声明出处!
-----------------------------------------
前言:
java语言中,参数的传递只有一种机制,那就是 值传递
举例:
下面将通过几个例子来说明java中的参数传递机制,这些例子基本涵盖了所有参数传递的情况。
1.基本数据类型:
public static void testBase(int i)   
 {
       i = 2;
 }

 测试:
int i = 10;
System.out.println(i);//10
testBase(i);
System.out.println(i);  //10

结果当然很显然都是10,因为基本数据类型传递的是值的一份拷贝(副本),对副本操作不影响原始值。

2.对象:
    2.1.对参数重新赋值:
public static void testObj(Object o)
{
   o = new Object();
}

测试:
Object o = new Object();
System.out.println(o);// java.lang.Object@1ff61bcf  
testObj(o);
System.out.println(o);//java.lang.Object@1ff61bcf

方法中的参数只是原始对象的一份拷贝,更准确的讲是地址的一份拷贝,故而对其进行重新赋值并不会影响原始对象。

  2.2.改变对象内部数据:
public class S
{
    private Object o = new Object();
    private int i = 2;
    
    public Object getO()
    {
        return o;
    }
    public void setO(Object o)
    {
        this.o = o;
    }
    public int getI()
    {
        return i;
    }
    public void setI(int i)
    {
        this.i = i;
    }
}
测试方法:
public static void testA(S s)
{
   s.setI(100);
   s.setO(new Object());
}

测试:
S s = new S();
System.out.println(s.getI()+","+s.getO());// 2,java.lang.Object@11b75be2  
testA(s);
System.out.println(s.getI()+","+s.getO());//100,java.lang.Object@1cf15b84

因为对象作为参数传递的是对象的引用地址(注意,这是值传递),故参数所指的对象和原始引用所指的对象都是堆中的同一个对象,故在测试方法中修改对象内容会改变对象的数据。

试试自己分析这个例子(跟上面是一样的):
package test;
public class A
{
    int t = 6;
    Object obj = new Object();
    public static void main(String[] args)
    {
        A a = new A();  
        a.func(a.t,a.obj);//问t和obj的值是否变化,答案:不变化
    }
    public void func(int t,Object obj)
    {
        t = 7;
        obj = null;
    }
}
3.数组:
    3.1.对参数重新赋值:
  public static void testArr(int[] arr)
    {
        arr = null;
    }
测试:
int[] arr = {1,2};
System.out.println(arr[0]);//1
testArr(arr);
System.out.println(arr[0]);  //1
传递机制跟对象一样,也是传递的对象地址,故而也不改变原始值。
     3.2.改变参数内部数据:
 public static void testArr(int[] arr)
    {
        arr[0] = 100;
    }
测试:
int[] arr = {1,2};
System.out.println(arr[0]);//1
testArr(arr);
System.out.println(arr[0]);//100
结果无须解释了吧。
4.基本数据类型的包装类型:
    其实跟基本类型是一样的。
public static void testWrapper(Float f)
{
     f = 100.0f;
}
测试:
Float f = 12.0f;
System.out.println(f);//12.0
testWrapper(f);
System.out.println(f);//12.0
5.【重点】字符串:
字符串作为参数的情形比较特殊。
    5.1.对参数重新赋值:
public static void testStr1(String str)
{
    str = "testOK";
}
测试:
 String str = "test";       
 System.out.println(str);//test
 testStr1(str);
 System.out.println(str);//test
根据前面的思路,字符串也是对象,参数拷贝的是对象的地址,在方法内部将参数指向另一个堆对象并不影响原始对象引用的指向。

 5.2.对参数执行替换、连接等操作:
 public static void testStr2(String str)   
 {
     str = str.concat("OK");
     str = str.toUpperCase();
 }
测试:
String str = "test";
System.out.println(str);//test
testStr2(str);
System.out.println(str);//test

也是对str的重新赋值,不改变原始串.
    5.3.对参数执行+的操作
public static void testStr3(String str)
    {
        str += "OK";
    }
测试:
String str = "test";
System.out.println(str);//test
testStr3(str);
System.out.println(str);//test
如果你以为第二次输出testOK,那就错啦,String类的’+‘是经过重载的,编译时会还原成StringBuilder的append操作,并且new了一个StringBuilder对象:
str += "OK";
str = new StringBuilder(str).append("OK").toString();//编译时会还原成这样
显然也是对副本重新赋值,并不影响原始的对象。
使用javap -c反编译一下会很直观:

6.StringBuffer或StringBuilder作为参数:
    6.1重新赋值
public static void testStringBuilder(StringBuilder sb)
{
     sb = new StringBuilder("testOK");
}
 测试:
StringBuilder sb = new StringBuilder("test");
System.out.println(sb.toString());//test
testStringBuilder(sb);
System.out.println(sb.toString());//test
  6.2在方法内部调用StringBuffer或StringBuilder的append方法:
public static void testStringBuilder(StringBuilder sb)
{
    sb.append("OK");
}
 测试:
StringBuilder sb = new StringBuilder("test");
System.out.println(sb.toString());//test
testStringBuilder(sb);
System.out.println(sb.toString());//testOK
7.交换问题
    经过上面的例子,相信对java参数传递机制比较清楚了,所以请不要再写这样的代码了:
public static void swap(Integer a, Integer b)
{
 Integer temp = a;
 a = b;
 b = temp;
}
这根本不能交换两个数.



总结:
1.如果参数是基本数据类型(包括对应的包装类型),那么参数传递时只是原始值的一份拷贝或者叫副本,对副本操作并不影响原始值;
2.如果参数是对象(引用类型),那么参数传递时传递的是对象的地址的一份拷贝,所以对对象内部属性的操作会改变原始对象相应值,但是对该参数进行重新赋值并不会影响原始对象;
3.String类型作为参数进行传递时,传递的也是地址。但是String类比较特殊,对参数进行concat,replace,’+‘等操作时不影响原始的串,对参数重新赋值当然也不影响原始字符串。
4.数组类型作为参数跟传递对象时一样的。

















作者:RowandJJ 发表于2014-4-28 9:46:47 原文链接
阅读:73 评论:0 查看评论

相关 [java 参数] 推荐:

java socket参数详解:BackLog

- - 开源软件 - ITeye博客
 java socket参数详解:BackLog. 输入连接指示(对连接的请求)的最大队列长度被设置为 backlog 参数. 如果队列满时收到连接指示,则拒绝该连接. backlog参数必须是大于 0 的正值. 如果传递的值等于或小于 0,则假定为默认值. 经过测试这个队列是按照 FIFO(先进先出)的原则.

Java虚拟机(JVM)参数简介

- - ITeye博客
Java虚拟机(JVM)参数简介. 在Java、J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能. JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置. 但是在生产环境中,为了提高性能,往往需要调整这些参数,以求系统达到最佳新能. 另外这些参数的配置也是影响系统稳定性的一个重要因素,相信大多数Java开发人员都见过“OutOfMemory”类型的错误.

Java可变参数的性能分析

- - Java译站
可变长参数列表是Java 5中的一个新特性. 如果方法需要传入多个同类型参数的话,这个功能就非常有用. 比如说,Java 5之前如果要写一个方法来将所有入参打印到控制台上的话,它的代码会是这样的:. Java 5增加了对可变参数的支持. 这个方法现在看起来就简单多了(译注:这里看起来简单难道不是因为新的for循环.

Java 6 JVM参数配置说明

- - Java - 编程语言 - ITeye博客
-XX:+

java参数传递机制浅析

- - CSDN博客编程语言推荐文章
java语言中,参数的传递只有一种机制,那就是 值传递. 下面将通过几个例子来说明java中的参数传递机制,这些例子基本涵盖了所有参数传递的情况. 结果当然很显然都是10,因为基本数据类型传递的是值的一份拷贝(副本),对副本操作不影响原始值.     2.1.对参数重新赋值:. 方法中的参数只是原始对象的一份拷贝,更准确的讲是地址的一份拷贝,故而对其进行重新赋值并不会影响原始对象.

JAVA性能优化 - IBMJDKJVM参数设置

- - 编程语言 - ITeye博客
 本文将描述IBM JDK下常用参数的设置.   -Xms:最小堆大小.   -Xmx:最大堆大小.   -Xminf and -Xmaxf:GC(垃圾回收)之后可用空间的最小值最大值.   -Xmine and -Xmaxe:堆增长的最小最大值.   -Xmint and -Xmaxt:垃圾回收占时间整个运行时间的比例,默认是5%.

Java 中的可选参数 | Java Debug 笔记

- - 掘金 后端
本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看. 如何使用 Java 中的可选参数. 一定程度上来讲, varargs (即长度可变的参数)可以做到这一点. 除此之外,必须提供方法声明中的所有变量. 如果想让变量是可选的,那么可以通过重载的方式,此时重载的方法是不带参数的.

Java 6 JVM参数选项大全(中文版)

- LightingMan - 淘宝JAVA中间件团队博客
本文是基于最新的SUN官方文档Java SE 6 Hotspot VM Options 编写的译文. 主要介绍JVM中的非稳态选项及其使用说明. 为了让读者明白每个选项的含义,作者在原文基础上补充了大量的资料. 希望这份文档,对正在研究JVM参数的朋友有帮助. 另外,考虑到本文档是初稿,如有描述错误,敬请指正.

java 三个点号...的含义-可变参数

- - ITeye博客
  在java 1.5 SE后,引入了三个点号"...",表示参数是可以有无数个的意思. // 参数都是int类型的,所以可以用foreach. 已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.

Java中的锁(Locks in Java)

- - 并发编程网 - ifeve.com
原文链接 作者:Jakob Jenkov 译者:申章 校对:丁一. 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂. 因为锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,所以我们还不能完全摆脱synchronized关键字( 译者注:这说的是Java 5之前的情况).