2020年9月17日 String类的特点、对象的比较、对象个数,拼接结果(变量、常量的存储位置)
package com.atguigu.test08; import org.junit.Test; /* * java.lang.String: * 1、特点 * (1)String类型不能被继承,因为String是由final修饰 * (2)String类型的对象是不可变 * 换句话说,只要修改字符串,就会产生新对象 * (3)String对象不可变的特性,使得我们可以把一些字符串存到常量池中, * 字符串有常量池。常量池中的是可以共享的。 * * 字符串常量池在哪里?Oracle官方虚拟机HotSpot * (1)JDK1.6以及之前:方法区 * (2)JDK1.7:挪到堆中,即在堆中单独划分了一块来存字符串常量 * (3)JDK1.8:从堆中挪出,挪到一个“元空间meta space”,即类似于方法区 * (4)String对象底层的存储 * JDK1.9之前:底层是用char[]存储 * JDK1.9之后:底层选用byte[]存储 * * (5)String对象怎么就不可变 * ①底层char[]数组有final修饰,意味着这个数组不能扩容等,来达到存更多的字符 * ②char[]数组是私有的,我们程序员无法直接操作这个char[]数组,而且String没有提供这样的方法,来修改char[]数组的元素的值。 * String提供的所有的方法,对字符串的修改都是给你返回一个新的字符串对象。 */ public class TestString01 { @Test public void test02(){ String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2);//true,说明是同一个位置,==比较的是地址值、equals比较的是内容。。。 } @Test public void test01(){ /* String s1 = "hello"; s1 = "world"; s1 = s1 + "java";*/ String s = ""; change(s); System.out.println(s);//输出空,说明字符串不能被修改 } public void change(String str){ str = "hello"; } }
package com.atguigu.test08; import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Locale; import org.junit.Test; /* * 2、字符串的比较 * (1)==:比较对象的地址 * 结论:只有两个字符串的常量对象(并且地址相同)比较时才会返回true,其他的都是false(比如常量和变量比较也是false) * (2)equals:比较字符串的内容,严格区分大小写 * 因为String类型重写了Object的equals * (3)equalsIgnoreCase(String anotherString) :比较字符串内容,不区分大小写 * (4)大小比较 * String类型实现了Comparable接口,(说明)重写了compareTo方法,严格区分大小写,s1.compateTo(s2) s1>s2,返回整数,<则返回负数; * 依次比较对应位置的字符,以下是比较的顺序: * ①比较最靠前的字母:hello和Hello,先[0]位置的h和H,h>H,就直接认定为hello>Hello * ②比较第一个不一样的之母:hello和hella,先[0][1][2][3]比较,都一样,最后到[4]o>a,认定hello>hella * ③比较长度: hello和helloworld,发现前面都一样,长的大 * * (5)大小比较:不区分大小写 * String类型还提供了一个方法compareToIgnoreCase,可以忽略大小写比较大小 * * (6)按照每个国家的语言校对顺序 * java.text.Collator:Collator 类执行区分语言环境的 String 比较。使用此类可为自然语言文本构建搜索和排序例程。 * Collator实现了Comparator接口 , * Collator是抽象类,不能直接创建对象,它有一个直接子类RuleBasedCollator * Collator内部提供了一个静态方法,可以获取一个它的子类对象 * * 自然排序:实现java.lang.Comparable接口,int compareTo(Object obj) * 定制排序 */ public class TestString02 { @Test public void test12(){ String[] arr = {"柴林燕","张三","李四","崔志恒","甄玉禄"}; //希望按照拼音顺序,字典顺序 Arrays.sort(arr, Collator.getInstance(Locale.CHINA));//Locale.CHINA指定语言环境 System.out.println(Arrays.toString(arr)); } @Test public void test11(){ String[] arr = {"柴林燕","张三","李四","崔志恒","甄玉禄"}; //希望按照拼音顺序,字典顺序 Arrays.sort(arr, Collator.getInstance());//默认语言环境,因为我现在的操作系统的平台是中文win System.out.println(Arrays.toString(arr)); } @Test public void test10(){ String[] arr = {"柴林燕","张三","李四","崔志恒","甄玉禄"}; Arrays.sort(arr);//按照自然顺序,按照每一个字符的Unicode编码值排序的 System.out.println(Arrays.toString(arr)); } @SuppressWarnings("all") @Test public void test09(){ String[] arr = {"hello","chai","Java","Alice","Hi"}; //排序 //按照字母的顺序排列,不区分大小写 Arrays.sort(arr,new Comparator(){ @Override public int compare(Object o1, Object o2) { String s1 = (String) o1; String s2 = (String) o2; return s1.compareToIgnoreCase(s2); } });//按照元素的自然顺序排序 System.out.println(Arrays.toString(arr)); } @Test public void test08(){ String[] arr = {"hello","chai","Java","Alice","Hi"}; //排序 //按照字母的顺序排列 Arrays.sort(arr);//按照元素的自然顺序排序 System.out.println(Arrays.toString(arr)); } @Test public void test07(){ String s1 = new String("hello"); String s2 = new String("Hello"); if(s1.compareToIgnoreCase(s2) > 0){ System.out.println(s1 + ">" + s2); }else if(s1.compareToIgnoreCase(s2) < 0){ System.out.println(s1 + "<" + s2); }else{ System.out.println(s1 + "=" + s2); } } @Test public void test06(){ String s1 = new String("hello"); String s2 = new String("helloworld"); /* if(s1 > s2){//不能直接使用比较运算符 }*/ if(s1.compareTo(s2) > 0){ System.out.println(s1 + ">" + s2); }else if(s1.compareTo(s2) < 0){ System.out.println(s1 + "<" + s2); }else{ System.out.println(s1 + "=" + s2); } } @Test public void test05(){ String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1.equalsIgnoreCase(s2));//true String s3 = "hello"; System.out.println(s3.equalsIgnoreCase(s1));//true String s4 = "Hello"; System.out.println(s3.equalsIgnoreCase(s4));//true } @Test public void test04(){ String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1.equals(s2));//true,变量与变量,内容严格一致。。。 String s3 = "hello"; System.out.println(s3.equals(s1));//true,常量与变量,内容严格一致。。。 String s4 = "Hello"; System.out.println(s3.equals(s4));//false,常量与变量,内容不严格一致。。。 } @Test public void test03(){ String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1 == s2);//false,变量和变量比较,地址值不一致; } @Test public void test02(){ String s1 = new String("hello"); String s2 = "hello"; System.out.println(s1 == s2);//false,变量和常量比较,地址不一致; } @Test public void test01(){ String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2);//true,常量和常量比较,并且地址相同; } }
package com.atguigu.test08; import org.junit.Test; /* * 1、面试题 * (1)String str = new String("hello");几个对象(2个) * (2)String str1 = new String("hello"); String str2 = new String("hello");几个对象(3个) * * 2、拼接的结果在堆还是在常量池? * 因为只有常量池中才是共享,==比较才为true * * (1)常量 + 常量 在常量池 * (2)变量 + 常量 在堆 * (3)变量 + 变量 在堆 * (4)xx.intern():在常量池 *
* 3、空字符串 * (1)"" * (2)new String() * (3)new String("") * * 四种方式: * (1)if(str != null && str.length() == 0) * (2)if(str != null && str.equals("")){ * (3)if("".equals(str)) 推荐 * (4)if(str!=null && str.isEmpty()) */ public class TestString03 { @Test public void test08(){ String str = null; System.out.println(test(str)); String str2 = ""; System.out.println(test(str2)); } //判断str是否是空字符串,是就返回true,不是返回false public boolean test(String str){//方法4 if(str!=null && str.isEmpty()){ return true; } return false; } /*public boolean test(String str){//方法3 if("".equals(str)){//推荐 return true; } return false; }*/ /*public boolean test(String str){//方法2 if(str != null && str.equals("")){ return true; } return false; }*/ /* public boolean test(String str){//方法1 if(str != null && str.length() == 0){ return true; } return false; }*/ @Test public void test07(){ String s1; //局部变量未初始化 String s2 = null;//初始化null String s3 = "";//空字符串常量对象 String s4 = new String();//空字符串对象 String s5 = new String("");//两个对象,一个是常量池中的,一个是堆中 // System.out.println(s1);//无法使用 // System.out.println(s2.length());//空指针异常 System.out.println(s3.length()); System.out.println(s4.length()); System.out.println(s5.length()); } @Test public void test06(){ String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; String s4 = (s1 + "world").intern();//把拼接的结果放到常量池中 String s5 = (s1 + s2).intern(); System.out.println(s3 == s4);//true System.out.println(s3 == s5);//true } @Test public void test05(){ final String s1 = "hello"; final String s2 = "world"; String s3 = "helloworld"; String s4 = s1 + "world";//s4字符串内容也helloworld,s1是常量,"world"常量,常量+ 常量 结果在常量池中 String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是常量,常量+ 常量 结果在常量池中 String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 System.out.println(s3 == s4);//true System.out.println(s3 == s5);//true System.out.println(s3 == s6);//true } @Test public void test04(){ String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; String s4 = s1 + "world";//s4字符串内容也helloworld,s1是变量,"world"常量,变量 + 常量的结果在堆中 String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是变量,变量 + 变量的结果在堆中 String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 System.out.println(s3 == s4);//false System.out.println(s3 == s5);//false System.out.println(s3 == s6);//true } @Test public void test03(){ String str1 = new String("hello"); String str2 = new String("hello"); //这两行代码,几个对象?3个 } @Test public void test02(){ String str = new String("hello");//两个字符串对象 //一个在常量池中:hello //另一个在堆中,String的对象 //堆中的这个字符串对象char[]的value数组,指向常量池中"hello"的char[]的value } @Test public void test01(){ String str = "hello";//一个字符串对象 } }