美文网首页
001 String

001 String

作者: 向上十五度 | 来源:发表于2020-03-15 15:40 被阅读0次
  • 1 、string类型为什么是final?

因为:
(1)为了实现字符串池(只有当字符是不可变的,字符串池才有可能实现)
(2)为了线程安全(字符串自己便是线程安全的)
(3)为了实现String可以创建HashCode不可变性(Map的key一般String用的最多原因就是这个)
String被final修饰:注意是安全性和效率;还有一点很多初学者没搞明白就是final修饰的对象只是引用地址不可变,内容还是能变的。

扩展
String、stringBuffer
String 被声明为 final,因此它不可被继承。
在 Java 8 中,String 内部使用 char 数组存储数据。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;
}

value 数组被声明为 final,这意味着value数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
不可变的好处

  1. 可以缓存 hash 值
    因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
  2. String Pool 的需要
    如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
  3. 安全性
    String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。
  4. 线程安全
    String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
    区别
    String, StringBuffer and StringBuilder
    1、可变性
    String 不可变
    StringBuffer 和 StringBuilder 可变
    2、线程安全
    String 不可变,因此是线程安全的
    StringBuilder 不是线程安全的
    StringBuffer 是线程安全的,内部使用 synchronized 进行同步
    StackOverflow : String, StringBuffer, and StringBuilder
    String Pool
    字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。
    当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
    下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中,然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。
String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
String s4 = s1.intern();
System.out.println(s3 == s4);           // true

如果是采用 "ccc" 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。

String s5 = "ccc";
String s6 = "ccc";
System.out.println(s5 == s6);  // true

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
StackOverflow : What is String interning?
深入解析 String#intern
new String("abc")
使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 "abc" 字符串对象)。
"abc" 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 "abc" 字符串字面量;
而使用 new 的方式会在堆中创建一个字符串对象。
以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

String 的toString()equals()
toString()
1、所有类间接或直接继承Object,所以每个类都有toString()
2、Object的toString()方法:

public String toString() {
 return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

Println()中的参数如果没有(显示调用)调用toString(),
只要是引用类型(除了String类型、基本类型形式(int char)、基本类型的引用数组类型(char[] int[]等))都是在Println()方法中默认调用toString()
什么时候重写toString()
当打印输出一个引用,想输出自己想要的信息的时候,一般要重写toString()

 public class Student{
  public String  name;
  public int age,id;
  public Student (String  name,int age,int id) {
      this.name = name;
      this.age = age;
      this.id = id;
  }
  //重写toString ()方法
  public String  toString () {
      return "name:"+name+"age:"+age+"id:"+id;
  }
 }
 public class Test{
  Student s = new Student ("张三",18,16101);
  System.out.println(s);
 }

运行:
name:张三age:18id:16101
equals()
1、String类型有自己的equals(),比较的是两个字符串的内容是否相同
2、Object的equals():

public boolean equals(Object obj) {
     return (this == obj);
}

实际上只是用“==”比较,“==”比较是地址和内容
什么时候重写equals()
当我们要判断两个对象的内容是否相等时(忽略地址),一般需要重写equals()方法
重写equals(),一定要重写HashCode()
根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”
注意:在处理set及对象的时候,hashcode和equals方法是一起都要写的,equals和hashcode方法的关系是这样的,如果两个对象相同既用equals对象比较返回true,那么他们的hashcode值一定相同;如果两个对象的hashcode相同,他们并一定相同,也就是说hashcode即使一样的话,即使用equals比较的话也有可能返回false,hashcode是取了因子的ID,但是equals又取了多个元素去比较。在工作中如果用set集合去处理的话,最好用equals和hashcode都重写,并且保证里面的判断因子是一样的,这样可以避免很多意想不到问题。

相关文章

网友评论

      本文标题:001 String

      本文链接:https://www.haomeiwen.com/subject/sdsjehtx.html