java中final关键字存在的可修改情况

final实例域

可以将实例域定义为final。final实例域在定义时必须初始化,并且在后面的操作中,不能够再对它进行修改。但是final关键字只表示变量中的对象引用不会指向其他地址,所以final类型的变量是存在可修改情况的。

1. 不可修改的情况

		final String abc = "abc";
		abc = abc + "de";

在java中,这种写法是不允许的。JVM对于这几行代码是这样处理的,首先创建一个String对象abc并指向内存中的"abc",然后创建一个新的String对象abc指向内存中的"abcde"。而原来的abc就会被JVM的垃圾回收机制(GC)给回收掉了。所以,这里abc的对象引用发生了变更。如下代码可以看出:

		String abc = "abc";
		System.out.println(abc.hashCode());
		abc = abc + "de";
		System.out.println(abc.hashCode());

运行结果如下:
96354
92599395

事实上,String对象一旦创建之后就不可更改了,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程。java中String对象的值会存在于常量池中,所以不管用什么对象去引用其指向的地址是同一个,如下代码可以看出:

		String abc = "abc";
		System.out.println(abc.hashCode());
		String bcd = "abc";
		System.out.println(bcd.hashCode());

运行结果如下:
96354
96354

也就是说两个不同的对象abc和bcd指向的"abc"是同一个。所以这里也可以直接使用==比较abc和bcd的值。

2. 可修改的情况
以上可以得出结论,final关键字只是不允许变更定义变量的对象引用。所以我们只要通过不更改引用而直接修改变量的值即可。代码如下:

		final StringBuilder a = new StringBuilder().append("abc").append("de");
		System.out.println(a+":"+a.hashCode());
		a.append("fg");
		System.out.println(a+":"+a.hashCode());

运行结果如下:
abcde:1876682596
abcdefg:1876682596

我们可以发现,变量a的值已经被修改了,但是它的hashcode并没有发生改变。在java中StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作。
而StringBuilder和StringBuffer的区别是:StringBuilder是线程不安全的,而StringBuffer是线程安全的。
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

猜你喜欢

转载自blog.csdn.net/Piqzem/article/details/84975735