一、Java提供两种参数传递方式:值传递和引用传递。
Java中处理8种基本数据类型用的是值传递,其他类型(包括不可变类:包装类、String)都是用的引用传递,但是不可变类的值是不能修改的。
-
形参是基本数据类型
传递数据值(值传递) -
实参是引用数据类型
传递地址值(引用传递)
特殊的类型:String、包装类等对象不可变性
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int i=1;
String str="hello"; //放在常量池中,String类型是常量,不可变。调用change的修改实际上是开辟新的空间
Integer num=200; //包装类在堆中,但是由于不可变性,调用change的修改也是开辟新的内存空间
int[] arr={1,2,3,4,5};
MyData myData=new MyData();
change(i,str,num,arr,myData);
System.out.println("i= "+i);
System.out.println("str= "+str);
System.out.println("num= "+num);
System.out.println("arr= "+ Arrays.toString(arr));
System.out.println("my.a= "+myData.a);
}
public static void change(int j, String s, Integer n, int[] a, MyData m){
j+=1;
s+="world";
n+=1;
a[0]+=1;
m.a+=1;
}
}
class MyData{
int a=10;
}
运行结果:
i= 1
str= hello
num= 200
arr= [2, 2, 3, 4, 5]
my.a= 11
二、创建不可变类的基本原则:
- 类中所有成员变量被private所修饰
- 类中没有写或者修改成员变量的方法,例如setXXX,只提供构造函数,一次生成,永不改变
- 确保类中所有方法不会被子类覆盖,可以通过把类定义为final或者把类中的方法定义为final来达成这个目的
- 如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量时,需要通过clone方法来确保类的不可变性。
- 如果有必要,可使用覆盖Object类的equals()方法和hashCode()方法。在equals()方法中,根据对象的属性值来比较两个对象是否相等,并且保证用equals()方法判断为相等的两个对象的hashCode()方法的返回值也相等,这可以保证这些对象能被正确地放到HashMap或者HashSet集合中。
此外,由于类的不可变性,在创建对象时就需要初始化所有成员变量,因此最好提供一个带参数的构造函数来初始化这些成员变量。
不可变类具有使用简单、线程安全、节省内存等优点。
缺点:不可变类的对象会因为值得不同而产生新的对象,从而导致无法预料的问题