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< ...
随机推荐
- DataFrame编程模型初谈与Spark SQL
Spark SQL在Spark内核基础上提供了对结构化数据的处理,在Spark1.3版本中,Spark SQL不仅可以作为分布式的SQL查询引擎,还引入了新的DataFrame编程模型. 在Spark ...
- 【原】cocos2d-x开发笔记:获取Sprite上某一个点的透明度,制作不规则按钮
本篇文章主要讲一下怎么做一个不规则的按钮,比如如下图的八卦,点击绿色和点击红色部分,需要执行不同的事件
- [ USACO 2018 OPEN ] Out of Sorts (Gold)
\(\\\) \(Description\) 运行以下代码对一长为\(N\)的数列\(A\)排序,不保证数列元素互异: cnt = 0 sorted = false while (not sorted ...
- 二次封装OKHttp网络框架(1)
1. 框架功能简介:暂时只有get.post两个请求 2. 请求的主要流程和区别: 2.1 get请求: (1)创建请求客户的 OkHttpClient对象 (2)创建请求构建器 Request.Bu ...
- asp.net——根据时间,显示内容
题目: 在VS 2010中建立一个网站,命名为Lab5_1,建立时注意项目文件夹的存放位置.根据当前时间,在页面上显示早上好或下午好或晚上好,并显示相应的不同图片. 体验: 一开始看到这个题目的时候, ...
- C# 窗体 切换、重复显示等遗留问题解决(第五天)
一.解决同一窗体多次点击重复显示BUG (1)点击弹出学校窗体 #region 弹出学校窗体 /// <summary> /// 弹出学校窗体 /// </summary> / ...
- Java我来了
七天的C#集训,第一天接触Java,觉得很多相似的地方,尝试用eclipse码了几句(有些差别,毕竟没有写C#那么流畅),总体来说觉得还不错,对自己接下来要求是,更加熟练并且牢记Java的命令,更加深 ...
- Makefile精髓篇【转】
什么是makefile?或许非常多Winodws的程序猿都不知道这个东西,由于那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序猿,makefile还是 ...
- 00 python基础知识
''' ''' print('hello world!') ''' 变量 ''' # 变量的:‘tank’,会在内存中产生一份内存地址 #变量名:相当于一个门牌号,用于与变量进行绑定 # = :用来把 ...
- 基于owncloud构建私有云储存网盘
注意事项:需要ping通外网 需要LAMP架构yum -y install httpd php php-mysql mariadb-server mariadb sqlite php-dom php- ...