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";//一个字符串对象
    }
}
原文地址:https://www.cnblogs.com/douyunpeng/p/13686645.html