栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVASE语法零基础——String类2

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVASE语法零基础——String类2

Java系列文章目录

Write once,Runanywhere.

  如果你觉得我的文章有帮助到你,还请【关注➕点赞➕收藏】,得到你们支持就是我最大的动力!!!
  

⚡版权声明:本文由【马上回来了】原创、在CSDN首发、需要转载请联系博主。
版权声明:本文为CSDN博主「马上回来了」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

 新的知识开始喽

文章目录
  • Java系列文章目录
  • 1.String常量池
    • 1.1 创建对象的思考
    • 1.2 字符串常量池(Stringable)
    • 1.3 再谈对创建对象的思考
    • 1.4 intern方法
    • 1.5 面试题:请解释String类中两种对象实例化的区别
  • 2.字符串的不可变性
  • 3.字符串修改
  • 4. StringBuilder和StringBuffer


1.String常量池 1.1 创建对象的思考

下面创建String对象的方式相同吗?

  public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s1==s2);//true
        System.out.println(s1==s3);//false
        System.out.println(s3==s4);//false
    }

为什么s1和s2引用的是同一个对象,而s3和s4引用的不是同一个对象呢?
对于1,3.14,"hello"这种被经常使用的字面常量,为了使程序运行跟块,跟节省空间,Java为这8中数据类型和String类型提供了常量池。

1.2 字符串常量池(Stringable)

字符串常量池在JVM中是StringTable类,实际是一个固定大小HashTable(一种高效用来进行查找的数据结构,后序给大家详细介绍),不同JDK版本下字符串常量池的位置以及默认大小是不同的,其中Java8 在堆中。

1.3 再谈对创建对象的思考

此处在java8上分析
对于直接使用常量创建String类:

 public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1==s2);//true
    }

详细讲解:

直接new常量池一开始没有的对象:

public static void main(String[] args) {
        String s1 = new String("world");
        
    }


对于直接new对象:

 public static void main(String[] args) {
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s3==s4);//false
    }

1.4 intern方法

intern方法是一个native方法(native方法是指底层用C++实现的,看不到它的源代码)该方法的作用是手动将创建的String对象添加到常量池中。

 public static void main(String[] args) {
        char[] chars = {'a','b','c'};
        String s1 = new String(chars);
        //s1.intern();
        String s2 = "abc";
        System.out.println(s1==s2);//未使用intern方法 false
    }

先看这两行代码:

//字符数组转字符串
char[] chars = {'a','b','c'};
String s1 = new String(chars);


这两行代码执行的结果:

这两行代码执行的过程:

一直到到这两行代码执行结束,常量池都没有添加双引号"“引起的字符串常量,因为s1里没有”"引起的字符串。
整个代码执行完毕:

当执行intern方法时:

 public static void main(String[] args) {
        char[] chars = {'a','b','c'};
        String s1 = new String(chars);
        s1.intern();
        String s2 = "abc";
        System.out.println(s1==s2);// true
    }

 public static void main(String[] args) {
        char[] chars = {'a','b','c'};
        String s1 = new String(chars);
      //运行到这里s1不在常量池中
      //s2在常量池中
        String s2 = "abc";
        //intern检查常量池,发现常量池里有"abc",不会再将s1引用的对象放入到常量池里,因此这里结果跟没有使用intern方法的情况类似。
          s1.intern();
        System.out.println(s1==s2);// false
    }
1.5 面试题:请解释String类中两种对象实例化的区别

JDK1.8中

  1. String str = “hello”
    只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象。常量池里的对象。
  1. String str = new String(“world”)
    会开辟两块堆内存空间,字符串"world"保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值。new一个对象、常量池里new一个对象。
  1. String str = new String(new char[]{‘h’, ‘e’, ‘l’, ‘l’, ‘o’})
    先new一个char类型的数组对象,然后在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中。
2.字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:

  1. String类在设计时就是不可改变的,String类实现描述中已经说明了

    String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:
  2. String类被final修饰,表明该类不能被继承。
  3. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。

    【纠正】网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。
    这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。
    【正确】关键在于value被private修饰类外拿不到value的值,因此无法对string进行修改。

为什么 String 要涉及成不可变的?(不可变对象的好处是什么?) (选学)

  1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
  2. 不可变对象是线程安全的.
  3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中
3.字符串修改
  1. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象。比如 replace 方法:

    看下面这个代码:
public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); //并不是在原有的hello空间上接了一个world,而是产生了一个新对象输出:hello world, 
}

2.注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。效率低下的原因是因为每次对字符串拼接都会产生新的对象。
下面是String类、StringBuilder类和StringBuffer类分别执行一段代码,StringBuilder类和StringBuffer类的效率是String类的282倍。

public static void main(String[] args) {
        //String
            long start = System.currentTimeMillis();
            String s = "";
            for(int i = 0; i < 10000; ++i){
                s += i;
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);//282
            //StringBuffer
            start = System.currentTimeMillis();
            StringBuffer sbf = new StringBuffer("");
            for(int i = 0; i < 10000; ++i){
                sbf.append(i);
            }
            end = System.currentTimeMillis();
            System.out.println(end - start);//1
            //StringBuilder
            start = System.currentTimeMillis();
            StringBuilder sbd = new StringBuilder();
            for(int i = 0; i < 10000; ++i){
                sbd.append(i);
            }
            end = System.currentTimeMillis();
            System.out.println(end - start);//1
    }
4. StringBuilder和StringBuffer

再看这个代码:

public static void main(String[] args) {
String s = "hello";
s += " world";
System.out.println(s); //并不是在原有的hello空间上接了一个world,而是产生了一个新对象输出:hello world, 
}

我们看看这段代码的汇编:

我们已经知道了:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
现在用StringBuilder来还原这段汇编码:

append方法:

toString方法:

 StringBuilder s1 = new StringBuilder();
        s1.append("hello");
        s1.append("hello");
      String s = s1.toString();
        System.out.println(s);//hellohello

代码执行过程看动图:


当然也可以使用StringBuffer来实现:

  StringBuffer s1 = new StringBuffer();
        s1.append("hello");
        s1.append("world");
        String s = s1.toString();
        System.out.println(s);

使用StringBuilder与StringBuffer的区别:

面试题:

  1. String、StringBuffer、StringBuilder的区别
  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
  • StringBuffer与StringBuilder大部分功能是相似的
  • StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
  1. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
String str = new String("ab"); // 会创建多少个对象 2 
String str = new String("a") + new String("b"); // 会创建多少个对象 2 + 2 + 2(new StringBuilde)、(new toString)


今天的你看懂这里又学到了很多东西吧



  下次见喽  

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013216.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号