目录
1. 字符串
1. 字符串创建
2. 实例化的区别
I. 直接赋值
II. 构造方法
3. 字符串比较
4. 字符串的修改
5. String类总结
【String类方法 】String 类是Java类中最常用用的类,记录一下 String类的对象实例以及String常用的一些方法
1. 字符串
【字符串的特点】
- 字符串内容永不可变
- 字符串可以共享使用【在常量池中】
- 字符串,字符数组,底层原理是byte[ ]字节数组
1. 字符串创建
直接赋值
这种赋值方式最为常用。
但是String本身毕竟是一个类,既然是类,那么类中一定存在构造方法。String类也不例外,String类的其中一种构造方法如下:
public String(String str);
构造方法创建
1. public String( ) :默认构造方法创建字符串
String msg = new String();
2. 根据字符数组创建字符串
3. 根据字节数组创建字符串(字符串底层其实还是字节存储)
2. 实例化的区别
I. 直接赋值
- 对于基本类型来说:== 是数值的比较
- 对于引用类型来说:== 是地址值的比较
内存图详解:
为什么现在并没有开辟新的堆内存空间呢?
直接赋值会把创建的字符串放到字符串常量池中,只有通过构造方法new出来的,每次才会开辟新空间。
常量优化机制:
String类的设计使用了共享设计模式
在JVM底层实际上会自动维护一个对象池(字符串对象池),如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。
- 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用;
- 如若没有,则开辟新的字符串对象而后将其保存在对象池之中,以供下次使用(目的就是减少开销)
- 所谓的对象池就是一个对象数组
II. 构造方法
类对象使用构造方法实例化是标准做法
String str = new String("hello");
通过分析可知,如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间。除了这
一缺点之外,也会对字符串共享产生问题。
面试题:请解释String类中两种对象实例化的区别
- 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
- 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern()方法手工入池。
因此,一般会采取第一种方式即直接赋值即可......
3. 字符串比较
- ==
- equals()
== 本身是进行数值比较的,如果现在用于对象比较,那么所比较的就应该是两个对象所保存的地址值比较,而并没有比较对象的内容
那么要想比较内容比较,则必须采用String类提供的equals方法。
使用equals方法比较字符串内容:
Object类equals方法的覆写
用equals( )来比较对象内容是否相同:
两个对象stu1 和 stu2 的内容明明相等,应该是true呀?怎么会是false?
因为此时直接调用
equals()
方法默认进行比较的是两个对象的地址。new一下就会在堆上创建新空间,地址自然不会相同,所以为false
我们在判断的是字符串的内容是否相等时,直接用 str1.equals(str2);
但是在判断两个对象是否相等时,比如要判断一个Person类的两个对象的姓名是否相同时,此时要重新覆写equals( )
面试题:请解释String类 == 与equals 的区别
- " == ":引用类型进行的数值比较,比较的是两个字符串对象的内存地址数值
- "equals( )":可以进行字符串内容的比较
在Java中,本身也没有直接提供字符串常量的概念,所有使用 " " 定义的内容本质上来讲都是String的匿名对象
观察字符串常量:
那么在之前出现的String str = "Hello",本质上就是将一个匿名的String类对象设置有名字,而且匿名对象一定保存在堆内存中。
PS :
String str = null ; // 假设由用户输入
System.out.println(str.equals("Hello"));
在进行接收用户输入数据的时候一定要考虑到用户没有输入的问题,用户没有输入的时候,一定会出现 NullPointerException 问题
所以应当改为:
常量的字符串内容放在前面,来避免空指针异常:
System.out.println("Hello".equals(str));
4. 字符串的修改
String类是不可变类,String类的对象一旦被创建,其值将不能被改动
但实际情况是
此处str却是被修改过了,这是为什么呢?
可以发现字符串上没有发生任何变化,但是字符串对象的引用一直在改变,而且会形成大量的垃圾空间
String字符串修改实现原理:
当用String类型来对字符串进行修改时,首先是创建一个StringBuilder,其次调用 StringBuilder 的 append( ) 方法,最后掉调用StringBulider 的 toString( )将结果返回
示例如下:
等价于
str字符串的内容不可改变,改变的是引用的地址值
5. String类总结
面试题:
Q: String类能不能被继承,有没有子类?
String类被final修饰,其不能被继承,所以没有子类
Q1: s1 与 s2 是否相等?
- true
- true
Q2: s1 与 s2 是否相等?内存中共有几个abc?
- false
- true
- 内存中有两个abc,一个在堆区,一个在常量池中
Q3: s1 与 s2 是否相等?
- true
- true
这便是Java的常量优化机制。Java程序时半编译半解释性语言,先将 .java 文件编译成 .class 字节码文件,最后再执行。区别于编译型语言,直接将源代码翻译成二进制的机器码。在编译成 .class 文件后,s1 与 s2 的内容是相同的,所以只是引用改变了而已。
Q4: s1 与 s2 是否相等?
- false
- true
s1,s2是变量,而 s3 则是变量.