Java基础:String不可变性和final修饰
转载请注明出处: 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类须要用finalkeyword来进行修饰的原因,设想一下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,StringBuilder,StringBuffer三者的区别
结论 1-String,StringBuilder,StringBuffer 之间的区别主要是在两个方面,即运行速度和线程安全这两方面: 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:St ...
- Java基础String的方法
Java基础String的方法 字符串类型写法格式如下: 格式一: String 变量名称; 变量名称=赋值(自定义或传入的变量值); 格式二: String 变量名称=赋值(自定义或传入的变量值); ...
- Java基础 String 裸暴力算法- 五个小练习
之间的博客,承上启下: Java基础 String/StringBuff 常用操作方法复习/内存分析 Java数组直接选择排序.sort()排序 Java基础 String 算法 - 五个练 ...
- Java基础—String构造方法
Java基础--String构造方法 public String(): 创建一个空表字符串对象,不包含任何内容 public String(char[]chs): 根据字符数组的内容,来创建字符串对象 ...
- Java基础学习笔记(四) - 认识final关键字、权限修饰符和内部类
一.final关键字 为什么要使用 final 关键字? 通过继承我们知道,子类可以重写父类的成员变量和方法.final 关键字可以用于修饰父类,父类成员变量和方法,使其内容不可以被更改. 1.被修饰 ...
- Java基础-String、StringBuffer、StringBuilder
看下面这段代码: public class Main { public static void main(String[] args) { String string = ""; ...
- Java基础String类
String是一个对象 String不属于8种基本数据类型(byte, char, short, int, float, long, double, boolean),String是对象,所以其默认值 ...
- java的String类型为什么是final
(转自:http://www.cnblogs.com/ikuman/archive/2013/08/27/3284410.html) 最佳答案: 主要是为了“效率” 和 “安全性” 的缘故.若 Str ...
- java基础-String不可变的好处
一.java内部String类的实现: java 8: public final class String implements java.io.Serializable, Comparable< ...
随机推荐
- 给网站添加运行时间的JavaScript完整代码
function secondToDate(second) { if (!second) { return 0; } var time = new Array(0, 0, 0, 0, 0); if ( ...
- MySQL 多表批量更新
使用inner join 进行表更新sql 与mysql 的区别: SQL UPDATE W SET W.字段=新数据 FROM 表a W INNER JOIN 表B d ON W.wID=D.wid ...
- DB2使用收集
db2命令收集 创建带分区的表: create table table_name( )in table_space index in index_space partition by range(c ...
- [Windows Server 2008] 安装IIS7.5及FTP
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装IISII ...
- C语言保留字
数值变量相关: int float double char long short unsigned signed 储存说明符 const 用于声明常量 static用于限制变量/函数的作用范围等等 e ...
- 1.CentOS安装Redis
首要条件:安装VMware,在虚拟机中安装CentOS. 第一次接触CentOS的开发者最好是在虚拟机手动一步步进行安装,并且系统环境选择开发环境,这样可以避免后期自己要安装诸多运行库. 安装步骤: ...
- tbType和TypeList操作
tbType查询数据库后 获得一个DataTable的数据表 数据表是写在内存里面的 可以在这个项目的其他地方去访问它,由于在内存里面 所以访问速度很快 用代码获取它的哪一行的数据供使用 例如 tbB ...
- uva 1401
Neal is very curious about combinatorial problems, and now here comes a problem about words. Knowing ...
- Gym - 101611D Decoding of Varints(阅读理解题 )
Decoding of Varints 题意&思路: 首先根据红色边框部分的公式算出x,再有绿色部分得知,如果x是偶数则直接除以2,x是奇数则(x+1)/-2. PS:这题有数据会爆掉un ...
- =、==、is、id(内容)
= 赋值 == 比较值是否相等 is 比较.比较的是内存地址 id(内容) 测出内存地址