- String类得两种实例化方式
(1)直接赋值 String 变量="字符串"; (2)构造方法实例化 public String(String str),在构造里面依然要接收一个String类对象; - 字符串的比较 字符串对象使用"=="比较的问题:"=="在String比较时比较的只是内存地址的数值,并不是内容。
引用类型都可以使用"=="比较,在整个Java中只要是引用数据类型一定会存在内存地址,而"=="可以用于所有的引用数据类型的比较,但比较的不是内容,永远都只是地址的数值内容。
- 如果要比较字符串的内容,可以使用String类里面定义的方法,内容比较操作(区别大小写)语法如下: public boolean equals(String str);
- 实现字符串内容比较 package oop;
public class StringDemo {
public static void main(String[] args) {
//直接赋值字符串定义
String stra="hello";
String strb=new String("hell0");
String strc=strb;
System.out.println(stra.equals(strb)); //比较结果true
System.out.println(stra.equals(strc)); //比较结果true
System.out.println(strb.equals(strc)); //比较结果true
}
}
- 解释String类中"=="和"equals()"比较的区别:
- "=="是Java提供的关系运算符,主要的功能是进行数值相等判断,如果用在String对象上表示的是内存地址数值的比较
- "equals()"是由String提供的一个方法,此方法专门负责进行字符串内容的比较
- 字符串常量就是String的匿名对象字符串数据实际上是作为String类的匿名对象的形式存在的观察字符串是匿名对象的验证 package oop;
public class StringDemo {
public static void main(String[] args) {
String str="hello";
System.out.println("hello".equals(str)); //比较结果为true
}
}
本程序最大的特别在于直接利用字符串"hello"调用equals()方法,由于方法是String类定义的,而类中的方法只要实例化对象之后才能使用,那么就得出一个结论:字符串常量就是String类的匿名对象
所谓的String类对象直接赋值的操作,实际上就相当于给一个匿名对象设置一个名字,但是唯一的区别是,String类的匿名对象是由系统自动生成的,不再由用户直接创建 。
- 两种实例化方式的区别
(1)分析直接赋值实例化String类对象的情况
直接赋值就是将一个字符串的匿名对象设置了一个名字,其语法如下: String 变量=字符串常量(匿名对象); String str="hello"; 使用String类对象实例化只会开辟一块堆内存空间,而除了这一特别外,利用直接赋值还可以实现堆内存空间的重用,即采用直接赋值的方式,在相同内容的情况下不会开辟新的堆内存空间,而会直接指向已有的堆内存空间。 - 观察直接赋值时的堆内存空间自动引用: package oop;
public class StringDemo {
public static void main(String[] args) {
String stra="hello";
String strb="hello";
String strc="hello";
String strd="abcde";
System.out.println(stra.equals(strb)); //判断结果true
System.out.println(stra.equals(strc)); //判断结果true
System.out.println(strb.equals(strc)); //判断结果true
System.out.println(stra.equals(strd)); //判断结果false
}
}
由于直接赋值的实例化操作方法,设置内容相同,所以即使没有直接发生对象的实例化操作,也都会指向同一块堆内存空间,但如果直接赋值时内容与之前不一样,则会自动开辟新的堆内存空间
- String类采用的设计模式为共享设计模式:
在JVM的底层实际上会存在一个对象池(不一定保存的String对象),当直接赋值的方法定义一个String类对象时,会将字符串对象所使用的匿名对象入池保存。如果只会其他的String类对象也采用直接赋值的方式,并且设置了同样的内容,将不会开辟新的堆内存空间,而是使用已有的对象进行引用的分配,从而继续使用
(2)分析构造方法实例化String类对象的情况
语法如下: String str=new String("hello"); 因为每一个字符串常量都是String类的匿名对象,所以本代码的含义是,根据"hello"这个匿名对象的内容,创建了一个新的String类对象
使用构造方法实例化String类对象,由于关键字new永远表示开辟新的堆内存空间,所以其内容不会保存在对象池中。
- 如果希望开辟的新内存数据也可以进行对象池的保存,那么可以采用String类定义的一个手工入池的操作
语法如下: public String intern();
- 手工入池: package oop;
public class StringDemo {
public static void main(String[] args) {
String stra=new String("hello").intern();
String strb="hello";
System.out.println(stra.equals(strb)); //判断结果true
}
}
- 解释String类的两种对象实例化方式的区别:
- 直接赋值(String str="字符串";):只会开辟一块堆内存空间,并且会自动保存在对象池中以供下次重复使用
- 构造方法(String str=new String("字符串");):会开辟两块堆内存空间,其中有一块空间将成为垃圾,并且不会自动入池,但是用户可以使用intern()方法手工入池。
在所有开发中,String对象的实例化永远都采用直接赋值的方法完成
- 字符串一旦定义则不可改变修改字符串对象引用 package oop;
public class StringDemo {
public static void main(String[] args) {
String str="Hello";
str=str+"World";
str+="!!!";
System.out.println(str);
}
}
输出结果: HelloWorld!!! 只是String类的对象引用发生了改变,而字符串的内容并没有发生改变
- 在进行String类对象的修改时,实际上原始的字符串都没有发生变化(最终没有引用的堆内存空间将成为垃圾空间),而改变的只是String类对象的引用关系。所有可以得出结论:字符串一旦定义将不可改变。