Java基础:String不可变性和final修饰
来源:互联网 发布:mac用什么画流程图 编辑:程序博客网 时间:2024/05/20 20:17
转载请注明出处: jiq•钦's technical Blog - 季义钦
String的不可变性
Java规定String是不可变的(immutable),其实这个不可变具备两层含义:
1 内容不可变
任何看起来修改它们的操作,实际上都是重新new出一个对象。
String s = new String("111");String newS = s;newS = "dsfsd";System.out.println(s); //111
如果不能做到内容不可变,在两个引用同时指向一个内存的时候,修改其中一个也会影响到另外一个。
2 实现方式不可变
使用String类型变量时,其不能表现出其它行为,这就是为什么String类需要用final关键字来进行修饰的原因,设想一下String不用final修饰,则其可以被继承并重写方法:
/** * 模拟非final的String * @author jiyiqin * */class MyString{ public char value[] = new char[10]; MyStringtoLowerCase(MyString s) { System.out.println("将s转换为小写,但不改变原有s"); char newValue[] = new char[s.value.length]; for(int i = 0; i < s.value.length; i++) newValue[i]= LowerUtils.Lower(s.value[i]); MyStringnewString = newMyString(); newString.value = newValue; return newString; }} /** * 继承MyString,将其toLowerCase重写 * @author jiyiqin * */class OverrideString extends MyString{ MyStringtoLowerCase(MyString s) { System.out.println("直接修改传递进来的s的内存,将s转换为小写"); for(int i = 0; i < s.value.length; i++) s.value[i] = LowerUtils.Lower(s.value[i]); return s; }} public classFinalStringTest { /** * 测试函数,java设计String是不可变的 * 所以必须将String修饰为final,否则其 * 一旦被继承,类似下面这种调用时,若传递 * 进来的参数是其被继承的子类,调用的就是 * 被重写的方法,这个重写的方法可能会破坏 * String的不可变特性。 * @param s * @return */ static MyStringLowerCusString(MyString s)//多态 { return s.toLowerCase(s); } public static void main(String[] args) { OverrideStringss = newOverrideString(); LowerCusString(ss);//传入重写后的字符串类 LowerUtils.testFinalClass(); }}
可以看到LowerCusString方法想要的是MyString对象,但是其子类可以传递进来使用,调用之后发现传递进来的对象s的内容被修改了,表现出和父类不同的行为!!!
同样地,应用程序可以编写新的String类,修改hasCode方法,让内容相同的String对象返回的hashCode不同,这样HashMap在使用String类型变量作为Key的时候,发现相同内容的Key竟然哈希到不同的位置。
除了实现方法不可修改这个原因,将String修饰为final还有一个好处就是效率。
String其他特性
除了上面讲的不可变性,String还其具备以下特性:
特性1:编译时和运行时区别
u 编译时能确定的String对象都放入常量池
u 运行时才能确定或者new出的String对象都放入堆
特性2:hasCode唯一性
两个内容相同的String对象hashCode返回值一定相同
下面通过一个例子总结一下这两个特性:
final String tmp = "ji"; //常量池、编译时确定String tmp2 = "ji"; //常量池、编译时确定 String s1 = "jiyiqin"; //常量池、编译时确定 String s2 = "jiyiqin"; //常量池、编译时确定String s3 = "ji" + "yiqin"; //常量池、编译时确定String s4 = tmp + "yiqin"; //常量池、编译时确定(final一旦初始化就不可变) String s5 = tmp2 + "yiqin";//堆、运行时确定String s6 = new String("jiyiqin");//堆、运行时确定 System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println(s3.hashCode());System.out.println(s4.hashCode());System.out.println(s5.hashCode());System.out.println(s6.hashCode()); //全部相同 System.out.println(s1 == s2); //true,指向常量池中相同内存System.out.println(s1 == s3); //true,指向常量池中相同内存System.out.println(s1 == s4); //true,指向常量池中相同内存System.out.println(s1 == s5); //false,一个指向堆一个指向常量池System.out.println(s1 == s6); //false,一个指向堆一个指向常量池System.out.println(s5 == s6); //false,指向堆中不同内存区域
Double、Long、Integer
对于String的不可变性(包括内容不可变和实现方式不可变),以及hashCode唯一性,Double、Long、Integer也是一样的。不同的是它们没有运行时和编译时的区别,都是在堆上分配内存。
- Java基础:String不可变性和final修饰
- 浅谈java中String类的不可变性(immutability)和final关键字修饰
- 图解Java String不可变性
- Java中String类型的不可变性和驻留池
- java之String对象的不可变性
- JAVA String 不可变性 / Hibernate_Validator学习
- String 的相等性和不可变性
- String的不可变性
- String的不可变性
- String的不可变性
- String的不可变性
- Java中String的不可变性和创建String的内存变化
- java基础入门-你不知道的string-不可改变性与编译器优化
- Android中的java基础(三)——String的不可变性
- Java中的String的 方法归类 及其 不可变性
- 深入理解java String 对象的不可变性
- Java中String类不可变性的好处
- java学习笔记24——String类不可变性
- Android Activity的生命周期简单总结
- 专题二 第一道题
- LintCode_157_判断字符串是否没有重复字符
- 总结分享十大iOS开发者最喜爱的库
- #7算法实战和错误类型#
- Java基础:String不可变性和final修饰
- Linux2.6内核启动分析
- No matching provisioning profiles found: None of the valid provisioning profiles include the device
- Android6.0.1r11源代码分享
- 解决U盘挂载到linux上没有写和执行的权限
- windows下把代码托管到github
- Sql Server 三种分页方式及测试
- 禁止WebBrowser网页跳转时发出的声音
- 实现人机下三字棋