【手把手带你学JavaSE系列】String类(上篇)

一、字符串的构造方法

public static void main(String[] args) {
        //方法一:使用常量串构造
        String str1 = "abcdef";
        //方法二:直接newString对象
        String str2 = new String("hehe");
        //方法三:使用字符数组进行构造
        char[] chars = {'a','b','c'};
        String str3 = new String(chars);
        System.out.println(str3);

    }

在这里插入图片描述
注意:1. String是引用类型,内部并不存储字符串本身。

public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = str1;
        System.out.println(str1);
        System.out.println(str2);
        str1 = "world";
        System.out.println("================");
        System.out.println(str1);
        System.out.println(str2);
    }

在这里插入图片描述

为什么会出现这样的结果呢?

由于 String 是引用类型

在这里插入图片描述
我们发现, “修改” str1 之后, str2 也没发生变化, 还是 hello?

事实上, str1 = “world” 这样的代码并不算 “修改” 字符串, 而是让 str1 这个引用指向了一个新的 String 对象.
在这里插入图片描述

public static void func(String s,char[] array){
        s = "Haha";
        array[0] = 'p';
    }

    public static void main3(String[] args) {
        String str = "abcdef";
        char[] chars = {'a','b','c'};
        func(str,chars);
        System.out.println(str);
        System.out.println(Arrays.toString(chars));
    }

在这里插入图片描述
在这里插入图片描述
注:并不是传引用就能改变实参的值!!!!

二、String对象的比较

1.==比较是否引用同一个对象。

public static void main(String[] args) {
        String str1 = "hello";//存放到字符串常量池里面
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }

在这里插入图片描述
要想弄清楚这个为什么是false?
就需要提前了解一个知识!

Class文件常量池
运行时常量池:当程序把编译好的字节码文件,加载到JVM当中后,会生成一个运行时常量池[方法区],实际上是Class文件常量池.
字符串常量池:主要存放字符串常量->字符串常量池,本质上是一个哈希表.StringTable

对于引用类型变量,==比较两个引用变量引用的是否为同一个对象 。

在这里插入图片描述

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
    }

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "he" + "llo";//此时 都是常量,编译的时候就是hello
        System.out.println(str1 == str2);
    }

在这里插入图片描述
所以这个结果依然为true
在这里插入图片描述

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "he" + "llo";//此时 都是常量,编译的时候就是hello
        String str3 = "he";
        String str4 = str3 + "hllo";//此时str3是一个变量,编译的时候不知道是什么
        System.out.println(str1 == str4);
    }

在这里插入图片描述

public static void main(String[] args) {
        String str1 = "11";
        String str2 = new String("1") + new String("1");
        System.out.println(str1 == str2);
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        String str2 = new String("1")+new String("1");
        str2.intern();//手动入池
        String str1 = "11";
        System.out.println(str1 == str2);
    }

在这里插入图片描述
在这里插入图片描述

2. boolean equals(Object anObject) 方法:按照字典序比较。

public static void main(String[] args) {
        String str1 = "11";
        String str2 = new String("1")+new String("1");
        str2.intern();//手动入池->当字符串常量池,没有的时候,就会入池
        System.out.println(str1 == str2);
        System.out.println(str1.equals(str2));
    }

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        String str1 = null;
        String str2 = "11";
        System.out.println(str2.equals(str1));
    }

在这里插入图片描述

public static void main(String[] args) {
        //数组的整体赋值 只有1次机会 就是在定义的时候
        final int []array = {1,2,3,4,5};
        //array = {4,5,6,7};
        String str1 =null;//str1这个引用 不指向任何对象
        String str2 = "";//str2这个引用 指向的字符串是空的
        System.out.println(str2.length());
    }

3. int compareTo(String s) 方法

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
  2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值。
  String s1 = new String("abc");
  String s2 = new String("ac");
  String s3 = new String("abc");
  String s4 = new String("abcdef");
  System.out.println(s1.compareTo(s2));  // 不同输出字符差值-1
  System.out.println(s1.compareTo(s3));  // 相同输出 0
  System.out.println(s1.compareTo(s4));  // 前k个字符完全相同,输出长度差值 -3

在这里插入图片描述

4.int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较

public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("ABc");
        String s4 = new String("abcdef");
        System.out.println(s1.compareToIgnoreCase(s2));  // 不同输出字符差值-1
        System.out.println(s1.compareToIgnoreCase(s3));  // 相同输出 0
        System.out.println(s1.compareToIgnoreCase(s4));  // 前k个字符完全相同,输出长度差值 -3
    }

在这里插入图片描述

三、字符串不可变

public static void main(String[] args) {
        String str = "hello" ;
        str = str + " world" ;
        str += "!!!" ;
        System.out.println(str);

    }

在这里插入图片描述
形如 += 这样的操作, 表面上好像是修改了字符串, 其实不是. 内存变化如下:
在这里插入图片描述
+= 之后 str 打印的结果却是变了, 但是不是 String 对象本身发生改变, 而是 str 引用到了其他的对象.

回顾引用
引用相当于一个指针, 里面存的内容是一个地址. 我们要区分清楚当前修改到底是修改了地址对应内存的内容发
生改变了, 还是引用中存的地址改变了.

那么如果实在需要修改字符串, 例如, 现有字符串 str = “Hello” , 想改成 str = “hello” , 该怎么办?

  1. 常见办法: 借助原字符串, 创建新的字符串
public static void main(String[] args) {
        String str = "Hello";
        str = "h" + str.substring(1);
        System.out.println(str);

    }

在这里插入图片描述

  1. 特殊办法(选学): 使用 “反射” 这样的操作可以破坏封装, 访问一个类内部的 private 成员.

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

  1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了.
  2. 不可变对象是线程安全的.
  3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.
  • 52
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 76
    评论
评论 76
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼王胖嘟嘟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值