String常量池 享元模式
本文基于java8 内存结构图
参考:
String
String 类是由 final 修饰的类 , 不可以被改变 (继承)
java中创建字符串的方式有几种? 区别所占用的空间不同
- String abc = “haha”; 内容处于堆中中的常量池
- String str = new String(“abc”); 内容处于堆中
String 类的常用构造器:
- new String();
- new String(byte[] b); 处理 byte数组
- new String(String original); 处理原生的字符串
- new String(char[] c); 处理char类型的数组
- new String(byte[] bytes, String charsetName); 可以指定字符串输出的字符集
new String() 动作
- 构建一个实例对象
- 在堆内存中开辟另一个空间
- 返回一个对象的引用给变量名
设计模式-享元模式
- 享元模式(享元模式)也叫蝇量模式:利用共享技术有效地支持大量细粒度的对象
- 常用于系统相关开发,解决系统的性能问题。 像数据库连接池,里面都是创建好的连接对象,在这些连接对象有我们需要的则直接拿来用,避免重新创建,如果没有我们需要,则创建一个。
- 享元模式能够解决重复对象的内存浪费问题,当系统大量类似对象,需要缓冲池时。不需要总是创建对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率。
- 享元模式经典的应用场景就是池技术了,字符串恒池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式元模式是池技术的重要实现方式。
享元模式的注意事项和细节
- 在享元模式这样理解,“享”就表示共享,“元”表示对象。
- 系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化时,我们就可以考虑选用享元模式。
- 用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用HashMap/HashTable存储。
- 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率
- 享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方。
- 使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制。
- 享元模式经典的应用场景是需要缓冲池的场景,比如String常量池、数据库连接池。
String 常量池
String 常量池使用到了享元设计模式的思想,
特殊的是:String 常量池是可以扩容的
JVM 底层实际上会自动维护一个对象池(字符串对象池,对象数组),目的就是减少开销
前提条件一样是当你声明了一个变量且想要让这个变量成为一个 String 类对象的引用时,
-
若是静态赋值,String 类优先从常量池中寻找对象
若是找到,那么直接将这个对象的地址返回变量;
没找到就在常量池创建对象,然后再将这个对象的地址返回变量。
所以 String 类的静态赋值的对象地址永远在常量池中 -
若是 new 语句赋值,
使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间。除了这一缺点之外,也会对字符串共享产生问题
在 String 类中提供有方法入池操作 public String intern() ;
总结String类两种对象实例化的区别:
直接赋值: 只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用
构造方法: 会开辟两块堆内存空间,其中一块称为垃圾空间,不会自动保存在对象池中,可以使用 Intern() 方法手工入池