JVM String类


面向对象:
1.
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
2. 三大特征:封装,继承,多态

虚拟机 JVM内存结构:主要的部分可分为三部分:栈 ,堆 和 方法区三部分

画内存图可以根据程序执行的顺序就推算出程序结果,有助于调试程序

  1. 方法区:
    类加载器classloader,将硬盘上的 .class 字节码文件装载到 JVM 的时候,会将字节码文件放到方法区,就是说方法区存储的是代码片段。
    类是最先加载,所以方法区当中最先有数据

  2. 栈(stack)内存
    数据结构通常是指存储数据的容器,该容器可能存在不同的结构;数据结构就是一门独立的学科,与之搭配的是各种算法
    栈数据结构:
    数据进栈又叫数据压栈(push)数据出栈又叫数据弹栈(pop)特点是先进后出
    栈帧:永远指向的是栈顶部的元素
    处于栈顶部的元素具备活跃权
    类加载后,会去执行main方法,在方法被调用的时候,该方法需要的内存空间在栈中被分配,以及会有该方法的局部变量
    方法只有被调用的时候,才会在栈中分配空间,并且调用时就是压栈,方法执行结束时,该方法所需要的空间就会释放,此时是弹栈

  3. 堆内存
    当new对象时,对象名放在栈中

String(字符串)类

  1. String类是 Java 的 JDK 中内置的一个类:java.lang.String (此包使用时不需要导包,直接使用就行)
  2. String表示字符串类型,属于引用数据类型
  3. 在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

相关