JavaSE-14 【String】

第一章 初识 String

1.1 String介绍

String是一个封装char[]数组的对象,字符串不可变,通过下图中的底层实现可以看出:被final修饰,是常量
在这里插入图片描述

1.2 创建字符串的方式

  • 1 用字符串直接量
     String  str1 = "helloworld";
  • 2 用new关键字
    String str2 = new String("helloworld");
  • 3 用字符数组
    char[] c = {'h','e','l','l','o','w','o','r','l','d'};
    String str3 = new String(c);

在这里插入图片描述

1.3 字符串对象的内存分配

  • 1 字面量 String str1 = “abc” 内存分配
    • 1.1 当代码使用这种方式创建时,JVM首先检查该对象是否存在字符串常量池中,若在,就返回该对象的引用,否则新的字符串将在常量池中创建,这种方式可以减少同一值得字符串对象的重复创建,节约内存。

    • 1.2、如果是第一次使用字符串,java会在字符串堆中常量池创建一个对象。

    • 1.3、再次使用相同的内容时,会直接访问堆中常量池中存在的对象。

在这里插入图片描述

案例:因此如下例子,将会输出 true (String02)
在这里插入图片描述

  • 2 关键字new :String str2 = new String(“abc”) 内存分配
    • 2.1 这种方式估计大家都很熟悉,一般创建一个对象都是通过 new 关键字。String s1 = new String(“123”) 这种方式它将会创建两个 “123” 对象。
    • 2.2 首先 “123” 是一个常量字符串,因此会先在常量池中创建 “123” 字符串对象,然后在堆中再创建一个字符串对象,将 “123” 的字符数组复制到堆中新创建的对象的字符数组上,因此该方式不仅会在堆中,还会在常量池中创建 “123” 字符串对象。

在这里插入图片描述

案例:如下例子,将会输出 false,因为堆中和常量池中 “123” 字符串不是同一个对象。(String03)
在这里插入图片描述

1.4 String常量池

  • 1 常量池的设计意图

    • 1.1、字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能。

    • 1.2 JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。

      • 1)为字符串开辟一个字符串常量池,类似于缓存区。

      • 2)创建字符串常量时,首先坚持字符串常量池是否存在该字符串。

      • 3)存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。

  • 2 字符串常量池在哪里
    字符串常量池存在于方法区,也可以说存在于堆区, java8中,取消永久代,方法存放于元空间(Metaspace),元空间仍然与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中
    在这里插入图片描述

  • 3、堆

    • 1)存储的是对象,每个对象都包含一个与之对应的class。

    • 2)JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身。

    • 3)对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定。

  • 4、栈

    • 1)每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。

    • 2)每个栈中的数据(原始类型和对象引用)都是私有的。

    • 3)栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

    • 4)数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失

  • 5、方法区

    • 1)静态区,跟堆一样,被所有的线程共享。

    • 2)方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

第二章 String常用API

2.1 常用API

int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)。
int length() 返回此字符串的长度。
String toUpperCase() 所有字符都转换为大写。
String toLowerCase() 所有字符都转换为小写
boolean startsWith(String prefix) 测试此字符串是否以指定的元素开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的字符串结束。
char charAt(int index) 返回指定索引/下标处的 char 值/字符
int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。
String concat(String str) 将指定字符串连接/拼接到此字符串的结尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分隔此字符串。
String trim() 返回去除首尾空格的字符串
byte[] getBytes() 把字符串存储到一个新的 byte 数组中
String substring(int beginIndex) 返回一个新子串,从指定下标处开始,包含指定下标
String substring(int beginIndex, int endIndex) 返回一个新子串,从执定下标开始,到结束下标为止,但不包含结束下标
static String valueOf(int i) 把int转成String

2.2 API的操作

  • 1 == 和equals 的用法
public class String04 {
    public static void main(String[] args) {
        //1.练习创建String的方式一
        /**1.字符串底层维护的是char[],存放在堆中*/
        char[] value = {'a','b','c'};
        String s1 = new String(value);//触发含参构造来创建String类对象
        String s11 = new String(value);//触发含参构造来创建String类对象

        //2.练习创建String的方式二:
        /**2.此种方式创建底层也会new String(),存放在堆中常量池,效率高*/
        String s2 = "abc";
        String s22 = "abc";
        String s3 = "aaa";

        //3.测试
        System.out.println(s1 == s2);//false
        System.out.println(s1 == s11);//false,没有高效的效果
        System.out.println(s2 == s22);//true,有高效的效果
        System.out.println(s2 == s3);//false,有高效效果,但值不一样

        /**3.==比较的是两个对象的地址值
         * Object类中equals()默认实现比较的也是==地址比较
         * 但String类重写了此方法,不再比较地址值,而是两个串的具体内容
         * 也就是说,不论创建方式,只要串的内容一致,equals()就返回true*/
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.equals(s11));//true
        System.out.println(s2.equals(s3));//值不一样,返回false
    }
}
  • 2 常用API用法
public class String05 {
    public static void main(String[] args) {
        //1.创建字符串
        String s = "abc";

        char[] value = {'a','b','c'};
        String ss = new String(value);

        //2.测试常用方法
        System.out.println(s.charAt(1));//b,获取指定下标处的字符

        String s2 = s.concat("cxy");//用于拼接指定的字符串,但注意不会改变原串
        System.out.println(s);//abc,不会改变原串
        System.out.println(s2);//abccxy,打印的是拼接后s2指向的串abccxy

        System.out.println(s.concat("cxy"));
        System.out.println(s.endsWith("y"));//false,判断是否以指定元素结尾
        System.out.println(s.startsWith("a"));//true,判断是否以指定元素开头

        System.out.println( s == ss );//false,比较的是地址值
        System.out.println(s.equals(ss));//比较的是内容

        //1,获取指定元素首次出现的下标值
        System.out.println(ss.indexOf("b"));
        ss = "abcbb";
        //4,获取指定元素最后一次出现的下标值
        System.out.println(ss.lastIndexOf("b"));
        System.out.println(ss.length());//5,获取指定字符串的长度

        String s3 = "a b c d e";
        //根据指定规则分割字符串,注意返回值类型是String[],需要使用数组工具类打印
        System.out.println(s3.split(" "));//[Ljava.lang.String;@1b6d3586
        System.out.println(Arrays.toString(s3.split(" ")));

        //根据指定下标截取子串,如果只有一个下标,那就从指定位置处开始截取,包含指定下标
        //如果有两个下标,就截取这两个下标之间的子串,注意含头不含尾
        System.out.println(s3.substring(3));// c d e,[3,结束]
        System.out.println(s3.substring(1,5));// b c,[1,5)

        System.out.println(s3.toUpperCase());//A B C D E,把指定字符串转为全大写
        System.out.println(s3.toLowerCase());//a b c d e,把指定字符串转为全小写

        s3 = "     abcde     ";
        System.out.println(s3.trim());//abcde,去除指定字符串首尾空格

        System.out.println(String.valueOf(10));//10,转为String类型的"10"
        System.out.println("20"+10);//2010,String20与int10不能计算,拼接
        System.out.println(String.valueOf(80)+10);//8010,int80转String80,拼接
        System.out.println(10+10);//20,int+int->int
    }
}

第三章 StringBuilder/StringBuffer

4.1 特点

  • String是 final 修饰的常量;
  • StringBuilder:没安全感,容易翻车,非线程安全的可变字符序列
  • StringBuffer: 线程安全的可变字符序列

4.2 主要区别

StringBuilder 非线程安全 / StringBuffer 线程安全

在这里插入图片描述
在这里插入图片描述在synchronized修饰下即加锁,多个线程访问时,只有一个线程获锁,其余线程等待,直到上一线程释放锁;StringBuffer 在多线程情况下保证了在操作时的原子性,使得被操作字符序列是安全的。

4.3 String字符串拼接

public class String06 {
    public static void main(String[] args) {
        /**
         * String 字符串拼接。完成通过"+"进行拼接
         */
        method1();
    }

    public static void method1() {
        //1.定义字符串
        String str = "abcdefghijklmnopqrstuvwxyz";

        //2.将指定的字符串拼接10000次
        //2.1定义变量,用来保存最终拼接的结果
        String result ="";
        //2.2拼接10000次
        /**4.可以添加一个计时功能*/
        //4.1获取系统当前时间作为开始时间
        long t1 = System.currentTimeMillis();//ms
        for(int i = 0; i < 10000 ; i++) {
            result = result + str;
        }
        //4.2获取系统当前时间作为结束时间
        long t2 = System.currentTimeMillis();//ms
        //3.打印拼接好的字符串
        //注意:eclipse控制台显示数据有限制,都打印在同一行了,所以控制台看不出来打印的内容
        //可以通过全选,复制拿出来看数据是否拼接成功
        System.out.println(result);

        //4.3打印拼接总共花费的总时长
        System.out.println(t2-t1);
    }
}

在这里插入图片描述

4.4 builder和buffer拼接字符串

public class StringBuilderStringBuffer {
    public static void main(String[] args) {
        /**
         * Stringbuffer StringBuilder 优化"+"拼接
         * builder线程不安全,速度快
         * buffer线程安全,速度慢
         */
            method1();
            //method2();
        }

    public static void method1() {
        //1.定义字符串
        String str = "abcdefghijklmnopqrstuvwxyz";

        //2.将指定的字符串拼接10000次
        /**优化1:String-->StringBuffer*/
        StringBuffer sb1 = new StringBuffer();//创建工具类对象1

        //2.2拼接10000次
        /**4.可以添加一个计时功能*/
        //4.1获取系统当前时间作为开始时间
        long t1 = System.currentTimeMillis();//ms
        for(int i = 0; i < 100000 ; i++) {
            /**优化1:+ -->append() */
            //result = result + str;
            sb1.append(str);
        }
        //4.2获取系统当前时间作为结束时间
        long t2 = System.currentTimeMillis();//ms
        //4.3打印拼接总共花费的总时长
        System.out.println(sb1.toString());//打印拼接的结果
        System.out.println(t2-t1);
    }

        public static void method2() {
            //1.定义字符串
            String str = "abcdefghijklmnopqrstuvwxyz";

            //2.将指定的字符串拼接10000次
            /**优化1:String-->StringBuilder*/
            StringBuilder sb2 = new StringBuilder();//创建工具类对象2

            //2.2拼接10000次
            /**4.可以添加一个计时功能*/
            //4.1获取系统当前时间作为开始时间
            long t1 = System.currentTimeMillis();//ms
            for(int i = 0; i < 100000 ; i++) {
                /**优化2:+ -->append() */
                //result = result + str;
                sb2.append(str);
            }
            //4.2获取系统当前时间作为结束时间
            long t2 = System.currentTimeMillis();//ms
            //4.3打印拼接总共花费的总时长
            System.out.println(sb2.toString());//打印拼接的结果
            System.out.println(t2-t1);
        }
}

4.5 二者与String的区别

string 是 final修饰的字符串常量,在操作改变字符序列长度、内容时,实际是使用了新的对象完成的

案例:

public class String07 {
    public static void main(String[] args) {

        String str1 = "abc";
        System.out.println(str1+"----"+ str1.hashCode());
        str1 = str1+"dd";
        System.out.println(str1+""+str1.hashCode());

        System.out.println("-------------------------------------------------------------------");

        String str2 = "abcdef";
        String str3 = "abc"+"def";
        System.out.println(str2==str3);
        System.out.println("==="+str2.hashCode());
        System.out.println("___"+str3.hashCode());

        System.out.println("-------------------------------------------------------------------");

        StringBuilder sb1 = new StringBuilder("海王");
        System.out.println(sb1+"=========="+sb1.hashCode());
        sb1.append("Mis吴");
        System.out.println(sb1+"//"+sb1.hashCode());

        System.out.println("-------------------------------------------------------------------");

        StringBuilder sb2 = new StringBuilder("海贼王");
        System.out.println(sb2+"=========="+sb2.hashCode());
        sb2.append("路飞");
        System.out.println(sb2+"//"+sb2.hashCode());

    }
}

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值