Java 字符串限制不能有非常规符号 java数组字符串不可能溢出_字符串

高效的使用字符串,可以提升系统的整体性能。
从以下方面入手学习:String对象的实现、特性、实际使用中的优化

面试题:以3种方式创建对象,两两比较是否相等
	
	
一、实现方式
	
1、java6及之前版本
	成员变量:4个,char[]数组、offset偏移量、count字符数量、hash哈希值
	优点,通过offer + count 定位 char[]数组。高效、快速共享数组对象、节约内存
	缺点,可能导致内存泄漏
2、java7、java8
	成员变量:2个,char[]数组、hash哈希值
	优点,1、减少2个变量,占用内存减少。2、String.substring()不共享char[]数组,避免该方法导致的内存泄漏
	解决,jdk6及之前版本中,内存泄漏的问题
3、java9及之后版本
	成员变量:3个,byte[]数组、hash哈希值、coder编码格式
		coder用于判断字符串长度,如length/indexOf()。coder=0(Latin-1 单字节编码)/1(utf-16)
	解决,jdk8及之前版本中内存空间浪费问题。char占2个字节/16位,若存储1个字节的数据很浪费。jdk9采用1个字节/8位byte数组存放,节约内存空间。
	

二、特性,不可变
String对象的不可变性(一旦创建成功,则不能改变),表现如下:
	1、final class String ,final修饰类 表示类不可被继承
	2、private final char value[],final+private 表示 对象不能更改
这样做的好处?
	1、安全,防止恶意修改
	2、hash属性值不变,保证唯一性,因此HashMap才能实现key-value的缓存功能
	3、实现字符串常量池,节约内存
		String str="abc"。
			创建字符串对象时,jvm判断字符串常量中包含该对象吗?包含,则返回该对象引用;不包含,则在字符串常量池中创建该对象,并返回对象引用。防止重复创建,节约内存。
		String str= new String("abc") 
			编译类文件时,“abc”常量字符串被放入常量结构
			类加载时,常量池中创建“abc”
			调用new时,jvm命令调用String的构造函数,同时引用常量池中的“abc”字符串-->
			在堆内存中创建String对象-->str将引用String对象
经典反例
	问题,先 String str="hello"; 后 str="world" 为啥值改变了呢?
	答案
		== 比较两对象是否相等;equals 比较两对象值是否相等
		“hello”“world”是内存中的一块内存地址,是对象本身;而str 是指向该内存地址的引用,是对象引用
		 str="hello",创建“hello”对象,str引用指向“hello”地址;
		 str=”world“,创建“world”对象,str引用指向“world”地址

三、优化
1、字符串构建,构建超大字符串
	字符串常量拼接,会被编译器自动优化
		
		理论分析,这段代码是低效的,会生成ab、abcd、abcdef三个对象。
		实际运行发现,编译器自动优化为 String str="abcdef"。
	字符串变量拼接
		
		
		
		编译器把1000次的+,优化为 1000次new StringBuilder,降低系统性能!推荐显示使用StringBuilder。
		并发环境中,可使用StringBuffer线程安全,但涉及到锁竞争,所以性能比StringBuilder差一些。
2、对象存储,intern节省内存
Twitter发布消息状态时,需要32G内存存储地址信息,初步优化降低为20G,二次优化降低为几百M。
	原版
		
	初次优化,抽象公共字段(国家、省份、城市)
		
	二次优化,赋值使用intern方法,通过常量池使用重复的地址信息
		
	
intern介绍
	intern原理解析
		字符串常量中,常量池中创建对象
		字符串变量中,堆内存中创建对象、常量池中创建字符串对象。引用赋值到堆内存对象中,并返回堆内存对象的引用。
		如果调用intern方法,会查看字符串常量池中是否包含该字符串,若包含,则直接返回常量池中字符串的引用;若不包含,则在常量池中新增该对象,后返回引用。由于堆内存中原有的对象 没有引用指向它,将会通过垃圾回收器回收。
	String a = new String("abc").intern() 解析
		
		
		在一开始创建a变量时,会在堆内存中创建一个对象,同时会在加载类时,在常量池中创建一个 字符串对象,在调用intern方法之后,会去常量池中查找是否有等于该字符串的对象,有就返回 引用。
		在创建b字符串变量时,也会在堆中创建一个对象,此时常量池中有该字符串对象,就不再创 建。调用intern方法则会去常量池中判断是否有等于该字符串的对象,发现有等于"abc"字符串的 对象,就直接返回引用。而在堆内存中的对象,由于没有引用指向它,将会被垃圾回收。所以a 和b引用的是同一个对象。
		
	一张图总结String字符串的创建分配内存地址的情况
		
	注意事项!常量池中不宜放太多数据
		结合实际场景。常量池的实现类似于HashTable的实现方式,存储数据越多,遍历的时间复杂度会增加。
	
3、字符串分割
谨慎使用split(),建议使用 indexOf()替代。
split()使用正则表达式实现分割功能,因此性能非常不稳定,使用不当会引发“回溯”问题,导致cpu高居不下。

总结,
	高效的使用字符串,可以提升系统的整体性能。
	java版本迭代中通过修改String成员变量,避免内存泄漏问题,节约内存
	String对象的不可变性,实现了字符串常量池,复用重复的字符串对象,节约内存。应用中,借用intern特性,避免创建重复对象,进而节约内存。
	
	
千里之堤,溃于蚁穴。日常编码,更要谨小慎微。