zoukankan      html  css  js  c++  java
  • 为什么说Java中只有值传递?

    一.为什么说Java中只有值传递?

    对于java中的参数传递方式中是否有引用传递这个话题,很多的人都认为Java中有引用传递,但是我个人的看法是,Java中只有值传递,没有引用传递。

    那么关于对象的传递怎么解释呢?难道对象不是一个引用传递吗?

    对于这一点我的看法是,对象的传递只不过是将对象的地址值传递到方法里,只要你不改变这个地址值,那他就指向原来的引用不会改变,但是你一旦改变了这个地址值,那么你就改变了他的实际引用。那归根到底还不是值传递吗?只不过我普通类型传递的是copy后的普通类型的值,我引用传递的是一个copy的地址值而已。

    当然我在举例子的时候还是将他们分开:

    实际的例子如下:

    1.值传递

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 10:18
     * 函数得值传递
     */
    public class Valuetransmit {
        public static void main(String[] args) {
            int num=0;//定义一个值
            System.out.println("在main中定义的值为:"+num);
            fan(num);
            System.out.println("在调用函数的值为:"+num);
        }
        public static  void fan(int num){
            System.out.println("###########进入函数###########");
            System.out.println("实参为:"+num+"此时的值没有被改变!");
            //修改函数的参数:
            ++num;
            System.out.println("在函数中实参自增后的值为:"+num);
            System.out.println("###########退出函数###########");
        }
    }

    可以看出值传递是不会改变他本身的值。

    所以Java中你就无法使用一个函数将两个变量的值交换。

    尝试如下:

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 10:35
     */
    public class ChangeValue {
        public static void main(String[] args) {
            //定义两个变量
            int num1=0;
            int num2=1;
            System.out.println("未经过函数的交换的值为:"+"num1="+num1+"	num2="+num2);
            change(num1,num2);
            System.out.println("经过函数的交换后的值为:"+"num1="+num1+"	num2="+num2);
        }
        //设置一个”交换函数“
        public static void change(int num1,int num2){
            int temp=num1;
            num1=num2;
            num2=temp;
        }
    }
    

    失败了,Java不能替我们完成这一项任务,但这无伤大雅,因为我们并不想交换两个变量的值就去定义一个函数,这实在是小题大做了。

    2.杠精们的"引用传递"

     那么首先我需要一个对象,来检测一下在函数中的对象是否和外面的对象相同。

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 10:53
     * 对象的判断函数实参对象,和传递对象是否相同
     */
    public class ObjectJudge {
        public static void main(String[] args) {
            A a=new A(0);
            System.out.println("main函数中的对象的哈希值为:"+a.hashCode());
            System.out.println();
            fan(a);
        }
        public static void fan(A a){
            System.out.println("函数中的对象的哈希值为:"+a.hashCode());
        }
    }
    class A{
        int num;
        public A(int num) {
            this.num = num;
        }
    }

    可以看出这两个引用指向的对象的哈希值是一样的,那么也就是说这两个引用指向的是同一个对象。

    那么也是说我们在函数对对象a的操作也会影响外面的对象。

    来看下面的操作:

    package com.cjm.functionparameter;
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 10:53
     * 对象的判断函数实参对象,和传递对象是否相同
     */
    public class ObjectJudge {
        public static void main(String[] args) {
            A a=new A(0);
            System.out.println("main函数中的对象的哈希值为:"+a.hashCode());
            System.out.println("在main函数中的对象的num为:"+a.num);
            System.out.println("##########函数开始##########");
            fan(a);
            System.out.println("##########函数之后##########");
            System.out.println("在main函数中的对象的num为:"+a.num);
        }
        public static void fan(A a){
            System.out.println("函数中的对象的哈希值为:"+a.hashCode());
            a.num=10;
            System.out.println("在函数中的对象的num为:"+a.num);
        }
    }
    class A{
        int num;
        public A(int num) {
            this.num = num;
        }
    }

    那么我们现在再来修改一下,将函数中的对象修改为其他的引用会发生什么

    package com.cjm.functionparameter;
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 10:53
     * 对象的判断函数实参对象,和传递对象是否相同
     */
    public class ObjectJudge {
        public static void main(String[] args) {
            A a=new A(0);
            System.out.println("main函数中的对象的哈希值为:"+a.hashCode());
            System.out.println("在main函数中的对象的num为:"+a.num);
            System.out.println("##########函数开始##########");
            fan(a);
            System.out.println("##########函数之后##########");
            System.out.println("在main函数中的对象的num为:"+a.num);
        }
        public static void fan(A a){
            System.out.println("为做改变前,函数中的对象的哈希值为:"+a.hashCode());
            a=new A(0);
            System.out.println("做了重新赋值后,函数中的对象的哈希值为:"+a.hashCode());
            a.num=10;
            System.out.println("在函数中的对象的num为:"+a.num);
        }
    }
    class A{
        int num;
        public A(int num) {
            this.num = num;
        }
    }

    现在就是我们将 实参重新赋值了一个新的对象,那么我们可以发现a指向的对象已经改变,所以当我们对a进行操作时,main函数中的实参就不会改变了。

    到这里我们可以总结出:Java中的参数传递就是值传递,只不过普通类型传递的是copy后的值,而对象传递的就是地址值,只要你不去改变地址值,那么你在函数中对对象的操作也会影响原来的对象。

    那么现在又来了一个问题:

    3.Java能不能交换两个对象呢?

    直接上代码:

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 12:26
     */
    public class ChangeObject {
        public static void main(String[] args) {
            A a1=new A(10);
            A a2=new A(20);
            System.out.println("在执行函数前:a1的值为:"+a1.num+"a2的值为:"+a2.num);
            change(a1,a2);
            System.out.println("在执行函数后:a1的值为:"+a1.num+"a2的值为:"+a2.num);
        }
        public static void change(A a1,A a2){
            A temp=a1;
            a1=a2;
            a2=temp;
        }
    }

    然而并没有交换。。。。。。

     我们输出所有的哈希码:

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 12:26
     */
    public class ChangeObject {
        public static void main(String[] args) {
            A a1=new A(10);
            A a2=new A(20);
            System.out.println("在执行函数前:a1的值为:"+a1.num+"a2的值为:"+a2.num);
            System.out.println("main函数中的a1的哈希码为:"+a1.hashCode()+"a2的哈希码为:"+a2.hashCode());
            System.out.println("############执行函数#############");
            System.out.println();
            change(a1,a2);
            System.out.println("在执行函数后:a1的值为:"+a1.num+"a2的值为:"+a2.num);
            System.out.println("############函数之后#############");
        }
        public static void change(A a1,A a2){
            System.out.println("函数刚开始时的a1的哈希码为:"+a1.hashCode()+"a2的哈希码为:"+a2.hashCode());
            A temp=a1;
            a1=a2;
            a2=temp;
            System.out.println("函数中的a1的哈希码为:"+a1.hashCode()+"a2的哈希码为:"+a2.hashCode());
        }
    }

     

     似乎没有问题:因为在函数中a1和a2的地址值是改变了,但是这是一个地址值,你修改了他有什么作用呢?

     图解如下:

    开始时:

    在函数中进行交换:

    那么此时main函数中的对象会交换吗?当然不会!所以还是那一句话:

    到这里我们可以总结出:Java中的参数传递就是值传递,只不过普通类型传递的是copy后的值,而对象传递的就是地址值,只要你不去改变地址值,那么你在函数中对对象的操作也会影响原来的对象。

    4.针对一个特殊类String类

    为什么说这个String特殊呢?

    因为:面试题里面都是拿他做例子所以他特殊(#手动滑稽)

    当然不是了,主要是因为String是final类不能在对象上去修改,只能new一个新的对象。

    所以看看下面的代码你就知道我的意思了:

    当你的参数拼接后其实已经改变了你这个对象的引用。而你的形参的类型是final的这也就代表着你不能改变他的引用对像。

    讲这个似乎对我们这个没有帮助,那么我们来看看下面的代码:

    package com.cjm.functionparameter;
    
    /**
     * @author 程嘉明
     * @version 创建时间:2018/8/9 14:08
     * String类型是否能够在拼接符的作用下不改变对象
     */
    public class StringAdd {
        public static void main(String[] args) {
           String str="101010";
            System.out.println("在没有进入函数之前String的对象的哈希码为:"+str.hashCode());
           stringChange(str);
            System.out.println("str经过函数的值为:");
            System.out.println(str);
        }
        public static void stringChange(String str){
            System.out.println("进入函数后没有修改String之前的Str的哈希码为:"+str.hashCode());
            str+="aaaa";
            System.out.println("进入函数后修改String之后的Str的哈希码为:"+str.hashCode());
        }
    }

    在修改时我们的值没有发生改变。

    就是拼接后你的String对象已经改变,接下来你所做的就与main函数里的str变量没有关系了。

     
  • 相关阅读:
    QT5 串口收发实例代码
    3D数学基础:四元数与欧拉角之间的转换
    3D数学基础:3D游戏动画中欧拉角与万向锁的理解
    WorldWind源码剖析系列:WorldWind如何确定与视点相关的地形数据的LOD层级与范围
    虚拟地球原理与实现
    开源(免费)三维 GIS(地形,游戏)
    [转]有关WorldWind1.4的worldwind.cs窗口设计器打开错误的解决方法
    [转]仿World Wind构造自己的C#版插件框架——WW插件机制精简改造
    [转]的C#实现三维数字地形漫游(基于Irrlicht)
    [转]开发Visual Studio风格的用户界面--MagicLibrary使用指南
  • 原文地址:https://www.cnblogs.com/SAM-CJM/p/9448905.html
Copyright © 2011-2022 走看看