String和Integer

发布时间 2023-08-17 10:40:51作者: NorthnightX

Integer

记录一下int和Integer之间相互比较的关系

Int和Integer

在java 5中引入了自动装箱和自动拆箱功能(boxing/unboxing),java可以根据上下文,自动进行转换,极大地简化了相关编程。javac自动把装箱转换为Integer.valueOf(),把拆箱替换为Integer.intValue()。

当我们使用 Integer integerValue = num 的时候,会自动装箱成 Integer integer = Integer.valueOf(num) ,如果num的数值小于128,则会从缓存中获取,如果大于的话会构造一个新的Integer对象(new Integer)

int与int比较

int数据类型,都是在栈内存中存储,如果这个数字在栈内存中存在就会直接指向这个内存地址,如果不存在,就会重新开辟内存空间,所以int和int类型的比较,相同的值不会存在内存不等的情况

    int intValue = 234;
    int intValue2 = 234;

int和Integer比较

这两个数据的相互比较,无论是谁和谁比,都最终比较的是存在栈中的值,因为int是基本数据类型,不能在对中创建数据,所以无论咋比较,都是将堆中的Integer拆箱为int类型的数据,然后进行比较
int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比较

    int intValue = 234;
    Integer integerValue = 234;

Integer和Integer比较

当两个Integer都是new出来的时候

int1 和 int2 是通过构造函数创建的不同实例,因此它们的地址值不同。(Java9以后弃用)

    Integer int1 = new Integer(42);
    Integer int2 = new Integer(42);
    System.out.println(int1 == int2);  // false

只有一个Integer是new的

    Integer integer = new Integer(42);
    Integer integer1 = 42; //小于128,从缓存中获取
    System.out.println(integer1 == integer);  // false

都不是new的

    Integer integer = 100;
    Integer integer1 = 100;
    System.out.println(integer1 == integer); //true,小于128,从缓存中获取
    Integer integer2 = 666;
    Integer integer3 = 666;
    System.out.println(integer3 == integer2); //false,大于127,构造新的Integer对象

String

image
来自官方的一段注解,这段意思是:String 类表示字符串。 Java 程序中的所有字符串(例如“abc”)都是作为此类的实例实现的。字符串是不变的;它们的值在创建后就无法更改。字符串缓冲区支持可变字符串(StringBuffer)。因为 String 对象是不可变的,所以它们可以共享。

例如:

String str = "abc";

等价于:
char data[] = {'a', 'b', 'c'};String str = new String(data[]);

也就是,这两种方式都可以用来创建包含相同字符序列 "abc" 的字符串对象。但是其实这两种的创建方式的内部实现有所差异。

再来看一段源码:

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

这段代码是String的构造函数之一,当我们new这个String的时候

String str = new String("Hello, World!");

会调用上方的构造函数,将传入的字符串作为原始字符串,并以此创建一个新的字符串对象,也就是相当于

String str1 = "Hello, World!";
String str2 = new String(str1);

换句话说,新创建的字符串是参数字符串的副本

String的赋值的两种方式

String str = new String("Hello, World!");

第一种方式:通过关键字new定义:编译程序先在字符串常量池查找,是否存在"Hello, World!"常量,如果不存在,则在字符串常量池开辟一个内存空间,存放"Hello, World!";如果存在,则不另外开辟空间,保证字符串常量区只有一个"Hello, World!",节省空间。然后在堆区,开辟一个空间,存放new出来的String对象,并在栈区开辟空间,存放变量名称str1,str1指向堆区new出来的String对象。

String str1 = "Hello, World!";

第二种方式:直接定义:在字符串常量区查找是否存在"Hello, World!"常量,如果不存在,则在字符串常量区开辟一个内存空间,存放"Hello, World!";如果存在,则不另外开辟空间;在栈区开辟空间,存放变量名称str2,str2指向字符串常量池"Hello, World!"的内存地址。

StringBuffer和StringBulider

String s1 = "a";
String s2 = "b";
String s3 = s1+s2;
String s4 = "ab";
System.out.println(s3==s4); //false

因为String是不可变的,所以s3是s1+s2使用StringBuilder的append方法进行拼接,然后通过StringBuilder的toString方法返回"ab"

//StringBuffer的私有的数组,用于toString方法(为了线程安全),StringBuilder则使用父类的value数组直接toString
private transient char[] toStringCache;
//将StringBuffer的value数组(来自父类AbstractStringBuilder),copy到toStringCache,并将使用toStringCache作为参数new一个新的String对象
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}
//String对应的构造函数,传入的是数组而并非String,不会在常量池创建字符串
String(char[] value, boolean share) {
    // assert share : "unshared not supported";
    this.value = value;
}

字符串拼接

+号拼接

String str1 = "hello";
String str2 = "world";
String result = str1 + str2;

会被编译器优化成String result = new StringBuilder().append(str1).append(str2);

常量字符串的拼接,编译器会做优化,使用String就可以:

String str = "Java" + "PHP" + "Python" + "C";

StringBuffer或者StringBuilder的append方法(supper.append)

和String的concat差不多

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count) //从strstr中复制字符到一个字符数组value,String的getChars方法内部调用System.arraycopy(native方法)
    count += len;
    return this;
}

String的concat方法

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

String的intern方法

当调用 String.intern() 方法时,如果常量池中不存在该字符串,它会将字符串添加到常量池中,并返回常量池中该字符串的引用。如果常量池中已经存在该字符串,它会返回常量池中的引用,而不会创建新的字符串对象。

String str1=new StringBuilder("this is ").append("a string").toString();
//执行完这行代码后,常量池中会有"this is "和"a string",但是不会有"this is a string"。
System.out.println(str1.intern()==str1);//true
String str2=new String("this is a string");
System.out.println(str2==str2.intern());//false
System.out.println(str2 == str1); //false
str1 = str1.intern();
str2 = str2.intern();
System.out.println(str1 == str2); //true