转载请注明出处: 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. UIPickerView的应用

    UIPickerView 是一个选择器控件, 它可以生成单列的选择器,也可生成多列的选择器.UIPickerView 直接继承了 UIView ,没有继承 UIControl ,因此,它不能像 UIC ...

  2. Android开发初体验

    本文通过开发一个应用来学习Android基本概念及构成应用的UI组件. 开发的应用名叫GeoQuiz,它能给出一道道地理知识问题.用户点击true或false按钮回答问题,应用即时做出反馈 第一步请先 ...

  3. html5——背景

    背景大小 background-size: % %;//宽 高 background-size: 100px 100px;//宽 高 background-size: cover;//覆盖,图片会完全 ...

  4. SQLServer bigint 转 int带符号转换函数(原创)

    有一个需求是要在一个云监控的状态值中存储多个状态(包括可同时存在的各种异常.警告状态)使用了位运算机制在一个int型中存储. 现在监控日志数据量非常大(亿级别)需要对数据按每小时.每天进行聚合,供在线 ...

  5. Matrix computations in C

    meschach配置使用 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !im ...

  6. eclipse中代码整体左右移动的方法

    1.向左:将要移动的代码选中,然后按TAB键2.向右:将要移动的代码选中,然后按shift+tab键 kettas:  2009-8-21

  7. (转) 分布式文件存储FastDFS(一)初识FastDFS

    http://blog.csdn.net/xingjiarong/article/details/50559849 一.FastDFS简介 FastDFS是一款开源的.分布式文件系统(Distribu ...

  8. CSS 之自定义滚动条样式

    ::-webkit-scrollbar {/*滚动条整体样式*/ width: 5px; /*高宽分别对应横竖滚动条的尺寸*/ height: 1px; } ::-webkit-scrollbar-t ...

  9. Origin C调用NAG库

    NAG(Numerical Algorithms Group, www.nag.com)库是一个无与伦比的算法库,它提供的算法可靠.轻便.严谨,覆盖了数学与统计方方面面.最大的缺点就是:它是一个收费的 ...

  10. 远程连接阿里云服务器ping不通ip解决方案

    搭建了阿里云服务器,发现本地ping不通,查看半天才发现,原来是在阿里云上的安全组少了些东西.  在出入方向上新建一个安全组,就可以搞定了.