前言
字符串:
在C语言里面 是 没有字符串类型的!
但是,在 Java 和 C++ 里,有字符串类型【String】
什么是字符串?什么是字符?
在java里面有表示字符串的类 String
使用双引号,且双引号中包含任意数量的字符【“abcdef”,“a”】,就是字符串。
使用单引号,且单引号中,只包含一个字符【‘a’,‘强’】,就是字符。
注意问题
1、在java中没有以“\0”结尾这种说法,比如说:String str = “abccdef”; ,那这个str字符串里面只要“abccdef”,这几个字符,没有“\0”
2、String 不能被继承
一、创建字符串
1、直接赋值
2、new 对象,调用构造方法
3、将字符数组转换成字符串
1.1、直接赋值
1.2、new 对象,调用构造方法
1.3、将字符数组转换成字符串
在官方文档上https://docs.oracle.com/javase/8/docs/api/index.html我们可以看到 String 还支持很多其他的构造方式, 我们用到的时候去查就可以了
这是怎样去将字符数组转换成字符串的呢???
注意事项
“hello” 这样的字符串字面值常量, 类型也是 String.
String 也是引用类型. String str = “Hello”; 这样的代码内存布局如下
当我们进入String这个类里面,发现了两个属性 private int hash; 和 private final char value[ ]; 这两个属性表示的是什么意思???
看下面一段代码,传引用不能解决一切问题,主要看这个引用做什么
public static void func(String s, char[] array){
s = "gaobo";
array[0] = 'p';
}
public static void main(String[] args) {
String str = "abcdef";
char[] chars = {'b', 'i', 't'};
func(str, chars);
}
1.4、比较两个字符串(地址(==)和内容(equals方法))
例1:比较地址,用引用直接进行比较的时候,比较的是两个的地址,因为是两个不同的对象,所以这结果是false
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1 == str2);
}
比较两个字符串的内容是否相等
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1.equals(str2));
}
1.5、字符串常量池
由双引号引起的字符串就是字符串常量,比如说:“hello” ,“word”
这些由双引号引起的字符串就会放到字符串常量池里面
常见的池有:
-
1、Class常量池:静态常量池,也叫 class文件常量池,主要存放编译期生成的各种 字面量(Literal)和符号引用(Symbolic References) 。
字面量:例如文本字符串、fina修饰的常量。
int b = 2; int c = "abcdefg";
符号引用:例如类和接口的全限定名、字段的名称和描述符、方法的名称和描述符 -
2、运行时常量池:当类加载到内存中后,JVM就会将class常量池中的内容存放到运行时常量池中;运行时常量池里面存储的主要是编译期间生成的字面量、符号引用等等。
类加载在链接环节的解析过程,会符号引用转换成直接引用(静态链接)。此处得到的 直接引用 也是放到运行时常量池中的。
运行期间可以动态放入新的常量。 -
3、字符串常量池:字符串常量池,也可以理解成运行时常量池分出来的一部分。类加载到内存的时候,字符串会存到字符串常量池里面。利用池的概念,避免大量频繁创建字符串。字符串常量池本质上是一个哈希表(StingTable)
-
4、数据库连接池
-
5、线程池
各种池,这些池有什么用???
提高效率!这么说吧,当你要创建一个数据的时候,如果池里面有那你就不用创建了,直接去池里面拿来用,这样就提高效率了,因为创建数据的时候也会浪费时间和空间
1.6、了解哈希表
唯一的不同就是,池里面的东西,是可以重复使用的,也就是说不同的字符串类型,池子里就需要一个就够了。如果一个程序里,前面和后面都用到相同的字符串,请不要怀疑,就是同一个字符串。
实例1:解析比较两个字符串是否相同
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1 == str2);
}
JDK1.8之后,哈希表是放在堆里面的
实例2
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
}
实例3
public static void main(String[] args) {
String str1 = "hello";
String str2 = "he" + "llo";
System.out.println(str1 == str2);
}
String str2 = “he” + “llo”; ,此时这个在编译的时候,就编译成"hello ",所以此时还是双引号的hello,那都是同样的常量,所以结果是true
我们可以验证一下,打开powershell 窗口,反编译一下
输入命令:javap -c + 文件名
实例4
public static void main(String[] args) {
String str1 = "hello";
String str2 = "he";
String str3 = str2 + "llo";
System.out.println(str1 == str3);
}
实例5
public static void main(String[] args) {
String str1 = "11";
String str2 = new String("1")+ new String("1");
System.out.println(str1==str2);
}
String str2 = new String(“1”)+ new String(“1”);
此时拼接好的 str2 还没有入池
实例6
public static void main(String[] args) {
String str2 = new String("1")+ new String("1");//str2还没有入池
String str1 = "11";
System.out.println(str1==str2);
}
实例7,手动入池
如果 我在程序中,在 str2后面加上一句代码 str2.intern(); 呢?
intern() 的作用:将它的调用者,手动入池。
public static void main(String[] args) {
String str2 = new String("1")+ new String("1");//str2还没有入池
str2.intern();//手动入池
String str1 = "11";
System.out.println(str1==str2);
}
1.7、数组的整体赋值 ,在Java中,只有一次机会,就是在定义数组的时候
例1
例2
例3、被final修饰的数组,指向是不能改的
1.8、理解字符串不可变
字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 但是 String 类并没有提供 set 方法之类的来修改内部的字符数组
1.8、String 类型的数据,可以通过反射修改
还是上一个程序,如果我非要把字符串"abcde"的 a 改成 g 呢?
可以,前面我们也看到,String类型的数据,是数组的形式存储在对上,既然是数组,那么我们可以通过下标去修改它,
但是问题是 value 的权限是private 是 私有的
所以,即使我们拿到了对象,都拿不到value的
但是 反射 就可以走到,反射的功能异常强大。
反射 是什么?
举一个很形象的例子:
我们每次坐地铁,我们所带的行李箱,都需要进过安检,了解过的都知道,安检的机器,会发射一中光谱的曲线,通过反射,就能知道我们的行李箱中装了什么东西。从这里就体现出了 “反射” 的 概念
这里是类比一下, 通过"反射"。我们能看到类里面存储的一些属性,哪怕是私有的,又或者是上锁了。我都能看到,
也就是说:通过反射,我们能获取其中所有信息。