以/**开始叫文档注释
当java中用双引号""创建这么一个字符串的时候,那java就会在堆里面创建一个String类型的这么一个字符串,然后这个字符串,它结构是这样的,这字符串里面主要有一个属性value,value是char[]数组类型,那这个数组怎么回事呢?
这么做的。数组肯定是个对象,是个引用,它引用了什么?它引用了一个数组类型的这么一个对象(char[]),
这个对象数组类型的,然后这个数组中放了字符A B C 三字符
字符串底层封装了一个什么?字符数组
之后把它的字符串引用交给s1,那我们就会在栈里面定义一个变量叫s1,而s1的值引用了对象
那为什么s1这个变量放栈里?因为是main方法中声明的变量
记住:方法中声明的所有变量都是放在栈里的,而对象都在堆里
提问:是不是所有引用变量放栈里?错误,比如上图s1是个引用变量,在栈里,value是个引用变量,在堆里
value也是个引用类型变量,它引用了一个char[]数组
String s2=s1;//把s1的引用传给s2,s2是个新变量,也是在新方法中声明的,那s2的值是什么?是s1的值交给s2
这样s1和s2具有相同的对象的首地址,那这样s2的值它也引用同一个对象
s1=s1+"DEF";
java的加法其实在底层,它是做一个字符串的合并,就是这个结构又出现了一遍,但是这个时候,它不叫ABC里面放的是DEF,
也就是先算"DEF",再去画加法
这是第二个字符串,而这个连接是把他连接在一起,而数组长度能改变吗?不能
那现在我希望生成个新字符串,里面那个数组啊是前面两个数组和,所以java在底层对数组进行扩容了,就是java
又创建一个字符串,而这个字符串引用一个新数组,这个数组就是一个扩容的数组,扩容以后,新数组的长度是两个数组长度的和,
然后把这个复制以后的结果,这个对象的引用交给value
扩容以后把ABCDEF复制过来,然后把复制以后的这个结果,这个对象的引用交给value
字面量:就是直接写的,比如"ABC",123,直接写死的,
常量:解释双等号的问题==
在这里a的值是5,b的值是5,那a跟b相等,其实就是底下的一个二进制相等
比较结果显然是true
String字面量的缓存重用现象
String s1 = "ABC";
String s2 =s1;
System.out.println(s1==s2);
结果为true://这个true什么意思?
是s1的地址值和s2的地址值一样
也说明是s1和s2引用同一个对象
那现在我要定义一个字符串,s3,让他也等于字面量"ABC"
这个时候java就会怎么做呢?是这样的,因为第一次创建"ABC"的时候,java会把ABC的引用放到常量池里边
缓存起来了
再用的时候,Java进到池里去找,用旧的
s1==s3
java凡是看到这种字面量"ABC",就会在堆里创建一个数据结构---常量池(存的引用)
这个引用它引用了字符串对象
s3的引用从常量池里面拿出来
字符串连接结果不参与优化
不是字面量的不缓存,s6就不是字面量,它是加起来的结果
/**
* String 字符量的缓存重用现象
* 提高字符串的性能!!!节省内存耗用
*
* 1. 直接写出的量称为字面量:"ABC" 5 3.14
* "ABC" 字符串字面量
* 2. Java 为了性能,优化字符串"字面量"对象
* 将String对象引用缓存到常量池.
* 3. 使用相同字符串"字面量"时候, 替换为
* 相同的字符串对象引用
* 4. 字符串常量 和 字面量连接的结果 也作为
字面量优化
比如 public static final String S = "ABC";
//字符串常量和字符串字面量一同优化
System.out.println(S==s1);//true
//"字面量"的连接结果
String s7 = "A"+"B"+'C';// 'C'是字符类型 ,是字符字面量,前面AB是字符串字面量 //"ABC"
那这些字面量连接完了,它也当字符串字面量
为什么?
因为java的编译器,它在编译期间能算的先算了,编译的时候是ABC,运行期间还是ABC,所以编译器事先知道这个运算结果永远就是ABC了,所以编译器在编译阶段把这个字面量连接完了 //"ABC"
但这个是字面量的连接结果
是不是变量?不是,它是字面量,跟刚才的s6不一样,s6是两个变量的连接结果,编译器不管
所以System.out.println(s7==s1);//true
* 5. 其他通过new运算,或者字符串变量连接的
* 结果是新字符串对象,不参与常量池优化
*/
单引号引的数据 是char类型的
双引号引的数据 是String类型的
char定义时用单引号,只能有一个字母,数字。char c='c';
而String用双引号,可以是一个,也可能是多个字母,汉字等。就是所谓的字符串。String s="adsaf";
char只是一个基本类型,而String 可以是一个类,可以直接引用。
比如char c='c';不能直接对c调用方法。
String s="abc"; 这时可以调用s.charAt(0);等方法,因为String是类,这是就是对象的调用了
//经典面试题目:
String s8 = new String("ABCD");
//如上程序运行期间创建了几个字符串对象:
//A.1个, B.2个 C.3个 D.4个
参数先算--"ABCD"
再进行new运算--new就会new一个字符串对象
上图还是稍微有点问题,更正一下,真正的java字符串在底层为了提高效率,为了节省内存
实际上,java连数组都进行重用
字符串里面存的是字符,而每个字符都是Unicode编码
package se1.day01;
public class LengthDemo03 {
public static void main(String[] args) {
/**
* String 类型提供了length()方法
* 返回字符串中字符的个数
*
* 面试点: 数组长度是属性(.length), 字符串长度是方法(通过String自带的length()方法取字符串长度)
*
* length: 长度
*/
String s1 = "Hello 世界!";
// 0123456 7 8
int l = s1.length();
System.out.println(l);//9(0到8)
char c = s1.charAt(6);//按照位置获取字符
System.out.println(c);//世
/**
* getBytes()对字符串进行编码, 并且返回
* 编码以后的结果, 不同编码返回字节数量不同!
* getByte方法返回在字节长度不是内存中
* 实际占用的字节长度! 以后在编码课程专门讲
*/
byte[] bytes = s1.getBytes();//这个getbytes[]不是去取得字符串中我们理解的那个byte
比如一个字符,是一个char,是两个byte----不是这个byte
getBytes()对字符串进行编码, 并且返回编码以后的结果, 不同编码返回字节数量不同!
返回值不是实际内存中存储的字节数,而是内存存储的字符串经过指定的编码,那编码以后那个结果的数量
getByte方法返回在字节长度不是内存中
int l =s1.charAt(6);//按照位置获取字符 //世
char 变量=字符串变量.charAt(数字)
System.out.println(bytes.length);
}
}
----------------------------------------------------------------------------------
检测一个人的姓名中包不包含王字
/**
* indexOf方法
* 在一个字符串中检索指定字符串出现的位置
* 如果找到了字符串,返回字符串的位置,否则
* 返回 -1
*
* 如果一个人的姓名第一个字符是"王"的话,则
* 这个人姓王------从前往后比
*
*/
Scanner in = new Scanner(System.in);
System.out.print("输入姓名:");
// "宋哲"
String name = in.nextLine(); // "王宝强";
// 0 1 2
int n = name.indexOf("欧阳");//"欧阳"
System.out.println(n);
if(n==0){
System.out.println("这位仁兄姓欧阳");
}