1.Java参数传递方式
网络上有很多地方都说明java的参数传递方式是值传递,虽然其最终的解释是正确的。但我认为值传递定义为java参数传递方式并不妥。
可以分成两种,便于记忆和理解:1.基本数据类型的值传递 2.对象的引用传递(传址)。
当然这里会有一个问题基本数据类型只能值传递么?如何进行引用传递?待以后慢慢研究吧
下面用直接用代码来说明一下这两种参数传递方式的区别:
// 基本数据类型是值传递,而非引用传递
public void changeInt(int params) {
params = params * 2 + 1;
}
// java对象是引用传递而非引用传递
public void changeObject(A a) {
a.a = "hello 2013!";
}
@Test
public void changeTest() {
int i = 3;
CloneTest ct = new CloneTest();
ct.changeInt(i);
A a = new A();
a.a = "style!";
ct.changeObject(a);
System.out.println(i);//结果 3
System.out.println(a.a);//结果 hello 2013!
}
2.对象的拷贝
1.浅拷贝和深拷贝
接下来的问题便是,如果我不想改变原来对象的属性内容,但又想得到对象的属性内容咋办?简言之,如何拷贝对象。
网上有很多地方都提到拷贝会产生风险,其实我们应该能理解,因为引用时无时无刻都存在的,但凡是对象,所以我们在处理拷贝时一定要非常注意。
那这里就会涉及到浅拷贝和深拷贝两个概念。
2.如何拷贝(对自定义类的对象)
在使用中我们经常要对自定义类的对象进行拷贝,因为自定义类中可以包含其他自定义类对象变量,基本数据类型变量或者jdk提供的其他类型的变量(集合,数组等等),
而我们的任务便是将这些属性值进行拷贝。
先来看一下一个最简单的拷贝对象的例子:
Modification Log:
package com.techbirds.lang;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class CloneTest {
@Test
public void cloneTest1() throws CloneNotSupportedException {
C c1 = new C();
c1.c = "c1";
C c2 = new C();
c2 = (C) c1.clone();
System.out.println(c1.c);//c1
System.out.println(c2.c);//c1
System.out.println(c1==c2);//false
System.out.println(c1.c==c2.c);//true
c2.c = "c2";
System.out.println(c1.c);//c1
System.out.println(c2.c);//c2
System.out.println(c1.c==c2.c);//false
}
}
/**
* 实现Cloneable接口,实现浅拷贝
*
*/
class C implements Cloneable {
public String c;
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
C o = null;
try {
o = (C) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
这个例子对于深浅拷贝做了很好的解释,很明显对于拷贝过来的对象中,对于属性c我们只对其进行了浅层拷贝。
那问题就抛向我们:那如何对类变量进行深层拷贝呢?其实很简单:对类变量所在类v也必须进行克隆实现。
@Test
public void testObject1() throws CloneNotSupportedException{
D d1=new D();
d1.d="12";
String[] strs1=new String[]{"1","2"};
d1.ds=strs1;
List<String> l1=new ArrayList<String>();
l1.add("12");
d1.lds=l1;
A a=new A();
a.a="a";
d1.a=a;
D d2=(D) d1.clone();
System.out.println(d1==d2);//false
System.out.println(d1.a.hashCode()+":"+d2.a.hashCode());//20324370:7578443
System.out.println(d1.ds.hashCode()+":"+d2.ds.hashCode());//31822120:31822120
}
class A implements Cloneable{
public String a;
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class D implements Cloneable{
public List<String> lds;
public String[] ds;
public String d;
A a;
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
D o = null;
try {
o = (D) super.clone();
a=(A) o.a.clone();//如果这句话没有-浅层拷贝,有-深层拷贝
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
分享到:
相关推荐
值类型和引用类型的区别: 似乎“值类型和引用类型的区别”是今年面试的流行趋势,我已然是连续三次(目前总共也就三次)面试第... C#中基本数据类型是值类型,结构也是值类型。而数组、类、接口、字符串都是引用类型。
在实际中,使用对象引用作函数参数要比使用对象指针作函数更普遍,这是因为使用对象引用作函数参数具有用对象指针作函数参数的优点,而用对象引用作函数参数将更简单,更直接。所以,在C++编程中,人们喜欢用对象...
当 Java 成长起来的时候,许多的 C 程序员开始转向学习 Java,他们发现,使用类似 SwapValue 的方法仍然不能改变通过参数传递进来的简单数据类型的值,但是如果是一个对象,则可能将其成员随意更改。于是他们觉得...
1、基本数据类型(数字、布尔值)。 2、对象引用。 一个方法不可能修改一个基本数据类型的参数。而对象引用作为参数不同了,对象参数所引用的对象状态是可以被改变的,因为方法 得到的是对象引用的...
2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 ...
== 运算符 比较两个表达式的值,看其值是否相等或数据类型是否一致。 0...n 属性 返回单个参数的实际值,该参数来自由当前运行函数的参数属性返回的参数对象。 $1...$9 属性 返回在模式匹配中找到的最近的九条记录...
== 运算符 比较两个表达式的值,看其值是否相等或数据类型是否一致。 0...n 属性 返回单个参数的实际值,该参数来自由当前运行函数的参数属性返回的参数对象。 $1...$9 属性 返回在模式匹配中找到的最近的九条记录...
== 运算符 比较两个表达式的值,看其值是否相等或数据类型是否一致。 0...n 属性 返回单个参数的实际值,该参数来自由当前运行函数的参数属性返回的参数对象。 $1...$9 属性 返回在模式匹配中找到的最近的九条记录...
2.7 抽象数据类型 2.8 对象细节 2.9 头文件形式 2.10 嵌套结构 2.11 小结 2.12 练习 第3章 隐藏实现 3.1 设置限制 3.2 C++的存取控制 3.3 友元 3.3.1 嵌套友元 3.3.2 它是纯的吗 3.4 对象布局 3.5 类 48...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 ...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、 动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...
全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...