旨在从内存方面看String类的知识点:

1、为何不能被继承(final类)

2、字符拼接时,String类的内存分配问题。

3、String的intern()方法

关于String类经常出现的面试题:

问题1:

String s1 = “abc”;
String s2 = “abc”;
System.out.println(s1 == s2);

结果:true

问题2:

String s1 = new String(“abc”);
String s2 = new String(“abc”);
System.out.println(s1 == s2);

结果:false

问题3:

String s1 = “abc”;
String s2 = “a”;
String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);

结果:false

问题4:

String s1 = “abc”;
String s2 = “a” + “bc”;
System.out.println(s1 == s2);

结果:true

问题5:

String str = “abc”;
str.substring(3);
str.concat(“123″);
System.out.println(str);

结果:abc

对于以上问题的解答,需要综合jvm内存分配及规范、String的源代码

一、java虚拟机运行时数据区域:

1、程序计数器

2、java虚拟机栈

3、堆

4、方法区(the method area is logically part of the heap)

5、运行时常量池(Each run-time constant pool is allocated from the Java Virtual Machine's method area)

6、本地方法栈(类似于java虚拟机栈,主要运行native方法)

这里主要看下运行时常量池,在jvm规范(SE8)中有如下解释:

A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4).

It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time.

可以看出它常量池(constant_pool table)主要用于存储编译期产生的常量和符号引用,并且在类加载时后存放到方法区的运行时常量池中(run-time constant pool)

(问题1 和 问题2解释)

对于常量表达式,在编译器的优化下,总是在编译时已计算完毕,类加载后放在运行时常量池。(比如说 “a”+ “bc”在编译后,与“abc”是同一个,加载后在运行时常量池中)(问题4在此解答

常量表达式有如下几种:

A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

• Literals of primitive type and literals of type String                                          //常量

• Casts to primitive types and casts to type String                                           //转换类型

• The unary operators +, -, ~, and ! (but not ++ or –)                                     //单目运算符

• The multiplicative operators *, /, and %                                                        //相关运算符

• The additive operators + and -

• The shift operators <<, >>, and >>>

• The relational operators <, <=, >, and >= (but not instanceof)

• The equality operators == and != (§15.21)
• The bitwise and logical operators &, ^, and |

• The conditional-and operator && and the conditional-or operator ||

• The ternary conditional operator ? :

• Parenthesized expressions whose contained expression is a constant expression.

• Simple names that refer to constant variables

• Qualified names of the form TypeName . Identifier that refer to constant variables

问题3为两个实例对象相加,会再产生一个堆区的实例对象,然后reference s4指向这个新产生的实例对象,所以会返回false;

问题5,查看下String源码对两个方法实现

public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}

从两个方法的实现上,可以看到,他们从String对象的value属性上获取信息,并未对value进行改动,String对象调用substring方法,就相当于从自己的value上复制一小部分内容,同理,concat方法,相当String对象复制一份一样的value给别人,并在复制的部分追加字符串,将结果返回。上述两个方法都是从String对象上查询信息,而不是改动信息。所以问题5的答案是false

特别指出:

String类有一个本地方法叫intern()-----Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern.

例如:

public class TestFinal{
public static void main(String[] args) {
String a = "abc";
String b = "ab";
String c = "c";
String d = (b+c).intern();
String e = (b+"c").intern();
System.out.println(a == c);
System.out.println(a == d);
System.out.println(a == e);
}
}

另外面试中常被问到,String类能不能被继承,通过查询String类的源码发现,它是final类的,是不能被继承的

引用如下文章:

《深入理解Java虚拟机++JVM高级特性与最佳实践.pdf》

oracle下载的官方文档:《jls8》《jvms8》

部分引用网上面试关于String的总结

java基础学习----String的更多相关文章

  1. Java基础学习中一些词语和语句的使用

    在Java基础学习中,我们刚接触Java会遇到一些词和语句的使用不清的情况,不能很清楚的理解它的运行效果会是怎么样的,如:break,continue在程序中运行效果及跳转位置, 1.先来看看brea ...

  2. Java基础学习笔记(一)

    Java基础学习笔记(一) Hello World 基础代码学习 代码编写基础结构 class :类,一个类即一个java代码,形成一个class文件,写于每个代码的前端(注意无大写字母) XxxYy ...

  3. JAVA基础学习-集合三-Map、HashMap,TreeMap与常用API

    森林森 一份耕耘,一份收获 博客园 首页 新随笔 联系 管理 订阅 随笔- 397  文章- 0  评论- 78  JAVA基础学习day16--集合三-Map.HashMap,TreeMap与常用A ...

  4. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

  5. [转帖]java基础学习总结——多态(动态绑定)

    https://www.cnblogs.com/xdp-gacl/p/3644035.html 多态的概念 java基础学习总结——多态(动态绑定) 一.面向对象最核心的机制——动态绑定,也叫多态

  6. Java基础学习(4)

    Java基础学习(四) String类 特点:创建后不可再修改,看起来的修改只是创建了新的对象 常用方法 StringBuilder类 目的:解决String类频繁创建对象的问题 常用方法 特点:非线 ...

  7. java基础学习笔记五(抽象类)

    java基础学习总结——抽象类 抽象类介绍

  8. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  9. Java基础学习笔记总结

    Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...

随机推荐

  1. 文件头 MAGE_FILE_HEADER

    IMAGE_FILE_HEADER这个结构的定义如下: typedef struct _IMAGE_FILE_HEADER { 00h WORD Machine; //运行平台 02h WORD Nu ...

  2. Git之detached HEAD

    今天遇到了和CSDN上博主相同的问题,就是使用git -branch -a 发现自己处于一个零时的分支上.这篇博文写的不错,转载记录一下. 转载:http://blog.csdn.net/lili62 ...

  3. JDK TOMCAT MAVEN在myeclipse如何配置

    对于没有基础的人来说,本工具务必放在D盘根目录下. 1配置环境变量, "我的电脑-->右键-->属性" 貌似是这样吧,我电脑桌面没"我的电脑"或&q ...

  4. 离线破win2003域账号密码(更新域数据库不在默认路径的情况)

    国内网站讲了许多方法,很多也讲得不清楚.我把我尝试成功的经验跟大家分享. 方法是按照tim的文章操作,链接如下: http://pauldotcom.com/2011/11/safely-dumpin ...

  5. pydev package包中__init__.py作用

    Eclipse用pydev,新建一个pydev package时,总会自动地生成一个空的__init__.py文件. 原来在python模块的每一个包中,都有一个__init__.py文件(这个文件定 ...

  6. Qt入门(3)——信号和槽

    信号和槽用于对象间的通讯.信号/槽机制是Qt的一个中心特征并且也许是Qt与其它工具包的最不相同的部分.在图形用户界面编程中,我们经常希望一个窗口部件的一个变化被通知给另一个窗口部件.更一般地,我们希望 ...

  7. bzoj2244[SDOI2011]拦截导弹

    http://www.lydsy.com/JudgeOnline/problem.php?id=2244 第$i$个导弹看成一个三元组$(i,h_i,v_i)$ 其实就是最长上升子序列的问题. 我们分 ...

  8. linux应用程序地址布局

    Linux应用程序在内存中的布局,由高地址到低地址依次为:栈.堆.BSS段.数据段.代码段.代码段的起始地址固定为0x8048000,无论哪一个应用程序它的代码段起始地址一定是0x8048000,这里 ...

  9. 介绍一款超实用的演讲必备工具 ZoomIt

    最近在整理以前的文件时,发现躺在某个角落的一个超好的实用的小工具——ZoomIt.此工具是 SysinternalsSuite(已被MS收购)众多实用工具的一个. 相信大家在演讲时,经常需要调整屏幕文 ...

  10. lua的几个时间相关处理函数

    随手写的,项目中没用,不一定对,只作参考. --游戏时间相关函数 local gt = {} local math = math local ONE_HOUR = ONE_MINUTE * ONE_M ...