JVM String类(JVM string class)

面向对象:
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<bytes.length;i++) {
			System.out.println(bytes[i]);//97 98 99 100
		}
		
		
//		方法8. int indexOf(String) 判断某个子字符串在当前字符串中第一次出现处的索引,从左往右查找
		System.out.println("abcdefcd".indexOf("cd"));//2
		System.out.println("abcdefcd".indexOf("d"));//3
		
		
//		方法9. boolean isEmpty()  判断某个字符串是否为空
		System.out.println("abcdefcd".isEmpty());//false
		
//		方法10.  int length() 判断某个字符串的长度
		System.out.println("abc".length());//3
//		与数组的长度不同,数组是length属性,字符串的长度是调用方法.length()
		
		
//		方法11. int lastIndexOf(String) 判断某个子字符串在当前字符串中最后一次出现处的索引,从右往左查找
		System.out.println("abcdefcd".lastIndexOf("cd"));//6
		
		
//		方法12. String replace(CharSequence target,CharSequence replacement) 返回一个新的字符串, 
		//String 的父接口就是CharSequence
		System.out.println("abcdefcd".replace("cd","ww"));//abwwefww
		
//		方法13. String[] split("分隔符"),将字符串以分隔符进行拆分,各部分以String数组的形式存储
		String[] s = "2021-11-24".split("-");
		for(int i=0;i<s.length;i++) {
			System.out.println(s[i]);//2021  11  24
		}
		
//		方法14. boolean startsWith(String) 判断前面的字符串是否以后面的字符串开始
		System.out.println("abxd".startsWith("ad"));// false
		
//		方法15.  String substring(int beginIndex)  从起始索引截取字符串,
		System.out.println("abxd".substring(1));//bxd
		
//		方法16.  String substring(int beginIndex, int endIndex)  从起始索引到结束索引截取字符串,
		//包含起始索引,不包含结束索引,左闭右开
		System.out.println("abxd".substring(0,2));//ab
		
//		方法17.   char[] toCharArray()  将字符串转换为char数组
		char[] a = "你啊你".toCharArray();
		for(int i=0;i<a.length;i++) {
			System.out.println(a[i]);//你 啊 你 
		}
		
//		方法18.   String toLowerCase()  将字符串中的字符都转换为小写
		System.out.println("ACD".toLowerCase());//acd
		
		
//		方法19.   String toUpperCase()  将字符串中的字符都转换为小写
		System.out.println("acd".toLowerCase());//acd
		
//		方法20.  String trim()   去除字符串的前后空白,中间的不会哟
		System.out.println("  hei hei  ".trim());//hei hei
		
 
		//		方法21. valueOf(参数)  将不是字符串的转换为字符串
//		是String中唯一的一个静态方法,不需要new对象,直接类名调用:String.valueOf(参数)
		 
		System.out.println(String.valueOf(100));//100
		
//		valueOf的源码
//		public static String valueOf(Object obj) {
//			return (obj==null) ? "null" : obj.toString();
//		}
		
//      同时,在输出语句System.out.println中的println方法,也就是会调用valueOf方法,
//		而valueOf方法又调用了toString()方法
//		所以println方法输出时会以字符串输出
		
		
		
	}
}
————————

object-oriented:
one
OOA: Object Oriented Analysis
Ood: Object Oriented Design
OOP: Object Oriented Programming
2. Three characteristics: encapsulation, inheritance and polymorphism

Memory structure of virtual machine JVM: the main part can be divided into three parts: stack, heap and method area

Drawing memory diagram can calculate the program result according to the sequence of program execution, which is helpful to debug the program

  • Method area:
    When the classloader loads the. Class bytecode file on the hard disk into the JVM, it will put the bytecode file into the method area, that is, the method area stores code fragments.
    Class is loaded first, so there is data first in the method area
  • Stack memory
    Data structure usually refers to the container for storing data, which may have different structures; Data structure is an independent subject, which is matched with various algorithms
    Stack data structure:
    Data in stack is also called data push stack. Data out stack is also called data pop stack. It is characterized by first in and last out
    Stack frame: always point to the element at the top of the stack
    The element at the top of the stack has active rights
    After the class is loaded, it will execute the main method. When the method is called, the memory space required by the method will be allocated in the stack, and there will be local variables of the method
    Only when a method is called will it allocate space in the stack, and when it is called, it will press the stack. At the end of method execution, the space required by the method will be released. At this time, it is time to pop the stack
  • Heap memory
    When a new object is, the object name is placed on the stack

String class

  • The string class is a built-in class in Java’s JDK: java.lang.string (this package does not need to be imported, but can be used directly)
  • String indicates the string type, which belongs to the reference data type
  • In Java, string objects are enclosed in double quotation marks, and strings enclosed in double quotation marks are immutable
    4. In the JDK of Java, the string enclosed in double quotation marks is directly stored in the string constant pool in the method area because the string is used too frequently in actual development to improve efficiency

1. Storage principle of 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 对象在堆内存中内存地址*/

Summary:

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 construction method:

 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<bytes.length;i++) {
			System.out.println(bytes[i]);//97 98 99 100
		}
		
		
//		方法8. int indexOf(String) 判断某个子字符串在当前字符串中第一次出现处的索引,从左往右查找
		System.out.println("abcdefcd".indexOf("cd"));//2
		System.out.println("abcdefcd".indexOf("d"));//3
		
		
//		方法9. boolean isEmpty()  判断某个字符串是否为空
		System.out.println("abcdefcd".isEmpty());//false
		
//		方法10.  int length() 判断某个字符串的长度
		System.out.println("abc".length());//3
//		与数组的长度不同,数组是length属性,字符串的长度是调用方法.length()
		
		
//		方法11. int lastIndexOf(String) 判断某个子字符串在当前字符串中最后一次出现处的索引,从右往左查找
		System.out.println("abcdefcd".lastIndexOf("cd"));//6
		
		
//		方法12. String replace(CharSequence target,CharSequence replacement) 返回一个新的字符串, 
		//String 的父接口就是CharSequence
		System.out.println("abcdefcd".replace("cd","ww"));//abwwefww
		
//		方法13. String[] split("分隔符"),将字符串以分隔符进行拆分,各部分以String数组的形式存储
		String[] s = "2021-11-24".split("-");
		for(int i=0;i<s.length;i++) {
			System.out.println(s[i]);//2021  11  24
		}
		
//		方法14. boolean startsWith(String) 判断前面的字符串是否以后面的字符串开始
		System.out.println("abxd".startsWith("ad"));// false
		
//		方法15.  String substring(int beginIndex)  从起始索引截取字符串,
		System.out.println("abxd".substring(1));//bxd
		
//		方法16.  String substring(int beginIndex, int endIndex)  从起始索引到结束索引截取字符串,
		//包含起始索引,不包含结束索引,左闭右开
		System.out.println("abxd".substring(0,2));//ab
		
//		方法17.   char[] toCharArray()  将字符串转换为char数组
		char[] a = "你啊你".toCharArray();
		for(int i=0;i<a.length;i++) {
			System.out.println(a[i]);//你 啊 你 
		}
		
//		方法18.   String toLowerCase()  将字符串中的字符都转换为小写
		System.out.println("ACD".toLowerCase());//acd
		
		
//		方法19.   String toUpperCase()  将字符串中的字符都转换为小写
		System.out.println("acd".toLowerCase());//acd
		
//		方法20.  String trim()   去除字符串的前后空白,中间的不会哟
		System.out.println("  hei hei  ".trim());//hei hei
		
 
		//		方法21. valueOf(参数)  将不是字符串的转换为字符串
//		是String中唯一的一个静态方法,不需要new对象,直接类名调用:String.valueOf(参数)
		 
		System.out.println(String.valueOf(100));//100
		
//		valueOf的源码
//		public static String valueOf(Object obj) {
//			return (obj==null) ? "null" : obj.toString();
//		}
		
//      同时,在输出语句System.out.println中的println方法,也就是会调用valueOf方法,
//		而valueOf方法又调用了toString()方法
//		所以println方法输出时会以字符串输出
		
		
		
	}
}