欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

可变类和不可变类用final修饰时的赋值问题

程序员文章站 2022-07-14 11:43:02
...

结论:

1.可变类用final修饰,只要不改变引用,改变值还是可以的,可变类传递的时候是引用传递

2.不可变类用final修饰,值和引用都不能改变,不可变类传递的时候是值传递

举例:

以可变类StringBuilder和不可变类String为例

实体类,包含四种成员变量(其实我只用到了两个)

package test_of_class;

public class TestClass {
	
	//注意,不能为final域设置set方法,而且必须在构造函数中为final成员变量进行初始化

	//final可变类
	private final StringBuilder finalStringBuilder1;
	//可变类
	private StringBuilder stringBuilder2;
	//final不可变类
	private final String finalString1;
	//不可变类
	private String string2;
	
        //构造方法
	public TestClass(StringBuilder stringBuilder111,String string111) {
		finalStringBuilder1=stringBuilder111;
		finalString1=string111;
	}

	//get,set方法
	public StringBuilder getStringBuilder2() {
		return stringBuilder2;
	}
	public void setStringBuilder2(StringBuilder stringBuilder2) {
		this.stringBuilder2 = stringBuilder2;
	}
	public String getString2() {
		return string2;
	}
	public void setString2(String string2) {
		this.string2 = string2;
	}
	public StringBuilder getFinalStringBuilder1() {
		return finalStringBuilder1;
	}
	public String getFinalString1() {
		return finalString1;
	}
	
	//toString方法,如果不重写,调用的时候打印的是对象的地址,比如[email protected]
	@Override
	public String toString() {
		return "TestClass [finalStringBuilder1=" + finalStringBuilder1 + ", stringBuilder2=" + stringBuilder2
				+ ", finalString1=" + finalString1 + ", string2=" + string2 + "]";
	}
}

下面是测试类,需要注意的是两次打印实体类的toString时,两个final修饰的成员变量的值是否有变化

package test_of_class;

public class TestClassMain {

	public static void main(String[] args) {
		TestClass testClass=new TestClass(new StringBuilder("stringBuilder111"), "string111");
		//打印结果: TestClass [finalStringBuilder1=stringBuilder111, stringBuilder2=null, finalString1=string111, string2=null]
		System.out.println(testClass.toString());
		
		//1.StringBuilder是可变类(虽然在StringBuilder中有final修饰)
		//在TestClass中有final修饰,但是由于是可变类,因此只要不改变引用,改变值还是可以的,可变类传递的时候是引用传递
		StringBuilder finalStringBuilder1=testClass.getFinalStringBuilder1().append("fff");
		//打印结果: true,证明是引用传递
		System.out.println(finalStringBuilder1==testClass.getFinalStringBuilder1());
		
		//2.String是不可变类,有final修饰
		//在TestClass中有final修饰,而且还是不可变类,因此值和引用都不能改变,不可变类传递的时候是值传递
		String finalString1=testClass.getFinalString1()+"fff";
		//打印结果: TestClass [finalStringBuilder1=stringBuilder111fff, stringBuilder2=null, finalString1=string111, string2=null]
		System.out.println(testClass);
		//打印结果: false,证明是值传递
		System.out.println(finalString1==testClass.getFinalString1());
	}
}

分析

可变类和不可变类用final修饰时的赋值问题

先调用了构造器,为两个final变量初始化(必须在创建对象的时候为final变量赋值),赋值如下

TestClass testClass=new TestClass(new StringBuilder("stringBuilder111"), "string111");

可以看到第一次打印结果是符合上面的赋值的

由于final变量不能生成set方法,因此试图修改两者的值的时候只能通过get方法,看看是否能够成功,修改方式如下

//尝试修改final修饰的StringBuilder类型变量
StringBuilder finalStringBuilder1=testClass.getFinalStringBuilder1().append("fff");	
		
//尝试修改final修饰的String类型的变量
String finalString1=testClass.getFinalString1()+"fff";

由结果分析,只有StringBuilder类型的变量的值变化了

原因是

1.append()方法是更改器方法,是能够修改原对象的,同时,getFinalStringBuilder1()方法将这个StringBuilder对象的地址赋值给了finalStringBuilder1,这是引用传递,两者一起拼接了"fff"

final修饰的可变类,可改值,不能改引用

(想改引用,没有set方法改不了)

注意:<<java核心技术>>一书中曾提到,最好不要编写返回引用可变对象的访问器方法(get方法就是访问器方法),因为这个可变对象的值是能够被修改的,这样就破坏了封装性

2.String是不可变类,该类中没有更改器方法,就是说没有修改原来对象数据的途径,因此在尝试修改string值的时候,是值传递,传递过来的是值,而不是引用,main中的finalString1对象指向了新字符串的同时,testClass中的finalString1是没有被修改的

final修饰的不可变类,值和引用都不能改

 

补充:基本数据类型的包装类和String都是不可变类

 

参考:<<java 核心技术 卷Ⅰ>>