String自我介绍

一、三大核心特点

不变性:

​ String是一immutable模式的对象,不变模式的主要作用是当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。

常量池的优化

​ String对象创建之后,会在字符串常量池中进行缓存,下次创建同样的对象时,会直接返回缓存的引用。

Final修饰:

​ String类不可被继承,提高了系统的安全性。

二、类型结构

​ String不是基本数据类型

三、String 的实例化

​ String 的实例化有两种方式:

1、直接赋值,

2、通过构造函数,可以直接将字符串的值传入,页可以传入一个char数组。

		String str1 = "Hello";//直接赋值
        String str2 = new String("hello");//构造函数
        char[] c1 = {'你','好'};
        String str3 = new String(c1);//构造函数存储char类型数组

直接赋值和构造函数的区别:

​ 存储的区域不同,直接赋值的方式存储字符串常量池当中,构造函数存储在堆内存当中。

        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1==str2);//true 内存地址一样(根据String常量池的优化特性)
        String str3 = new String("hello");
        String str4 = new String("hello");
        System.out.println(str3==str4);//false 内存地址不一样(堆内存中指向不同的地址)

四、equals重写

​ 因为Strign类堆equals方法进行了重写,所以我们可以直接调用String的equals方法判断两个字符串的值是否相等。源码先判断两个值的内存地址是不是一样,若是一样的话那么值就相同。若是不一样,先判断两个值的长度是否一样,不一样的直接返回false。一样则使用char[]数组进行一个一个的字符进行对比,若是每个字符都相等则返回true反之。

 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }	

五、不可变

​ 当String对象的值发生改变时,栈里面会创建另外一个内存地址,与原来的地址不一致。

      String str1 = new String("hello");
      String str2 = str1;
      System.out.println(str1==str2);//true 两者指向的地址一致
      str1 +="world";//值发生了改变,内存地址也会跟着改变
      System.out.println(str1==str2);//false

六、intern()方法

​ 当调用某个字符串对象的intern()方法时,会去字符串常量池中寻找,如果已经存在一个值相等的字符串对象的话,则返回改对象的引用。如果不存在,则在字符串常量池中创建该对象,并返回false。堆内存中引用会被gc回收。

​ 分析:因str1的值已经存入到常量池当中,而str2的值则是在栈中开辟一个空间来存储。所以两者的内存是不一致的。当str2使用了intern()方法,首先会默认到常量池当中,寻找有没有相匹配的值。若是有匹配的值,就返回该值的对象引用。因为str1的值和str2的值一致,则返回str1的引用地址。所以str1==str2.intern();

 	 String str1 = "hello world";//存入常量池中
      String str2 = new String("hello world");//在栈内存中开辟空间
      System.out.println(str1==str2);//false 内存地址不一致
      System.out.println(str1==str2.intern());//true 常量池中的值一致

七、常用方法

方法描述
public String()创建一个值为空的对象
public String(String original)创建一个值为original的对象
public String(char value[ ])将一个char型数组转为字符串对象
public String(char value[ ], int offset, int count)将一个指定范围的char型数组转为字符串对象
public String(byte[ ] bytes )将一个byte型数组转为字符串对象
public String (byte bytes[ ], int offset, int length)将一个指定范围的byte型数组转为字符串对象
public int length()返回字符串的长度
public boolean isEmpty()判断字符串是否为空
public char charAt(int index)返回字符串中指定位置的字符

…其余的看文档…

八、经典问题

1、==和equals的区别?

​ 分析:==可以理解为比较栈内存中的值,如果说这个变量是基本数据类型,那么栈内存中存的就是具体的数值。如果是引用类型,栈里面存的就是引用类型的地址。所以说对于基本数据类型来说,就是比较值是否相等,对于引用类型来讲,比较的就是引用地址是否相等。equals方法实际是Object提供的方法,它的本质就是用进行判断。但是,java中任意一个类都可以对它进行重写,根据具体的需求重新定义它的判断逻辑。

2、下述代码的运行结果是?

	  String str1 = "hello world";
      String str2 = "hello"+" world";
      System.out.println(str1==str2);

​ 分析:str1首先在字符串常量池当中创建了“hello world”,而str2是把两个字符串字面值进行拼接起来(常量与常量拼接),结果还是存在常量池当中。根据常量池的优化功能,str2会去引用str1的值,所以结果是true。

3、下述代码的运行结果是?

     String str1 = "hello world";
      String str2 = "hello";
      str2 += " world";
      System.out.println(str1==str2);

​ 分析:str1存在字符串常量池当中,而str2使用间接拼接,使用变量与常量拼接那么值会存储到堆内存中。所以两者之间的地址不一致,返回false。

4、下述代码的运行结果?

	 String str1 = "hello world";
     String str2 = "world";
     String str3 = "hello"+str2;
     System.out.println(str1==str3);

​ 分析:str3使用常量与变量进行拼接,那么值会存在堆内存中。而str1的值存在字符串常量池当中,所以两者比较的结果是false。

5、下述代码的运行结果是?

        String str1 = "hello world";
        final String str2 = " world";
        String str3 = "hello"+str2;
        System.out.println(str1==str3);

​ 分析:原本str2是变量,使用final修饰后变成常量。str1的值存在字符串常量池当中,而str3使用常量与常量进行拼接,那么结果会存到常量池当中。根据常量池的优化功能,str3会去引用str1的值,所以结果是true。

6、下述代码的运行结果是?

	    String str1 = "hello world";
        final String str2 = new String(" world");
        String str3 = "hello"+str2;
        System.out.println(str1==str3);

​ 分析:str1的值存在字符串常量池当中。str2使用构建函数创建值那么会在堆中开辟空间存储,加上final修饰成常量任然存储在堆内存当中。str3等于常量加上一个堆内存的数据那么结果还是在堆内存当中。结果是false。

7、下述代码的运行结果是?

	   String str1 = "hello world";
       String str2 = "hello";
       String str3 = " world";
       String str4 = str2+str3;
       System.out.println(str4==str1);
       System.out.println(str4.intern()==str1);

​ 分析:str1存储在字符串常量池当中,str2和str3是两个变量,两个变量拼接会存储在堆内存当中,所以str1和str2的内存地址不一样结果false。str4.intern()方法首先会默认到常量池当中,寻找有没有相匹配的值。若是有匹配的值,就返回该值的对象引用。因为str4的值和str1的值一致,则返回str1的引用地址。所以结果true;

8、什么是字符串常量池?

​ 分析:字符串常量池它是位于堆内存里面的,专门用于存储字符串常量的。可以提高内存的使用率,避免开辟多块空间存储相同的字符串。若是没有常量池,每创建一个数据,都需要开辟一个空间。我们在创建字符串对象的时候,JVM首先会检查字符串常量池,如果这个字符串已经存在于常量池当中就直接返回它的引用。如果不存在,就会创建字符串对象存入到字符串常量池当中,再返回它的引用。

9、String是线程安全的吗?

​ 分析:String是线程安全的。因为String是一个不可变的类,一旦创建String对象,我们就不能改变它的值。同一个字符串实例,可以被多个线程共享 。

10、在使用HashMap的时候,用String做key有什么好处?

​ 分析:因为字符串是不可变的,所以说当字符串被创建的时候,它的HashCode的值就被缓存下来了。后续计算的时候,不需要重复去计算它的哈希值,可以直接去获取value值。相对其他类型会快一些。若是其他类型,每次使用key值的时候都会去计算以下的它的哈希值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值