转载请注明出处: 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修饰的更多相关文章

  1. Java基础 -- String,StringBuilder,StringBuffer三者的区别

    结论 1-String,StringBuilder,StringBuffer 之间的区别主要是在两个方面,即运行速度和线程安全这两方面: 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:St ...

  2. Java基础String的方法

    Java基础String的方法 字符串类型写法格式如下: 格式一: String 变量名称; 变量名称=赋值(自定义或传入的变量值); 格式二: String 变量名称=赋值(自定义或传入的变量值); ...

  3. Java基础 String 裸暴力算法- 五个小练习

      之间的博客,承上启下:    Java基础 String/StringBuff 常用操作方法复习/内存分析 Java数组直接选择排序.sort()排序 Java基础 String 算法 - 五个练 ...

  4. Java基础—String构造方法

    Java基础--String构造方法 public String(): 创建一个空表字符串对象,不包含任何内容 public String(char[]chs): 根据字符数组的内容,来创建字符串对象 ...

  5. Java基础学习笔记(四) - 认识final关键字、权限修饰符和内部类

    一.final关键字 为什么要使用 final 关键字? 通过继承我们知道,子类可以重写父类的成员变量和方法.final 关键字可以用于修饰父类,父类成员变量和方法,使其内容不可以被更改. 1.被修饰 ...

  6. Java基础-String、StringBuffer、StringBuilder

    看下面这段代码: public class Main { public static void main(String[] args) { String string = ""; ...

  7. Java基础String类

    String是一个对象 String不属于8种基本数据类型(byte, char, short, int, float, long, double, boolean),String是对象,所以其默认值 ...

  8. java的String类型为什么是final

    (转自:http://www.cnblogs.com/ikuman/archive/2013/08/27/3284410.html) 最佳答案: 主要是为了“效率” 和 “安全性” 的缘故.若 Str ...

  9. java基础-String不可变的好处

    一.java内部String类的实现: java 8: public final class String implements java.io.Serializable, Comparable< ...

随机推荐

  1. Java继承体系中this的表示关系

    在继承关系下,父类中的this关键字并不总是表示父类中的变量和方法.this关键字的四种用法如前文所述,列举如下. 1) this(paras…); 访问其他的构造方法 2) this.xxx; 访问 ...

  2. Oracle 递归的写法(start with) 以及where条件作用域

    先转一个讲Oracle递归讲得非常透彻的文章: http://blog.csdn.net/weiwenhp/article/details/8218091 前言:嗯,这也是一个前人挖坑,后人来填的故事 ...

  3. webstorm进行VisualSVN配置及上传项目到项目库

    以前建站一直都是自己一个人,最近要做一个比较大的网站,寻思着利用svn在整个开发过程中会比较快,于是摸索着配置了一下. 首先,下载VisualSVN这个软件,官网链接 https://www.visu ...

  4. 微信小程序音频长度获取的问题

    小程序推荐使用wx.createInnerAudioContext()创建的innerAudioContext,我们也通过这个接口创建音频.音频的长度可以通过属性获取: 但是,给innerAudioC ...

  5. CAD保存高版本的dwg(com接口)

    主要用到函数说明: MxDrawXCustomFunction::Mx_SaveDwgEx 保存DWG文件,可以设置保存的文件版本号和密码,详细说明如下: 参数 说明 IN CString sFile ...

  6. iOS 中plist文件中配置key值冲突的现象

    iOS开发一些特殊的软件需要在项目中配置对应的key值,然而近期在项目中发现一个有意思的现象,苹果官方文档中提供的key值很多,但其实有一些彼此可能有冲突,当你同时配置了彼此冲突的key值,可能会出现 ...

  7. ListView学习(一)

    最近了解了LIstView的用法,在听了孙老师的课程后,终于对Adapter有了一定的理解,特作此文记之. ListView在App当中应用相当广泛,比如QQ好友列表.微博等等,都是某种特定的列表,所 ...

  8. 基于requests模块的cookie,session和线程池爬取

    目录 基于requests模块的cookie,session和线程池爬取 基于requests模块的cookie操作 基于requests模块的代理操作 基于multiprocessing.dummy ...

  9. Linxu基础入门

    Linux命令大全:http://man.linuxde.net/ 创建目录 使用 mkdir 命令创建目录 mkdir $HOME/testFolder 切换目录 使用 cd 命令切换目录 cd $ ...

  10. springcloud(六):给Eureka Server服务器端添加用户认证

    1.  还未完成 ,客户端有点问题,后期完善 2.