String类对象的两种实例化方法
String并不是一个基本数据类型,它本身属于一个类。但是这个类在设计的过程之中加入了属于Java的特殊支持,所以对于这个类的对象实例化方式有两种形式
-
直接赋值:
String 对象名称 = "内容";
-
构造方法:
String 对象名称 = new String("内容");
String的相等比较
如果说现在有两个int型的变量,要进行相等的判断,则直接使用“==”即可;如果进行String的比较,我们可先用“=="尝试:
class StringDemo{
public static void main(String[] args){
String steA = "hello";
String steB = new String("hello") ;
String steC = steB;
System.out.println(steA == steB);//false
System.out.println(steB == steC);//true
System.out.println(steA == steC);//false
}
}
发现结果并不相等,此时我们发现问题,字符串的内容实际上都是一样的,而在使用“==”比较结果是,具体原因如下图所示:
- 发现在程序中如果使用“==”比较的只是两个对象(任意的引用类型),并不是对堆内存中保存的内容进行比较
- 如果想要在
String
类中进行比较,那么可以利用String
类中提供的public boolean equals(String str);
方法进行比较
代码如下:
class StringDemo{
public static void main(String[] args){
String strA = "hello";
String strB = new String("hello") ;
String strC = strB;
System.out.println(strA.equals(strB));//true
System.out.println(strB.equals(strC));//true
System.out.println(strA.equals(strC));//true
}
}
面试题:请解释在String比较中”==“与"equals()"的区别
- "=="是java的一种关系运算符,可以进行数值比较,如果用在String上时则是对堆内存地址数值进行比较,使得结果错误
- "equals()"是String类的一个方法,用于进行字符串内容的比较
String匿名对象
任何的编程语言都不会提供有字符串这一数据类型,字符串的描述在很多语言之中都是用字符数组表示,而在Java的设计之初为了解决这样的问题,专门提供了一个String类来进行描述。但是随着发展,为了能够让程序变得更加的易于开发,所以在Java里面也提供双引号声明的数据,而这些数据,在Java中并不是普通的变量,而是String类的匿名对象
String 字符串对象 = "字符串";
本质:就是为一个字符串的匿名对象起了一个名字
String类两种实例化对象的区别(核心)
此时对于String类的声明方式有两种,那么这两种方式到底应该使用哪一种,以及每种方式的区别
分析String类对象直接实例化的形式
开辟一块堆内存空间,并且开辟一块栈内存空间将直接指向该堆内存
观察以下代码:
class StringDemo{
public static void main(String[] args){
String strA = "hello";
String strB = "hello";
String strC = "nihao";
System.out.println(strA == strB);//true
System.out.println(strB == strC);//false
System.out.println(strA == strC);//false
}
}
内存关系图如下:
关于对象池的概念(Object Pool):
-
为了更方便用户的代码编写开发,针对于几个特殊的类使用了共享设计的思路,其中String类属于这其中的一员。这种设计思路是Java自己的支持,而且只针对于直接赋值的情况
-
在使用直接赋值实例化String类对象的操作之中,字符串的内容定义之后实际上会自动将其保存在一个对象池之中,而后如果现在有其他的字符串对象也采用了直接赋值的形式,并且内容与之前的字符串内容完全相同,那么不会开辟新的堆内存空间,而是会通过对象池找到已有的堆内存空间地址,直接引用即可
回到上方的疑问:由于对象池的存在,当若干个字符内容相同时,地址是完全相同的,所以“==“的结果也是相同的,这样的设计就是共享设计模式
分析String类利用构造方法实例化对象的形式
代码如下:
class StringDemo{
public static void main(String[] args){
String str = new String("hello");
System.out.println(str);
}
}
内存关系图如下:
内存关系图分析以上情况:
-
通过此时的内存分析可以发现,如果采用了构造方法进行String类对象的实例化操作,那么最终会产生两块堆内存,其中一块是垃圾空间
-
如果使用了构造方法进行String类对象实例化,那么所产生的的对象将不会保存在对象池之中(此对象无法重用),如果用户需要其入池,只能通过
public String intern();
手工入池
面试题:请解释String类两种对象实例化的区别
-
直接赋值
String str = "字符串";
:只会开辟一块堆内存,且对象可以自动入池以供重复使用 -
构造方法
String str = new String("字符串");
:会开辟两块堆内存,且其中一块为垃圾空间,由构造方法声明的实例化对象不能自动入池,需要调用intern()
方法手动入池
字符串一旦声明不可改变
观察以下代码:
class StringDemo{
public static void main(String[] args){
String str = "hello ";
str += "world";
str += "!!!";
System.out.println(str);
}
}
分析内存关系:
内存关系图可以发现整个的操作流程之中,都是String类对象的引用发生着改变,而字符串本身的内容并没有改变,这样的操作会产生大量垃圾,因此杜绝使用
总结
-
String类开发中都使用直接赋值,并且不要频繁修改
-
字符串内容比较时使用
equals()
方法
网友评论