Java String相关问题

一、String 的不可变特性

String 可能是 Java 中最特殊的一个数据类型。

  • 和基本数据类型的封装类型一样,具备不可变性
  • 声明方式像基本数据类型,但其实是引用类型
  • 作为引用类型,又不一定直接放在里,有可能放在字符串池(String Pool)中;

String 的不可变特性体现在哪些方面呢?

首先,String 类是一个 final,它不能被继承

public final class String implements Serializable, Comparable<String>, CharSequence {
   
    
    ** 用来存储字符 *private final char[] value; 
	......
}

其次,它的内部真正用来存储字符的 value 数组也是一个 final 类型的,不能被修改指向

此外,String类中所有外部能调用的操作,凡是返回String对象的操作方法都是返回一个新的String实例对象

public String subString( int begin ) {
   
    
    
	......
	return (beginIndex == 0) ? this : new String(value, begin, subLen); 
}

也就是说,不管你怎么操作,最开始的String对象一定是不变的,你得到的所有String新实例都是新生成的(当然新生成的也是不可变的),而不会去修改原本的对象。

在这里插入图片描述

所以,总结一下String 的不可变特性主要体现在两个方面:

  • 不可变的类(包括数据成员)
  • 不可变的实例对象

二、String 为什么要设计成不可变的?

  1. 使用习惯需要:
String fileName = "demo.jar"; 
String dirPath = “disk/code/";
String filePath = dirPath + fileName;

String 实例的使用,主要是对字面量的使用,更接近基本数据类型。

  1. 计算需要:加快字符串处理速度
public final class String implements Serializable, Comparable<String>, CharSequence {
   
    
    ** 缓存字符串的hash code *private int hash;
	......
	public int hashCode() {
   
    
    
		int h = hash;
		if (h == 0 && value.length > 0) {
   
    
     
			char val[] = value;
			for (int i = 0; i < value.length; i++)	{
   
    
    
				h =(31 * h + val[i]; // 将每一位的特征在末位不断累加
			}
			hash = h; 
		}
		return h; 
	}
}

我们发现 Stringhash 值是计算出来以后缓存在内部的,假如 Stringvalue 数组可变,那么可能每次改变 value 数组都要重新计算 hash 值,效率降低。

由于String是不可变的,保证了hashcode的唯一性,于是在创建对象时其hashcode就可以放心的缓存了,不需要重新计算。这也就是Map喜欢将String作为Key的原因,处理速度要快过其它的键对象。所以HashMap中的键往往都使用String

  1. 线程安全需要:

例如以下代码:

public StringBuilder addSuffix(StringBuilder builder) {
   
    
     
	return builder.append(.jar");
}

// 这里的 StringBuilder 不具备线程可见性,且 StringBuilder 是可变类 
String fileNameBuilder = new StringBuilder("demo"); 
String fullFileName = "";

fullFileName = addSuffix(fileNameBuilder).toString(); // 并发执行 
fullFileName = addSuffix(fileNameBuilder).toString(); // 并发执行

在不加锁的前提下,假设有两个线程同时调用 addSuffix 方法并将结果赋值给 fullFileName ,那么 fullFileName 结果是 demo.jar 还是 demo.jar.jar?显然这无法得到线程安全的保证。

如果换成是 String,就能保证绝对线程安全,结果一定是 demo.jar

public String addSuffix(String str) {
   
    
     
	return str + ".jar" ;
}

String fileName = "demo"; 
String fullFileName = ""

猜你喜欢

转载自blog.csdn.net/lyabc123456/article/details/134845351
今日推荐