`
leejunner
  • 浏览: 87867 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA经典问题:传值还是传引用 zz

    博客分类:
  • JAVA
 
阅读更多
在实际生产项目中遇到这样的问题,如,传数据给一个方法进行处理,返回处理后的数据,处理的过程中可能出现不是异常的 但是影响结果的情况,需要拿到数据的同时判断是否发生了意外。我能想到的解决方法是 1,在数据的数据结构中标记异常 2,传递一个其他对象进去记录异常 那么关于方法2,我搜了一篇文章来更好的理解.
---------------------------------------------------------------------------------
经典的问题,但却不容易弄懂,尤其对有c基础的java程序员来说,更容易引起混乱,这里我试图简单点描述。

“java函数是传值的,java函数传递的参数是对象的引用”

这两句话好像初听上去有些矛盾,但却是事实,因而引起很多初学者的混乱。在这里我试图据个简单的例子来说明java的这个特性,可能不全面,希望大家来补全。

public class TestRef {
        public static void main(String[] args)
        {
                ValueObject vo1 = new ValueObject("A", 1);
                System.out.println("after vo1: " + vo1.getName()); //=A
                
                changeValue1(vo1);
                System.out.println("after changeValue1: " + vo1.getName());
                //=A1, changed
                
                changeValue2(vo1);
                System.out.println("after changeValue2: " + vo1.getName()); 
                //=A1, changeValue2内部的赋值不会影响这里。
        }
/**
         * 使用vo1自身的函数对其内部数据进行改变是有效的,函数外可反映出来
         * 这种object称为可变的(mutable)
         * @param vo1
         */
        private static void changeValue1(ValueObject vo1) {
                vo1.setName("A1");
        }

        /**
         * 在函数内给vo1重新赋值不会改变函数外的原始值
         * @param vo1
         */
        private static void changeValue2(ValueObject vo1) {
                vo1 = new ValueObject("B", 2);
                System.out.println("inside changeValue2: "+ vo1.getName());
                //=B,赋值操作引起的结果变化仅在changeValue2内部有效
        }
}

class ValueObject {
        
        public ValueObject() {}
        
        public ValueObject(String name, int id)
        {
                this.name = name;
                this.id = id;
        }
        
        private String name;
        private int id;
        public int getId() {
                return id;
        }
        public void setId(int id) {
                this.id = id;
        }
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
}

解释,vo1作为一个object,当它被用作函数参数的时候传递给函数的是一个引用值,这个名称有点怪,又有引用又有值,到底是引用还是值呢,就看你怎么理解了。如果你是去考试,官方的答案是值。可是看起来又象引用啊,希望从这个例子,你能理解java参数传递和和C/C++程序中的引用传递的不同的地方。另外,这也是java作为OO语言的特性之一:封装的体现。

先讲一下对象赋值的关系,举例来说,下列代码:

ValueObject v2, v3;
v2 = new ValueObject("C", 3); 粗体的部分创建了一个数据结构,假设存放在内存地址A000,赋值给句柄 v2
v3 = new ValueObject("D", 4); 粗体的部分创建了一个数据结构,假设存放在内存地址B000,赋值给句柄 v3
v2 = v3; 这句话的作用是把操作B000的地址的句柄的值付给了v2的句柄,使得v2和v3一样操作B000的地址,这意味着:
1.原来v2指向的地址A000变成无主的内存地址,将自动被jvm回收。
2.既然v2和v3指向同一片地址,对v3的修改v2也能得到,反之亦然。

整理得下列代码,请感兴趣的朋友运行验证
ValueObject v2 = new ValueObject("C", 3);
ValueObject v3 = new ValueObject("D", 4);
v2 = v3;
System.out.println("after v2=v3");
System.out.println("v2= "+ v2.getName());//=D
System.out.println("v3= "+ v3.getName());//=D
v3.setName("C1");
System.out.println("after v3 setnameTo C1");
System.out.println("vo2= "+ v2.getName());//=C1
System.out.println("vo3= "+ v3.getName());//=C1

因此,可以得出结论,java中对象的每个实例(instance, 比如vo1, v2, v3 都是ValueObject的实例)的内存地址是唯一的,它一旦被创建,能够对这个地址进行操作的就是每个实例自己,如果ValueObject类中没有public void setName之类的方法对这个类的实例中的数据进行修改的话,程序是没有任何别的方法可以修改ValueObject类的实例中的数据,这个就是java的封装特性。对于不提供修改内部数据的方法的类,我们称为不可变(immutable)的类。在函数中对传入的参数变量进行赋值操作,只能在函数范围内改变局部变量指向的引用地址,但是不会改变原始地址的内容。因此,在changeValue2(...)函数内部的vo1和函数外的vo1虽然名字相同,但是实际上是不同的实例变量,只不过指向了和函数外的vo1同样的地址,所以当我们用vo1=... 对其进行赋值的时候,只不过是把函数内的临时变量指向了新的地址,并没有改变原始vo1内存地址中的内容。这就是在运行changeValue2(...)之后,vo1的值在main范围内仍然没有被修改的原因。而changeValue1里面是调用的ValueObject本身的function来更改其内容,因此是原始内存地址中的数据被更改了,所以是全局有效的。
分享到:
评论

相关推荐

    解决java.security.InvalidKeyException: Illegal key size

    在Java编程环境中,有时会遇到一个常见的错误:"java.security.InvalidKeyException: Illegal key size"。这个错误通常是由于Java安全策略的限制导致的,尤其是当你尝试使用超过默认限制的密钥长度(例如,超过128位...

    JAVA源码Java毕业论文:搜索引擎系统附源代码

    JAVA源码Java毕业论文:搜索引擎系统附源代码提取方式是百度网盘分享地址

    base zz zz zz zz

    base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz

    fizzbuzz:Java FizzBu​​zz

    总结来说,"fizzbuzz:Java FizzBu​​zz"是一个专注于Java FizzBuzz问题的项目,包含多种不同的实现方式,旨在帮助面试者、学习者和开发者提升编程技能,理解和比较不同的解决问题策略。通过研究这些实现,你可以...

    阿里巴巴java笔试zz.

    在技术面试中,编程知识的考察自然是核心内容,但企业也越来越注重求职者所具备的软技能,尤其是逻辑推理、决策分析与问题解决等能力。阿里巴巴的Java笔试题尤为注重这一点,即使部分题目与直接的编程技能无直接关联...

    Zz: java 线程池设计思想

    Java线程池是一种高效管理线程资源的工具,它的设计思想是基于生产者消费者模型,借鉴了工厂模式和代理模式的元素。线程池通过维护一组可重用线程,减少了创建和销毁线程的开销,提高了系统响应速度与并发处理能力。...

    java 段点续传 例子

    1. **文件IO操作**:Java的`java.io`包提供了丰富的文件输入/输出流类,如`FileInputStream`、`FileOutputStream`、`RandomAccessFile`等,这些类在断点续传中起到关键作用。特别是`RandomAccessFile`,它能让我们在...

    聊天工具的java开发 超越QQ 天翔ZZ

    《聊天工具的Java开发:超越QQ,天翔ZZ》 在IT行业中,开发一款聊天工具是一项挑战性十足的任务,尤其当目标是超越如QQ这样的巨头时。本文将深入探讨使用Java语言开发聊天工具的关键知识点,结合"天翔ZZ"这个项目,...

    基于Java与HTML的studyjava-zz设计源码,深入探索Java编程新视野

    在“studyjava-zz”项目中包含的66个偏好设置文件,可能是为了给用户提供更好的使用体验,通过配置文件保存用户的设置,使得用户在使用项目时能够感觉到更为便利和贴心。 Markdown文档被广泛用于编写文档和说明,在...

    zz.rar_JAVA俄罗斯方块

    本项目“zz.rar_JAVA俄罗斯方块”提供了一套完整的JAVA源代码,让开发者可以深入理解如何用JAVA语言实现这个经典游戏。本文将详细解析该项目中的关键知识点,帮助读者更好地理解和掌握JAVA编程技巧。 1. **JAVA基础...

    FizzBuzz:解决 FizzBu​​zz 问题

    该代码利用 Java 8 lambda 和流支持来解决 FizzBu​​zz 问题。 持续集成是通过 CloudBees-CloudFoundry服务实现的,其中 git push 到 repo。 如果构建稳定,则会在 CloudBees 上触发构建并部署到 CloudFoundry。 ...

    FizzBuzz-Java-Gradle:带有Gradle的Java FizzBu​​zz样板

    本项目“FizzBuzz-Java-Gradle”提供了一个使用Java语言和Gradle构建工具实现FizzBuzz问题的模板,旨在帮助开发者理解如何将现代构建工具应用于简单的编程任务。 首先,让我们了解什么是FizzBuzz问题。FizzBuzz问题...

    百度地图毕业设计源码-studyjava-zz:Java再回首,重新探索这个精彩的世界

    studyjava-zz Java再回首,重新探索这个精彩的世界。 斯人已去,独探索矣。 背景 从事Android移动开发4年(Java语言),因朋友想转行(铁路),需要带他转行入门。 朋友是电脑小白,没有任何编程经验,也没有学习过...

    springboot基于java的招聘求职系统_886zz792毕业设计源码数据库.zip

    采用Java作为主要开发语言,结合Spring Boot框架和MySQL数据库技术,不仅确保了系统的高效运行和良好的用户体验,也保障了系统的可维护性和扩展性。 jdk版本:jdk1.8+ 编程语言: java 框架支持:springboot 数据库: ...

    springboot-基于java的招聘求职系统-886zz792.zip

    标题中提到的“springboot-基于java的招聘求职系统-886zz792.zip”暗示了这个压缩包是与一个基于Spring Boot框架和Java语言开发的招聘求职系统相关。Spring Boot是一个开源的Java基础框架,用于简化新Spring应用的...

    利用 Best Fit 算法解决物流3D bin packing问题 Java实现

    在物流行业中,3D bin packing(三维箱包装)问题是一个重要的优化问题,它涉及到如何高效地将各种形状和尺寸的物体放入最小数量的箱子中,以节省存储和运输空间。"Best Fit"算法是一种常见的启发式策略,用于解决这...

    利用 First Fit 算法解决物流3D bin packing问题 Java实现

    在这个Java实现中,我们探讨如何利用First Fit算法有效地解决3D装箱问题。 First Fit算法的基本思想是将每个3D物体按照其尺寸顺序尝试放入已有的箱子中,只要能放下,就立即放入,而不是寻找最佳位置。这种简单的...

    JAVA源码lobby(经典board游戏Domination)

    - **跨平台性**:Java编写的程序可以在任何安装了JVM的平台上运行,这为游戏的多平台发布提供了极大的便利。 - **丰富的类库支持**:Java拥有庞大的社区和丰富的类库资源,使得开发者能够快速实现各种复杂功能。 - *...

    zz牌类小游戏24点

    "zz牌类小游戏24点" 是一个基于Java编程语言开发的桌面游戏,其核心玩法是24点游戏。24点游戏是一种流行的心算游戏,玩家需要利用四张给出的扑克牌上的数字,通过加、减、乘、除运算,使得结果等于24。这个游戏旨在...

Global site tag (gtag.js) - Google Analytics