java对象赋值,就是通过“=”,完成两个对象数据信息的传递。主要分为“基本类型”赋值和“引用类型”赋值。
- 基本类型赋值
当赋值对象为“基本数据类型”时,在通过“=”符号进行赋值操作时,是将具体的数据值直接传递的。如
int a = 1;
int b = a;
a = 2;
此时,a的值为2;b的值为1。
- 引用类型赋值
基本数据类类型存的是数值本身,而引用类型变量在内存放的是数据的引用,并不是数据的本身,引用类型变量是以间接方式去获取数据。引用类型变量都属于对象类型,如:数组、类、字符串等都属于引用类型变量。所以,引用类型变量里面存放的是数据的地址。
在这里主要以List为分析对象进行操作。
1、问题代码
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
List<String> b = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
a.add(i + "");
// 当运行到第5个时,将a赋值给b
if (i == 4) {
b = a;
}
}
//输出a、b结果
System.out.println("a:");
int sizeA = a.size();
for (int i = 0; i < sizeA; i++) {
System.out.print(a.get(i)+" ");
}
System.out.println("\n"+"b:");
int sizeB = b.size();
for (int i = 0; i < sizeB; i++) {
System.out.print(b.get(i)+" ");
}
}
输出结果:
a:
0 1 2 3 4 5 6 7 8 9
b:
0 1 2 3 4 5 6 7 8 9
按照代码表面意思:将List a的前五项,赋值给List b。但是List b的内容却是和List a的内容相同。
主要原因是因为代码
if (i == 4) {
b = a;
}
该操作,是将a的“指针地址”传给了b。
2、解决方案
方法一:利用 集合自带的构造方法方法 List<String> b = new ArrayList<String>(a)方法进行数据值传输
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
List<String> b = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
a.add(i + "");
// 当运行到第5个时,将a赋值给b
if (i == 4) {
b= new ArrayList<String>(a);
}
}
//输出a、b结果
System.out.println("a:");
int sizeA = a.size();
for (int i = 0; i < sizeA; i++) {
System.out.print(a.get(i)+" ");
}
System.out.println("\n"+"b:");
int sizeB = b.size();
for (int i = 0; i < sizeB; i++) {
System.out.print(b.get(i)+" ");
}
}
输出结果为:
a:
0 1 2 3 4 5 6 7 8 9
b:
0 1 2 3 4
方法二:利用克隆的方法进行赋值 ArrayList<String> b = (ArrayList<String>) a.clone()
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
ArrayList<String> b = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
a.add(i + "");
// 当运行到第5个时,将a赋值给b
if (i == 4) {
b = (ArrayList<String>) a.clone();
}
}
//输出a、b结果
System.out.println("a:");
int sizeA = a.size();
for (int i = 0; i < sizeA; i++) {
System.out.print(a.get(i)+" ");
}
System.out.println("\n"+"b:");
int sizeB = b.size();
for (int i = 0; i < sizeB; i++) {
System.out.print(b.get(i)+" ");
}
}
输出结果为:
a:
0 1 2 3 4 5 6 7 8 9
b:
0 1 2 3 4
方法三:利用List中的addAll()方法
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
ArrayList<String> b = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
a.add(i + "");
// 当运行到第5个时,将a赋值给b
if (i == 4) {
b.addAll(a);
}
}
//输出a、b结果
System.out.println("a:");
int sizeA = a.size();
for (int i = 0; i < sizeA; i++) {
System.out.print(a.get(i)+" ");
}
System.out.println("\n"+"b:");
int sizeB = b.size();
for (int i = 0; i < sizeB; i++) {
System.out.print(b.get(i)+" ");
}
}
输出结果为:
a:
0 1 2 3 4 5 6 7 8 9
b:
0 1 2 3 4
以上三个方法(浅克隆)只限于,将“赋值对象”的“当前层数据”进行了数据赋值传输,对于“赋值对象”的深一层数据无法赋值传输(深度克隆:利用浅克隆方法,深入对象内部操作)。如代码
TestObj对象定义信息:
public class TestObj {
private Integer a;
private List<String> bList;
public Integer getA() {
return a;
}
public void setA(Integer a) {
this.a = a;
}
public List<String> getbList() {
return bList;
}
public void setbList(List<String> bList) {
this.bList = bList;
}
}
功能实现代码:
public static void main(String[] args) {
ArrayList<TestObj> a = new ArrayList<TestObj>();
ArrayList<TestObj> b = new ArrayList<TestObj>();
// 对List a赋值
for (int i = 0; i < 10; i++) {
TestObj to = new TestObj();
to.setA(i);
List<String> bList = new ArrayList<String>();
bList.add(i + "");
to.setbList(bList);
a.add(to);
}
// 将List a 赋值给List b 操作
// b = new ArrayList<TestObj>(a);
// b.addAll(a);
b = (ArrayList<TestObj>) a.clone();
//展示现在的a、b内容值
int sizeBB = b.size();
for (int i = 0; i < sizeBB; i++) {
System.out.println("原来a:" + toJsonString(a.get(i)));
}
System.out.println();
for (int i = 0; i < sizeBB; i++) {
System.out.println("原来b:" + toJsonString(b.get(i)));
}
//对List a进行修改
int sizeA = a.size();
for (int i = 0; i < sizeA; i++) {
TestObj testObj = a.get(0);
testObj.setA(1);
List<String> bList = new ArrayList<String>();
bList.add(1 + "");
testObj.setbList(bList);
a.add(testObj);
a.remove(0);
}
//展示修改后的a、b内容值
System.out.println();
int sizeB = b.size();
for (int i = 0; i < sizeB; i++) {
System.out.println("现在b:" + toJsonString(b.get(i)) + "+");
}
System.out.println();
for (int i = 0; i < sizeB; i++) {
System.out.println("现在a:" + toJsonString(a.get(i)) + "+");
}
}
/**
* 将object转换成字符串
*
* @param obj
* @return
*/
public static String toJsonString(Object obj) {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
return gson.toJson(obj);
}
输出结果为:
原来a:{"a":0,"bList":["0"]}
原来a:{"a":1,"bList":["1"]}
原来a:{"a":2,"bList":["2"]}
原来a:{"a":3,"bList":["3"]}
原来a:{"a":4,"bList":["4"]}
原来a:{"a":5,"bList":["5"]}
原来a:{"a":6,"bList":["6"]}
原来a:{"a":7,"bList":["7"]}
原来a:{"a":8,"bList":["8"]}
原来a:{"a":9,"bList":["9"]}
原来b:{"a":0,"bList":["0"]}
原来b:{"a":1,"bList":["1"]}
原来b:{"a":2,"bList":["2"]}
原来b:{"a":3,"bList":["3"]}
原来b:{"a":4,"bList":["4"]}
原来b:{"a":5,"bList":["5"]}
原来b:{"a":6,"bList":["6"]}
原来b:{"a":7,"bList":["7"]}
原来b:{"a":8,"bList":["8"]}
原来b:{"a":9,"bList":["9"]}
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在b:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
现在a:{"a":1,"bList":["1"]}+
- 例子介绍分析
public void test() throws Exception {
System.out.println("\nint:=================");
int i = 2;
System.out.println("before:" + i);
change1(i);
System.out.println("after:" + i);
System.out.println("\nInteger:=================");
Integer integer = 3;
System.out.println("before:" + integer);
change2(integer);
System.out.println("after:" + integer);
System.out.println("\nString:=================");
String str = new String("xxx");
System.out.println("before:" + str);
change3(str);
System.out.println("after:" + str);
System.out.println("\nString[]:=================");
String[] array = new String[]{"a", "b", "c"};
System.out.println("before:" + array[0]);
change4(array);
System.out.println("after:" + array[0]);
System.out.println("\nBook:=================");
Book book = new Book("book1");
System.out.println("before:" + book.name);
change5(book);
System.out.println("after:" + book.name);
System.out.println("\nint[]:=================");
int[] int_array = new int[]{1, 2, 3};
System.out.println("before:" + int_array[0]);
change6(int_array);
System.out.println("after:" + int_array[0]);
}
public void change1(int i) {
i = 4;
}
public void change2(Integer integer) {
integer = (Integer) 8;
}
public void change3(String str) {
str = new String("yyy");
}
private void change4(String[] array) {
array[0] = "A";
}
private void change5(Book book) {
book.name = "book2";
}
private void change6(int[] int_array) {
int_array[0] = 10;
}
private class Book {
public String name;
Book(String name) {
this.name = name;
}
}
输出结果:
int:=================
before:2
after:2
Integer:=================
before:3
after:3
String:=================
before:xxx
after:xxx
String[]:=================
before:a
after:A
Book:=================
before:book1
after:book2
int[]:=================
before:1
after:10
以上例子分析:
1、java 中 Integer 传参方式的问题,不是说Integer是引用传递么?但为什么不会改变it
Java本身都是值传递式的调用,对于对象传递的是地址值。给地址值重新赋值等于重新指向,不会影响外层。
而且这里Integer对象也有特殊性。其实现上可能类似
class Integer{
final int value; //一旦赋值,就不能改变。
}
2、String和Integer传递给方法时到底是不是传递引用?
http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html
When the argument is of reference type, pass-by-value means that the method cannot change the object reference, but can invoke the object's methods and modify the accessible variables within the object.
当参数是引用类型时,你能通过调用该引用所指向的对象本身的方法来改变对象自身,但是,你并不能改变该引用。(你改变的只能是引用所指向的对象,而不是引用。所以,仍然是值传递。)
3、java值传递还是引用传递
不管传的是什么,传过去的都只是一个副本而已,这个副本作为方法的局部变量保存在栈中。
如果传的是基本数据类型,修改这个值并不会影响作为参数传进来的那个变量,因为修改的是方法的局部变量,是一个副本。
如果传的是一个对象的引用,也是一样的,也是一个副本,但是这个副本和作为参数传进来的那个引用指向的是内存中的同一个对象,所以通过这个副本也可以操作那个对象。但是如果修改这个引用本身,比如让它指向内存中的另外一个对象,原来作为参数传进来的那个引用不会受到影响。
因此,说值传递或引用传递都无所谓,但是说值传递更适合一些,这个值可以是引用也可以是基本数据类型。