JVM String类
面向对象:
1.
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
2. 三大特征:封装,继承,多态
虚拟机 JVM内存结构:主要的部分可分为三部分:栈 ,堆 和 方法区三部分
画内存图可以根据程序执行的顺序就推算出程序结果,有助于调试程序
-
方法区:
类加载器classloader,将硬盘上的 .class 字节码文件装载到 JVM 的时候,会将字节码文件放到方法区,就是说方法区存储的是代码片段。
类是最先加载,所以方法区当中最先有数据 -
栈(stack)内存
数据结构通常是指存储数据的容器,该容器可能存在不同的结构;数据结构就是一门独立的学科,与之搭配的是各种算法
栈数据结构:
数据进栈又叫数据压栈(push)数据出栈又叫数据弹栈(pop)特点是先进后出
栈帧:永远指向的是栈顶部的元素
处于栈顶部的元素具备活跃权
类加载后,会去执行main方法,在方法被调用的时候,该方法需要的内存空间在栈中被分配,以及会有该方法的局部变量
方法只有被调用的时候,才会在栈中分配空间,并且调用时就是压栈,方法执行结束时,该方法所需要的空间就会释放,此时是弹栈 -
堆内存
当new对象时,对象名放在栈中
String(字符串)类
- String类是 Java 的 JDK 中内置的一个类:java.lang.String (此包使用时不需要导包,直接使用就行)
- String表示字符串类型,属于引用数据类型
- 在java中用双引号括起来的都是String对象,并且,双引号括起来的字符串是不可变的
4.在 Java 的 JDK 中 双引号括起来的字符串是直接存储到方法区的字符串常量池当中的,是因为字符串在实际开发中使用的过于频繁,便于提高效率
1.String字符串的存储原理:
public class Text {
public static void main(String[] args) {
String s1 = "abcd";
String s2 = "abcd" + "xy";
}
}
/*分析:
* 1. 在 JVM 中的方法区进行类加载,Text.class 和 String.class 等代码片段,静态变量
* 2. main 方法在栈中压栈,形成main方法栈帧
* 3. 在方法区的字符串常量池中,保存了"abcd",向右赋值给s1,指的是在main方法栈帧中有局部变量String类型的 s1
* 其中保存的是"abcd"在字符串常量池中的内存地址;
* 4. 因为字符串有不可变性,对于"abcd" + "xy",直接将"abcd"拿过来进行拼接成"abcdxy",向右赋值给s2,在main方法栈帧中有局部变量String类型的 s2
*其中保存的是"abcdxy" 在字符串常量池中的内存地址*/
public static void main(String[] args) {
String s3 = new String("abcd");
}
}
/*分析:
1. new 对象的时候一定在堆内存中开辟了空间,名为String 对象的空间保存的是"abcd"在字符串常量池中的内存地址
* 2. 在main方法栈帧中有局部变量String类型的 s3保存的是String 对象在堆内存中内存地址*/
汇总:
public class Team {
public static void main(String[] args) {
User u = new User(1111,"xiao");
}
}
class User{
int id;
String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
/*分析:
* 1. 在 JVM 中的方法区进行类加载,Team.class,String.class,User.class 等代码片段,静态变量
* 2.main 方法在栈中压栈,形成main方法栈帧
* 3.new 对象的时候在堆内存中开辟了空间,名为User类型对象的空间保存的是int型 id的值是1111
* String 类型的name保存的是"xiao"在字符串常量池中的内存地址
* 4.main方法栈帧中有局部变量User类型的u,保存的是指向堆内存中的User类型对象的内存地址
* */
public class Test {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);//true
// 分析:"hello"保存在方法区的常量池中,在栈的main方法栈帧中的s1中保存的是
// "hello"保存在方法区的常量池中的内存地址;之后在s2中保存的也是同一个hello的内存地址
// == 比较的是引用对象的内存地址
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3==s4);//false
// 分析:在堆中的两个new 对象中保存的是"hello"保存在方法区的常量池中的同一个内存地址
// 但在栈的main方法栈帧中的s3和s4中保存的是各自的指向堆中对象的内存地址,不同
System.out.println(s3.equals(s4));//true
// 说明String类已经重写了equals方法,
System.out.println("hello".equals(s4));//true
// 因为双引号括起来的就是一个String类,
// 写时不建议直接 System.out.println(s4.equals( "hello"));
// 有效避免空指针异常
// String k = null;
// System.out.println(k.equals( "hello"));
// 空指针异常:java.lang.NullPointerException
// int i=100;
// 在i 中保存的就是100;
String s5 = "hello";
// 在s5中保存的就是内存地址
System.out.println(s1.toString()); //hello
// 说明:String类已经重写了toString()方法,
// 直接输出引用时,会默认调用他的toString()方法,
System.out.println(s1);//hello
}
}
2.String构造方法:
class Tect {
//1.String a = "xxx";
//2.String b = new String("xxx");
//3.String c = new String (char数组);
//4.String d = new String (char数组,起始下标,长度);
//5.String e = new String (byte数组);
//6.String d = new String (byte数组,起始下标,长度);
public static void main(String[] args) {
byte[] e={97,98,99};
String s1 = new String(e);
System.out.println(s1);//abc
String s2 = new String(e,1,2);
System.out.println(s2);//bc
char[] d ={'1','2','3','4'};
String s3 = new String(d);
System.out.println(s3);//1234
String s4 = new String(d,1,3);
System.out.println(s4);//234
}
}
3. String方法:
public class Text {
public static void main(String[] args) {
// 方法1. char charAt(int index) 返回指定索引处的字符
char c = "hello".charAt( 1);
System.out.println(c);//e
// 方法2. int compareTo(String anotherString) 按字典顺序比较两个字符串,可以看出谁大谁小
// 从前依次比较各个字符串中的字符,遇到第一个不同的字符,直接比较,不再往下比了
System.out.println("he".compareTo("ha"));//4 e在字典中比a的序号大于4
System.out.println("hep".compareTo("hab"));//4
System.out.println("he".compareTo("he"));//0 两个字符串相等
// 方法3. boolean contains(String) 判断前面的字符串是否包含后面的字符串
System.out.println("heell".contains("ee"));//true
// 方法4. boolean endsWith(String) 判断前面的字符串是否以后面的字符串结尾
System.out.println("abxd".endsWith("ad"));//false
// 方法5. boolean equals(Object obj) 判断两个字符串相等
System.out.println("heell".equals("ee"));//false
// 方法6. boolean equalsIgnoreCase(String) 判断两个字符串相等,忽略大小写
System.out.println("heell".equalsIgnoreCase("Heell"));//true
// 方法7. byte[] getBytes() 将字符串对象转换为字节数组
byte[] bytes = "abcd".getBytes();
for(int i=0;i
相关