Java学习笔记:具体解释传值和传引用

传值和传引用

When you’re passing primitives into a method ,you get a distinct copy of the primitive. When you’re passing a reference into a method , you get a copy of the reference.

以上引自《Thinging in Java》。总结一下就是无论Java參数的类型是什么。一律传递參数的副本。

在Java中,变量分为以下两类:

  1. 对于基本类型变量(int、long、double、float、byte、boolean、char),Java是传值的副本。
  2. 对于一切对象型变量,Java都是传引用的副本,事实上穿引用副本的实质就是复制指向地址的指针。

一、传值

例1:传Int类型的值

程序

    @Test
    public void passInt(){
        int testInt = 0;
        System.out.println("Before operation, testInt is : " + testInt);
        intOperation(testInt);
        System.out.println("After operation, testInt is : " + testInt);
    }

    public void intOperation(int i){
        i = 5;
        System.out.println("In operation, testInt is : " + i);
    }

结果

Before operation, testInt is : 0
In operation, testInt is : 5
After operation, testInt is : 0

总结

结果不难看出来。虽说intOperation()方法改变了传进来的參数值,但对这个參数源本身并没有影响。參数类型是简单类型的时候。是按值传递的。以參数类型传递简单类型的变量时,实际上是将參数的值作为一个副本传进方法函数的,那么在方法函数中无论怎么改变值,其结果都是仅仅改变了副本的值,而不是源值

二、传引用

例2:传对象型变量

代码

@Test
    public void passClass(){
        Person person = new Person(175,140);

        System.out.println("Before classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);

        classOperation(person);

        System.out.println("After classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);
    }

    public void classOperation(Person person){
        person.height = 190;
        person.weight = 160;

        System.out.println("In classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);

    }

    public class Person{

        int height;
        int weight;

        public Person(int hei, int wei){
            this.height = hei;
            this.weight = wei;
        }
    }

结果

Before classOperation, the person height is 175 and the weight is 140
In classOperation, the person height is 190 and the weight is 160
After classOperation, the person height is 190 and the weight is 160

总结

从结果不难看出,在经过classOperation()处理之后。person的值发生了变化。

传引用和之前的传值是有一些差别的。能够这样理解:

  • 传值:当前的值好比是一个苹果A。在Java中的传值就相当于是把这个苹果复制了一个苹果B,实际上传递的事实上是苹果B,也就是说无论对苹果B做出如何的改动,苹果A是不变的。
  • 传引用:能够这样理解,当前的person是一个仓库,由于这个仓库(对象型变量)不像基本类型变量那么小,就好比一个仓库比一个苹果大的多的多一样。聪明的Java不会每次传递这个仓库的时候就又一次复制一份仓库传过去,它的做法是把钥匙A复制一把钥匙B(钥匙就相当于引用。引用指向仓库),传递的时候把钥匙B传递过去,和传值相似的地方在于钥匙B怎么改变都不影响钥匙A这个引用的值,可是钥匙A和钥匙B都指向同一个仓库,也就是说通过钥匙B来改变了这个仓库的值(比方偷取走一万吨粮食)。那么这个仓库的值就确确实实改变了,假设再通过钥匙A訪问这个仓库。得到的结果和B訪问时一样的(少了一万吨粮食)。

例3:传String类型

代码

    @Test
    public void passString(){
        String testString = "Hello";
        System.out.println("Before operation, testString is : " + testString);
        stringOperation(testString);
        System.out.println("After operation, testString is : " + testString);

    }

    public void stringOperation(String s){
        s = "World";
        System.out.println("In operation, testString is : " + s);
    }

结果

Before operation, testString is : Hello
In operation, testString is : World
After operation, testString is : Hello

总结

String类型也是对象型类型,所以它是传引用副本。

可是问题来了,String类型也是对象型类型,那么为什么String类型的对象。经过stringOperation()后。值没有发生变化?

首先String类型是对象型变量,所以它是传引用的副本。

不要由于String在Java里面很易于使用并且不须要new,就觉得String是基本变量类型。

仅仅只是String是一个非可变类,使得其传值还是穿引用显得没什么差别。

然后来解决上面说的问题。事实上问题是出在String的创建上面了,在stringOperation()中。s = "World";这条语句相当于运行了String s = new String("World");。对,也就是说,在这种方法中的s相当于是一个新的String对象,当这个函数结束时,s作用消失。原来内存地址的值没有变化。

以下来具两个样例来说明这个问题:

例4:传String类型——使用new来创建新对象

代码

    @Test
    public void passString(){
        String testString = new String("Hello");
        System.out.println("Before operation, testString is : " + testString);
        stringOperation(testString);
        System.out.println("After operation, testString is : " + testString);

    }

    public void stringOperation(String s){
        s = new String("World");
        System.out.println("In operation, testString is : " + s);
    }

输出

Before operation, testString is : Hello
In operation, testString is : World
After operation, testString is : Hello

总结

例4和例3的差别就在于,创建String都使用了new,最后的输出结果是不一样的。

例5:传对象型变量——在classOperation()使用new创建

代码

public class Person{

        int height;
        int weight;

        public Person(int hei, int wei){
            this.height = hei;
            this.weight = wei;
        }
    }

    @Test
    public void passClass2(){

        Person person = new Person(175,140);

        System.out.println("Before classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);

        classOperation2(person);

        System.out.println("After classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);
    }

    public void classOperation2(Person person){

        person = new Person(190,160);

        System.out.println("In classOperation, the person height is " + person.height +
                " and the weight is " + person.weight);

    }

结果

Before classOperation, the person height is 175 and the weight is 140
In classOperation, the person height is 190 and the weight is 160
After classOperation, the person height is 175 and the weight is 140

总结

最后一个样例事实上就是为了说明一个情况,例3的stringOperation()中看到了字符串的赋值操作事实上就相当于例5中classOperation2()里面new出来的新对象。

三、总结

上面的分析主要是基于结果来推断的,可能不是特别准确。望批评指正。

文章来源:http://blog.csdn.net/zhaodedong

时间: 2024-08-29 05:05:54

Java学习笔记:具体解释传值和传引用的相关文章

Java实参和形参与传值和传引用

实参和形参的定义: 形参出现函数定义中,在整个函数体内都可以使用,离开函数则不能使用. 实参出现在主函数中,进入被调函数后,实参变量也不能使用. 形参和实参的功能是做数据传送.发生函数调用时,主调函数把实参的值传送给被调函数的形参从而向被调函数传送数据. 实参和形参的区别: 1.形参变量只有在被调用时才分配内存单元,在调用结束后,立即释放所分配的内存单元.因此,形参只有在函数内部有效.函数调用结束返回主调函数后则不能在使用该形参变量. 2.实参可以变量.函数.数组等.无论实参是何种类型的,在进行

Java学习笔记:详解传值和传引用

传值和传引用 When you're passing primitives into a method ,you get a distinct copy of the primitive. When you're passing a reference into a method , you get a copy of the reference. 以上引自<Thinging in Java>,总结一下就是不管Java参数的类型是什么,一律传递参数的副本. 在Java中,变量分为以下两类: 对

java学习笔记——自动拆箱装箱(Autoboxing&amp;Unboxing)

一.基本类型打包器 1.基本类型:long.int.double.float.boolean 2.类类型:Long.Integer.Double.Float.Boolean 区别:基本类型效率更高,类类型的对象却可以携带更多的信息. public class TestInteger01 { public static void main(String[] args) { int a = 10; int b = 20; Integer A = new Integer(a); Integer B =

Java学习笔记3-操作符

Java基本操作符:+.-.*./.%.=.==.!=.+=.-=. 优先级:先乘除后加减,如果是连接符+号会优先往前匹配,比如 a+++++b,会被解释称 a++ ++ +b,所以会报错,需要自行使用括号隔离为 (a++) + (++b). 对象的引用如果赋值给了对象的引用后,2 个对象将指向同一个引用,有一个对象的引用重新赋值后将同时影响到另一个对象,比如 ClassName classA = new ClassName(); ClassName classB = new ClassName

java学习笔记3——java关键字

java学习笔记3——java关键字 虽然老师说不用刻意的去记忆,但是我还是在网上找到了非常详细的注解,再次收藏 关键字的类型表: 各个关键字的详细注解和实例,按首字母排序: 1.abstract abstract 关键字可以修改类或方法. abstract 类可以扩展(增加子类),但不能直接实例化. abstract 方法不在声明它的类中实现,但必须在某个子类中重写. -示例- public abstract class MyClass{ } public abstract String my

Java学习笔记day_01

Java学习笔记(复习整理) 虽然不知道该怎么写,但是不起步就永远不知道该怎么做..刚开始可能会写的很差劲,但会一点一点变好的. 本笔记是以我按照传智播客的视频和Java核心思想来学习,前面的基础部分主要是用于个人的复习使用的. 第一段代码:HelloWorld public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } }

【Java学习笔记之二十六】深入理解Java匿名内部类

在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始化匿名内部类.匿名内部类使用的形参为何要为final. 一.使用匿名内部类内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 } 在这里我们看到使用匿名内部类我们必须要继承一个父类或者

Java 学习笔记(2015.7.13~17)

Java 学习笔记(2015.7.13~17) Java this关键字 表示本类中的属性,调用本类中的方法 class Person {        private String name;         private int age;         public Person(String name, int age) {         this.name = name;//调用本类中的属性         this.age = age;//同上} //get&set方法:    

Java学习笔记&lt;3&gt;面向对象相关

面向对象的基本思想 从现实世界客观存在的事务出发来构造软件系统,并在系统的构造中尽可能运用人类的自然思维方式,如抽象.分类 继承.聚合.多态等. 类和对象的关系 对象中存储了类规定的数据类型,并且对象可以调用类的方法. java面向对象 <1>对象是java程序的核心,一切皆对象. <2>对象可以看成静态属性(成员变量)和动态属性(方法)的封装体. <3>类是创新同一类型对象的模版,定义了该类型对象应具有的成员变量及方法. 类的定义 成员变量可以用java语言的任何一种