• java基础学习----String


    旨在从内存方面看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方法)

    image

    这里主要看下运行时常量池,在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)

    image(问题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的总结

  • 相关阅读:
    问题:Controller中Response的用法
    C#中字符串前缀@和$
    C#中Viewbag和ViewData的区别
    C#中Session和Cache的区别
    try catch捕获异常
    C#开发中,添加错误日志功能,并自定义错误页面
    数据库索引中,聚集索引和非聚集索引有何区别?
    String和StringBuilder的区别?
    C#函数,引用类型作为值参数,改变参数值后,形参也会改变.重新给实参赋值后,形参则不会改变.
    jQuery操作radio选中和取值
  • 原文地址:https://www.cnblogs.com/qinghua0310/p/5309394.html
Copyright © 2020-2023  润新知