在讨论上面问题之前,我们先来看看函数的实参为形参赋值时,传递的到底是什么东西?实际上实参赋值给形参时,是将自己的一份拷贝传递到函数内部。这就不难理解,不管是“传址”还是“传值”,本质上都是传值,但传递值的类型是不相同的。对于普通基本类型,就是这个数值的拷贝,所以函数内部对其进行修改,不会影响传递的实参的值;而对于指针来说,函数内部对其修改,影响的是指针指向的那片内存区域,但实参指针的值也没有发生变化(指针还是指向那片内存区域)。
java中不存在指针,但实际上java中对象的引用(句柄)就是指针。 由此可见,java中所谓的“传址”其实也是一种传值(或者说java中没有传址)。我们给方法“传址”时实际上是传递的是实参的地址的一个拷贝,它跟我们的实参(这里把他们暂时都理解为指针)所指向的地址虽然相同,但他们却是两个不同的实体。所以当我们在方法中对形参进行重新赋值时,改变的只是形参所指向的地址,而实参所指向的地址没有被改变,所以其内容不变。
上面两段是整体总结,下面我们来看一下设计到的知识点:
1.Java中的参数传递有传值和传址两种;
2.基本类型和String型作为参数时,为传值方式,只把值传入方法,不管在方法中怎么处理这个参数,原值不变;
3.其他引用类型作为参数时,为传址方式,将指向内存中的地址传入方法,方法中此内存地址中的值发生变化时,原值也会改变;
4.例外:
(1)如果引用类型的对象通过传址方式将其指向内存中的地址传入方法后,方法中使用new关键字重新给参数赋值时,会在内存中重新开辟空间,参数指向新的内存空间,此时参数和原对象指向的就不是同一个地址了,参数值的变化不会改变原值;
(2)String型是引用类型,但是String型作为参数,是传值方式,可以通过以下两种方式来理解:
<1>String本质上是基本类型的char[],基本类型作为参数时,为传值方式;
<2> 字符串在内存中是存储在堆中的一个常量,String对象指向内存中这个常量的地址,通过传址方式将地址传入方法后,方法中如果通过字符串给参数赋值,则会重新在堆中创建一个字符串常量,并指向这个地址,原值依然指向原来的字符串常量地址,参数值的变化不会改变原值,如果通过new关键字给参数赋值,参见 (1)中的解释。
下面为大家一一详解:
一、别名的问题
“别名”意味着多个句柄都试图指向同一个对象,若有人向那个对象写入一点什么东西,就会产生别名问题。如果其他句柄所有者不希望那个对象改变,那就要失望了。在编写程序的过程中,我们可以避免多个句柄指向同一个对象,但是一旦准备将句柄作为一个自变量或参数传递,别名问题就会自动重现。下面就是讲如何克服这个问题。
二、制作本地副本
在讲制作本地副本之前我需要强调一下,我们无须在传值和传址上纠结,如果知道他们的区别后,即可以灵活的运用,这个在实际的编程的过程中为我们带来的好处远远大于弊端。只有我们明确的需要,句柄传递后的使用过程中,不能对外面的对象产生影响,才考虑下面的方式。
对象的克隆就是我们这里要讲解的,这也是本地副本最常见的一种用途。只需要简单的使用clone()方法即可。这个方法在基础类object中定义成了protected模式,但在希望克隆的任何衍生类中,必须将其覆盖为public模式。
采用clone()方法复制对象,我们通常把这种方法叫做“简单复制”或者“浅层复制”。因为他只是复制了一个对象的表面部分。实际对象除了包含这个表面以外,还包括句柄指向的所有对象,以及那些对象又指向的其他所有对象。由此类推,这便是对象网或对象关系网。如果可以复制下所有这张网,便叫做全面复制。
三、如何实现clone()
为了使一个对象的克隆能力成功圆满,需要实现Cloneable接口。这个接口使人感觉奇怪,因为他是一个空的! interface Cloneable{}
之所以要实现这个空接口,显然不是因为准备上塑造成一个Cloneable,以及调用其他的某个方法。而是为了实现一种标记的功能。首先,可能有一个上塑造句柄指向一个基础类型,而且不知道他是否真的能克隆那个对象,在这种情况下,可用instanceof调查句柄是否确实实现克隆功能;其次,我们可能不愿意所有对象类型都能克隆,所以Object.clone()会验证一个类是否真的实现了Cloneable接口,判断类是否真的可以Clone()。
在Object.clone()正式开始操作之前,首先会检查一个类是否实现Cloneable。如果已经实现,则Object.clone()会检查原先的对象有多大,在为新对象腾出足够大的内存,将所有二进制位从原来的对象复制到新的对象,这就是“按位复制”。
注意:java对“是否等价”的测试并不对所对比对象的内部进行检查,从而核实他们的值是否相同。==和!=运算符知识简单的对比句柄内容。若句柄的地址相同,就认为句柄指向同样的对象,所以认为他们是“等价”的。所以运算符真正检测的是“由于别名问题,句柄是否指向同一个对象?”。
在克隆的过程中,第一个部分都应该调用super.clone()。这样做的目的就是希望复制整条对象链,达到深层复制的目的。试图深层复制合成对象时会遇到一个问题。必须假定成员对象中的 clone()方法也能依次对自己的句柄进行深层复制,以此类推。这使我们的操作变得复杂。为了能正常实现深层复制,必须对所有类中的代码进行控制,或者至少全面掌握深层复制中需要涉及的类,确保它们自己的深层复制能正确进行。
四、再论String类
String 类的对象被设计成“不可变”。若查阅联机文档中关于 String 类的内容,就会发现类中能够修改 String 的每个方法实际都创建和返回了一个崭新的 String 对象,新对象里包含了修改过的信息——原来的 String 是原封未动的。
由于 String 对象是不可变的,所以能够根据情况对一个特定的 String 进行多次别名处理。因为它是只读的,所以一个句柄不可能会改变一些会影响其他句柄的东西。因此,只读对象可以很好地解决别名问题。通过修改产生对象的一个崭新版本,似乎可以解决修改对象时的所有问题,就象 String 那样。但对某些操作来讲,这种方法的效率并不高。一个典型的例子便是为 String 对象覆盖的运算符“+”。为了解决这个问题,java又引入了StringBuffer(可变字符串)。无须像string对象那样,在变动的过程中,需要差生很多垃圾中间字符串对象。
相关推荐
在Java编程语言中,`clone`是一个非常重要的概念,它涉及到对象复制和对象克隆。本文将深入探讨Java中的`clone`方法,包括其工作原理、使用场景、注意事项以及一些个人实践心得。 首先,让我们理解什么是`clone`。...
本文将深入探讨Java中的引用以及对象的克隆机制,包括浅拷贝和深拷贝的区别及其应用场景。 #### 二、Java中的引用 在Java中,当使用`new`关键字创建一个对象时,实际上创建的是一个指向该对象的引用。例如,以下...
在Java中,`clone`方法提供了一种快速复制对象的方式。它属于`Object`类的一部分,但需要显式地在子类中声明并实现`Cloneable`接口才能正常使用。本文将详细介绍`clone`的基本概念、工作原理以及如何实现浅拷贝和深...
在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在对象复制和克隆方面。这个小例子将帮助初学者理解如何在Java中使用`clone()`来创建对象的副本。让我们深入探讨`clone()`方法以及它在实际编程中的...
在Java编程语言中,`Cloneable`接口和`clone()`方法是两个重要的概念,它们用于对象复制。在本文中,我们将深入探讨Java中的浅克隆(shallow clone)和深克隆(deep clone),并结合测试代码进行分析。 首先,让...
C# 中 Clone 一个对象的值到另一个对象案例 C# 中 Clone 一个对象的值到另一个对象案例是一种常见的编程需求。在这篇文章中,我们将学习如何使用 C# 中的 Clone 方法来复制一个对象的值到另一个对象。 什么是 ...
在Java编程语言中,克隆(Clone)机制是一种创建对象副本的方法,它允许开发者创建一个已有对象的新实例,这个新实例与原对象具有相同的属性值,但却是两个独立的对象,彼此的操作不会互相影响。克隆机制在某些情况...
在Java编程中,对象复制是一项常见的任务,特别是在处理模型(Model)和视图对象(VO)时。模型对象通常用于封装业务数据,而视图对象则用于展示这些数据。值复制,即对象属性值的复制,是保持数据一致性和简化代码...
Java中的`clone`方法是Java语言提供的一种复制对象的方式,它允许创建一个对象的副本,这个副本与原对象具有相同的属性值,但它们是两个独立的对象,修改副本不会影响原对象。`clone`方法存在于Java的`java.lang....
在Java中,克隆分为两种类型:浅克隆(Shallow Clone)和深克隆(Deep Clone)。浅克隆创建的新对象只复制了原对象的引用,这意味着如果原对象中包含可变的引用类型,如数组或复杂的数据结构,那么新对象和原对象会...
JAVA对象clone方法代码实例解析 JAVA对象clone方法是JAVA编程语言中的一种复制对象的方法,通过实现Cloneable接口和重写clone方法,可以实现对象的浅复制或深复制。在本文中,我们将通过示例代码详细介绍JAVA对象...
在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在处理对象复制和数据持久化时。本示例将深入探讨`clone()`方法的工作原理、使用场景以及如何在实际编程中应用。首先,我们来理解一下`clone()`方法的...
-java 创建对象的四种方法是指在 Java 中创建对象的不同方式,它们分别是使用 new 语句创建对象、使用反射机制创建对象、使用 clone() 方法创建对象和使用反序列化机制创建对象。 - 使用 new 语句创建对象是 Java ...
首先,我们要理解Java中的对象复制有浅拷贝和深拷贝两种方式。浅拷贝只复制对象本身,不复制引用的对象;深拷贝不仅复制对象,还复制对象中引用的对象。在描述中提到的方法,很可能是关于深拷贝的实现。 在Java中,...
本文将深入探讨Java中的对象克隆,包括其原理、实现方式以及注意事项。 一、对象克隆的原理 在Java中,对象克隆可以通过实现`Cloneable`接口并覆盖`Object`类中的`clone()`方法来完成。`Cloneable`接口本身不包含...
Java中的clone方法详解_动力节点Java学院,动力节点口口相传的Java黄埔军校
Java中的对象复制与克隆是程序开发中常见的需求,主要用于创建一个对象的副本,而不会影响原始对象的状态。这里主要讨论两种类型的对象拷贝:浅拷贝和深拷贝。 浅拷贝,也称为表面拷贝,是创建一个新的对象,然后将...
详细的描述了Java中 clone方法使用
Java中创建对象主要有四种显式的方式,分别是使用new关键字、反射机制、克隆克隆方法以及反序列化手段。每种方法都有其特定的使用场景和特点,以下是这些方法的详细说明: 1. 使用new关键字创建对象 这是最常见也是...