字符串和包装类

字符串

java中表示字符串的类有String StringBuffer StringBuilder

1.String

String类被final修饰的 没有子类的

1.1 创建String类对象的方式

  • a.以字面量的形式赋值 创建String对象
    String str = “bac”;
    字面量 - 就是字符串常量 位于方法区的常量池中
    int a = 10;

  • b.根据构造方法创建字符串对象
    String str = new String(“bcd”);
    new 出来的对象是位于堆中的

字符串和包装类_第1张图片
1.2 两种创建方式的区别

  • a.以字面量形式创建的对象,位于java提供的字符串常量池中。
    字符串常量池有一个特点:当定义对象时,先在常量池中查看是否有该对象值,如果有的话直接使用,如果没有先在常量池中添加,再使用

  • b.以字面量形式赋值的话 内存中只有一个对象
    以构造方法赋值的话 内存中有两个对象

1.3 String对象是不可变的
一旦创建了String对象,对象的值将不再发生改变

 源码分析String类对象为什么不可变
          // The value is used for character storage.
      private final char value[];
       String字符串存放字符序列的数组
             String str = "hello";
                 --》 char value[] = new char[]{'h','e','l','l', 'o'};
                   该数组使用的是final修饰的 表示该数组对象地址不可变
                   该数组前面的修饰符为private
只能在String本类中使用 外界获取不了的 --> 外界无法通过数组索引修改数组,所以数组的内容是固定的 而且地址是不可变的 导致String对象不可变

1.4 打印字符串变量的结果 【了解】

得到的结果是字符串序列值。

 原因: 在String类中重写了toString方法
    public String toString(){
            retur this;
    }
    以字面量形式赋值的对象 这个获取的常量池中字符序列值

以构造方法赋值的

public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
    String str = new String("abc");
   分析:
        str.value = "abc".value;
        str.hash = "abc".hash;

    "abc".hash ---> 获取的就是对应的字符序列
    
    hash --> hashCode值
    打印变量的时候 Object中toString方法
        类名@hashCode的十六进制
 this.hash = original.hash;
    而方法区常量池的hash打印的是对应的字符序列
    所以导致以构造方法形式创建的对象打印出来的也是字符序列

1.5 String中常见的操作

String的对象是不可变 如果下列方法中有操作String对象,其实是生成了一个新的String对象,对于原来的对象不受影响

​获取
1.获取字符串字符序列的长度
int len=str.length()
2.根据索引位置获取对应的字符
char ch=str.charAt(index) index为索引值
3.根据字符或者字符串返回第一次或者是最后一次出现的索引位置

根据字符返回第一次该字符出现的索引位置
int index=str.indexof('字符')
根据字符串返回第一次该字符串出现的索引位置
int index=str.indexof("字符串")
如果字符串中没有对应的字符或子串 返回值??? -1
根据字符返回最后一次出现的索引位置
int index=str.lastIndexof('字符')
根据字符串返回最后一次出现的索引位置
int index=str.lastIndexof("字符串")
从某个位置开始
int index=str.indexof('字符',fromindex)

  • ​判断
    1.判断字符串是否包含某个子串
    str.contains()
    2.判断字符串中是否有内容
    str.isEmpty()
    3.判断字符串是否以指定内容开头
    str.startsWith()
    4.判断字符串是否以指定内容结尾
    str.endsWith()
    5.判断字符串内容是否相同[忽略大小写]
    不忽略大小写 str.equals(str1)
    忽略大小写 str.equalsIgnoreCase(str2)

  • ​转换
    将字符串数组转化为字符串

//		 将字符串数组转化为字符串
      char[] ch={'h','e','l','l','o'};
      //1.通过构造方法转化
      //a.全部转化
      String str=new String(ch);
      //b.第二个参数表示从第几个开始转化
      //第三个参数表示转化几位,注意数组越界问题
      str=new String(ch,2,3);
      System.out.println(str);
      //2.通过静态方法转化
      //a.String.copyValueOf
      String str1=String.copyValueOf(ch);
      System.out.println(str1);
      str1=String.copyValueOf(ch, 2, 3);
      System.out.println(str1);
      //b.String.valueOf
      str1=String.valueOf(ch);
      System.out.println(str1);
      str1=String.valueOf(ch, 2, 3);

将字符串转化为字符数组

char []ch1=str.toCharArray();
System.out.println(Arrays.toString(ch1));

将字节数组转化为字符串

将字符串转化为字节数组
将基本类型数据转化为字符串
字符串大小写转换
替换字符串
切割字符串
spilt
提取子串
substring
比较字符串大小
去除字符串两端空格
拼接字符串
字符串格式化

2.StringBuffer

​ 这个也是表示字符串的类

String和StringBuffer的区别
String是不可变的类 对象是不可变的
StringBuffer相当于是字符缓冲容器,对象是可变的。在对字符串做修改时,修改的是其本身

2.1 StringBuffer的初始化

创建StringBuffer对象 是通过构造方法创建的

  • a.public StringBufffer()
    初始化的是一个不带字符的字符缓冲区,缓冲区初始容量为16个字符

  • b. public StringBuffer(int a)
    初始化的是一个不带字符的字符缓冲区,缓冲区初始容量为a个字符

  • c. public StringBuffer(String str)
    初始化的是一个带有字符的字符缓冲区,初始字符内容为String字符串内容,缓冲区初始容量为16 + str.length()个字符

StringBuffer对象可变的原因:

存放字符序列数组是可变的没有用final进行修饰
在StringBuffer中添加字符时,会先判断存放字符的数组长度是否充足,如果充足的话直接在数组添加添加一个新的内容,如果不充足,先改变存放字符数组长度,原数组中的内容进行拷贝,赋值到新的数组中

字符串和包装类_第2张图片
2.2 常用的方法
String中 获取的方法在StringBuffer也存在

获取字符串长度
获取某个位置上的字符
获取字符或者是字符串第一次/最后一次出现的位置

  • a. 获取StringBuffer的当前可存储字符的容量

  • b. 拼接字符串
    StringBuffer append(基本数据类型的数据/String/StringBuffer/char[]/Object);

  • c.插入字符串
    StringBuffer insert(索引,基本数据类型的数据/String/StringBuffer/char[]/Object)

  • d. 删除字符序列
    删除多个字符[删除子串]
    StringBuffer delete(int beginIndex, int endIndex);
    [begin, end)

    删除单个字符
    StringBuffer deleteCharAt(int index)

  • e.替换字符串
    替换子串
    StringBuffer replace(int start, int end, String newStr)
    替换单个字符
    void setCharAt(int index, char newChar);

  • f.反转字符串
    StringBuffer reverse();

字符串和包装类_第3张图片
3.StringBuilder和StringBuffer
StringBuilder的使用和StringBuffer一样。区别在于:

StringBuffer是线程安全的 执行效率较慢
StringBuilder是线程非安全的 指向效率是偏快的

StringBuffer中的append方法

public synchronized StringBuffer append(int i) {
        toStringCache = null;
        super.append(i);
        return this;
    }

StringBuilder中的append方法

public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
  }

因为在StringBuffer所有的方法操作都是同步方法,被synchronized修饰,当多个线程来对方法同时进行操作时,线程顺序被同步化
简单而言就是一个线程一个线程的进行数据修改 StringBuilder的方法操作并没有同步化,当多条线程来进行方法访问时,线程是并发的,几乎是同时执行该方法 有可能会导致数据混乱的问题

4.String类中的“+”拼接符拼接字符串原理

String str = “abc”;
str = str + “ABC”;

内部操作:
当使用+拼接符时:
StringBuffer sb = new StringBuffer(str);
sb.append(“ABC”);
str = sb.toString();

文字描述:
String str = “abc”; 创建一个String对象"abc",str变量引用这个对象
再创建一个容量为str.length+16的StringBuffer对象
StringBuffer sb = new StringBuffer(str)
再调用StringBuffer中的append方法将“ABC”进行拼接
最后再调用StringBuffer中toString方法创建一个新的String对象将StringBuffer类型的数据"abcABC"
转换为String类型,最后将str再引用新的String对象
public String toString(){
return new String(value);
}

5.String和StringBuffer类型的转换

String ----》 StringBuffer

    通过构造方法进行转换
        String str = "abc";
        StringBuffer sb  =new StringBuffer(str);

StringBuffer ----》 String

    调用StringBuffer的toString方法
    String str1  =sb.toString();

6.包装类
​ 包装类把基本数据类型的数据转化为对象

对于包装类来说,用途:
1.集合中只能存放引用类型的数据,如果想存放int数字等这个时候就需要使用包装类
2.对于每个类型的包装类都有对应的相关属性 和 每个类型的最大值与最小值以及对应的相关操作
如: Integer中对进制的转换

包装类的结构图
字符串和包装类_第4张图片
包装类的构造方法

public Type(type value)
真实的 public Integer(int value)

除了Character 都可将字符串类型转化为对应的数据包装类型
例如:将字符串类型转化为Integer类型

6.1 以Integer为例讲解一下常用的方法

  • 1、基本数据类型 —> 引用类型
    int a = 10;
    Integer in = new Integer(a);

  • 2、将引用类型转化为基本数据类型 type typeValue()
    int b = in.intValue();

6.2 装箱和拆箱

  • 装箱:将基本数据类型使用其对应的引用类型包装起来
    Integer in = new Integer(10);

  • 拆箱:将引用类型转化成对应的基本数据类型
    int value = in.intValue();

JDK5.0之后支持自动装箱和自动拆箱

  • 自动装箱:
    Integer in = 10;

  • 自动拆箱
    int b = in;

自动装箱如何实现的?

Integer in = 10;
内部调用的方法为: static Integer valueOf(int i)
in = Integer.valueOf(10);
看一下valueOf这个方法:
public static Integer valueOf(int i) {
if (i >= -128 && i <= 127)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);

}

6.3 面试中对于装箱拆箱会遇到的问题
1.Integer in = new Integer(10); 和 Integer in = 10; 两者的区别

  • a.前者不会触发自动装箱,但是后者会触发

  • b.前者一定会在堆中创建对象 但是后者可能不会【-128~127直接在数值缓冲池中取值】

2.自动装箱的弊端

Integer sum = 0;
for(int i = 0; i < 100; i++){
sum += i;
}

Integer对象无法做算术运算,完成以上功能,得先对sum拆箱,进行加法运算,再进行装箱。如果数量过大,会降低程序的执行性能,加重了垃圾回收的工作

3.valueOf做了解

你可能感兴趣的:(Java,字符串)