String类

String类

String类是一个字符串类,也是java的一个常用类。它会字符串封装成字符串对象,以便调用

String类的理解和创建对象

  1. String对象用于保存字符串,也就是一组字符序列

  2. 字符串常量对象使用双引号括起的字符序列,例如:“您好”,“1234”,“qishi”

  3. 字符串的字符使用Unicode字符编码,一个字符(不管是汉字还是字母)占两个字节

  4. String类常用构造器
    String s1 = new String();
    String s2 = new String(String original);
    String s3 = new String(char[] a);
    String s4 = new String(char[]a,int startindex,int count);
    String s5 = new String(byte[] b);

  5. String类实现了接口Serializable接口:可以串行化,用于网络传输

  6. String类实现了接口Comparable接口:对象可以比大小

  7. String类是final修饰,不能被其他类继承

  8. String类有属性private final char[] value,用于存放字符串内容(jdk9以后是byte[])

  9. value属性是final修饰,不可以修改。这里的value是一个数组,是引用类型,不可修改指的是地址不可修改,数组的值还是可以修改的

两种创建String类对象的区别

方式一:直接赋值 String s = “大卫”;
方式二:使用构造器String s2 = new String(“大卫”);

  1. 第一种方式,会先到常量池中查看是否有"大卫",如果有直接指向它,如果没有就创建一个"大卫",然后指向它。所以最终s指向的是常量池的空间地址
    示意图:
    在这里插入图片描述
  2. 第二种方式先在堆中创建空间,里面有value属性,指向常量池的空间地址,如果常量池没有"大卫",就创建一个然后指向它。如果有直接指向它,所以s2指向的是堆中的空间地址,s2的属性value指向的是常量池的空间地址

示意图:
在这里插入图片描述

创建String对象测试题
1.下列代码会输出什么?

String s = "da";
        String s2 = "da";
        System.out.println(s.equals(s2));
        System.out.println(s==s2);

因为都是直接赋值创建的,所以会直接指向常量池的空间地址。指向的都是同一个所以都输出为true

2.下列代码会输出什么?

String a ="abc";
String b = new String("abc");
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a == b.intern());
System.out.println(b == b.intern());

第一个,equals比较的是字符串的内容,所以为true
第二个,a指向的是常量池的地址 b指向的是堆中的地址,所以为false
第三个,intern方法:返回常量池的地址(对象),那么因为b.intern的常量池地址和a是同一个,所以输出true
第四个,b指向的是堆中的空间地址,b.intern指向的是常量池的空间地址,所以不是同一个,返回false

3.下列代码会输出什么?并画出内存图

Person p1 = new Person();
p1.name = "java";
Person p2 = new Person();
p2.name = "java";
System.out.println(p1.name.equals(p2.name));
System.out.println(p1.name == p2.name);
System.out.println(p1.name == "java");

第一个:p1p2的name内容相同,true
第二个:p1p2的name常量池地址相同,true
第三个:内容相同,true

内存图:
在这里插入图片描述

4.下列代码输出什么?

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

s1和s2指向的是分别的堆空间地址,因此为false

String对象的特性

  1. String是一个final类,代表不可变的字符序列
  2. 字符串是不可变的,一个字符串对象一旦被分配,其内容是不可变的

举例说明:
下列代码创建了几个对象?

String s = "hello";
s1 = "hahha";

这两句语句并不是把"hello"改成了"hahha"。而是会在常量池中寻找"hahha",如果没有就创建一个,但是原来的“hello”并不会就此销毁。所以一共是创建了两个对象,先创建了"hello",指向它。然后又创建“hahha”,改成指向它

内存图演示:
在这里插入图片描述

String面试题

1. 下列代码创建了几个对象?

String s = "hello"+"abc";

编译器会做一个优化,判断创建的常量池对象是否有引用指向。
如果没有指向会直接合并,String s = “hello”+“abc”; = String s = “helloabc”;。所以只创建了一个对象

2. 下列代码创建了几个对象?

String a = "hello";
String b = "abc";
String c = a+b;

当创建的常量池对象是变量时(封装到对象的常量),底层会进行以下几个步骤:
1.创建一个StringBuilder 对象,也就是StringBuilder sb = new StringBuilder();
2.然后调用StringBuilder的append方法传入第一个和第二个(分两次)封装成对象的常量字符串
3.而append会在已有的字符串上追加,所以最终是创建了3个对象,但是要注意的是,a和b都是直接指向常量池的,而c是指向堆中的StringBuilder 对象,这个对象的属性才是指向常量池的

所以最终创建了a的"hello",b的"abc",c对象属性的"helloabc",这三个
因此如果添加一个变量String d = “helloabc”;
使用System.out.println(d == c);是false,因为指向的地址不同。

内存图示意:
在这里插入图片描述
3. 下列代码输出什么?

String s1 = "oop";
String s2 = "java";
String s3 = "oopjava";
String s4 = (s1+s2).intern();;
System.out.println(s3 == s4);
System.out.println(s4.equals(s3));

intern方法会返回常量池中对象的地址,而s3和s4指向的是同一个地址,所以为true,既是同一个地址,内容肯定也是一致的所以输出:true true

4. 下列代码输出什么?

public class test1 {
    String str = new String("oop");
    final char [] ch = {'j','a','v','a'};
    public void change(String str,char[] ch){
        str = "java";
        ch [0]='h';
    }
    public static void main(String[] args) {
        test1 t1 = new test1();
        t1.change(t1.str, t1.ch);
        System.out.print(t1.str+"and");
        System.out.println(t1.ch);
    }
}

内存示意图:
在这里插入图片描述

最终输出:
oopandhava

特别注意点:change里的str是在change栈重新创建的一个引用,只是先开始把t1对象的value属性指向的地址复制了一份给change方法里的str,跟原来的没关系。就算change里的修改了,但是main方法输出的是t1的str的value属性指向的地址,而这个地址没有动过所以还是指向0x002”oop“

String类的常用方法

String类是保存字符串常量的,每次更新都需要重新开辟空间,效率较低,因此设计了 StringBuilder和StringBuffer增强String的功能,且提高效率。

以下是String类的常用方法:

  1. equals:包含大小写,判断内容是否相等
  2. equalsIgnoreCase:忽略大小写,判断判断内容是否相等
  3. length:获取字符串的个数,长度
  4. indexOf:获取某个字符在字符串中第一次出现的下标,如果找不到返回-1
  5. lastindexOf:获取某个字符在字符串最后一次出现的下,如果找不到返回-1
  6. substring:获取指定范围的子串(字符串的某一段),只传入一个数字就是从x处起后面的全部,两个就是从a到b前面,(含头不含尾)
  7. trim:去前后空格
  8. charAt:获取字符串的某个字符

使用演示:

  • equals
public class test1 {
    public static void main(String[] args) {
        String s = new String("hello");
        System.out.println(s.equals("hello"));
    }
}

运行结果:true

  • equalsIgnoreCase
public class test1 {
    public static void main(String[] args) {
        String s = new String("Hello");
        System.out.println(s.equalsIgnoreCase("hello"));
    }
}

运行结果:true

  • length
public class test1 {
    public static void main(String[] args) {
        String s = new String("Hello");
        System.out.println(s.length());
    }
}

运行结果:5

  • indexOf
public class test1 {
    public static void main(String[] args) {
        String s = new String("H@ell@o");
        System.out.println(s.indexOf('@'));
    }
}

运行结果:1

  • lastindexOf
public class test1 {
    public static void main(String[] args) {
        String s = new String("H@ell@o");
        System.out.println(s.lastIndexOf('@'));
    }
}

运行结果:5

  • substring
public class test1 {
    public static void main(String[] args) {
        String s = new String("Hee11");
        System.out.println(s.substring(2));
        System.out.println(s.substring(2,4));
    }
}

运行结果:e11 e1

  • trim
public class test1 {
    public static void main(String[] args) {
        String s = new String("   Hee11 ");
        System.out.println(s.trim());
    }
}

运行结果:Hee11

  • charAt
public class test1 {
    public static void main(String[] args) {
        String s = new String("Heb11");
        System.out.println(s.charAt(2));
    }
}

运行结果:b

第二部分常用方法:

  1. toUpperCase:转换成大写
  2. toLowCase:装换成小写
  3. concat:拼接字符串
  4. replace:可以传入两个参数,在字符串里找a替换成b
  5. split:分割字符串,传入某个字符,以此字符为界,将字符串分割成String数组,特殊分割符需要转义字符
  6. toCharArray:转换成字符数组
  7. compareTo :比较两个字符串的大小,如果前者大返回正数,后者大返回负数。如果长度相同,且每个字符相同返回0
  8. format:格式字符串,给不同的格式符,由后面传入对于的变量填充。相当于制作一个模板,可以对 固定但部分需要变化的字符串进行封装

使用演示:

  • toUpperCase
public class test1 {
    public static void main(String[] args) {
        String s = new String("abc");
        System.out.println(s.toUpperCase());
    }
}

运行结果:ABC

  • toLowCase
public class test1 {
    public static void main(String[] args) {
        String s = new String("ABC");
        System.out.println(s.toLowerCase());
    }
}

运行结果:abc

  • concat
public class test1 {
    public static void main(String[] args) {
        String s = new String("ABC");
        System.out.println(s.concat("嘿嘿嘿").concat("hahha"));
    }
}

运行结果:ABC嘿嘿嘿hahha

  • replace
public class test1 {
    public static void main(String[] args) {
        String s = new String("ABC");
        System.out.println(s.replace("A","a"));
    }
}

运行结果:aBC

  • split
public class test1 {
    public static void main(String[] args) {
        String s = new String("A,B,C");
        String [] sp = s.split(",");
        for (String a:sp) {
            System.out.println(a);
        }
    }
}

运行结果:
A
B
C

  • toCharArray
public class test1 {
    public static void main(String[] args) {
        String s = new String("A,B,C");
        char [] sp = s.toCharArray();
        for (char a:sp) {
            System.out.println(a);
        }
    }
}

运行结果:
A
,
B
,
C

  • compareTo
public class test1 {
    public static void main(String[] args) {
        String s1 = "abcd";
        String s2 = "abc";
        System.out.println(s1.compareTo(s2));
        String s3 = "dbc";
        String s4 = "abc";
        System.out.println(s3.compareTo(s4));
    }
}

运行结果:
1
3
注意:如果长度都相同,比按照编码表的对应数字进行比较

  • format
public class test1 {
    public static void main(String[] args) {
       //format是String类的静态方法
        //输出一个人的信息
        String name = "jack";
        int age = 21;
        double sal = 8222.212;
        char gender = '男';
        String info = String.format("姓名%s,年龄%d,薪水%.2f,性别%c",name,age,sal,gender);
        System.out.println(info);
    }
}

运行结果:姓名jack,年龄21,薪水8222.21,性别男
占位符:
%s:字符串
%d:整数
%.2f:小数(保留两位)
%c:字符
占位符由后面的变量来替换


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值