String类的详解(1)

目录

String类的理解和创建对象

两种创建String对象的区别

String习题

第一题

第二题

第三题

第四题

第五题

第六题

第七题

第八题

第九题


String类的理解和创建对象

1)String对象用于保存字符串,也就是一组字符序列

2)字符串常量对象是用双引号括起的字符序列。例如:“你好”、"12.97"、"boy"等

3)字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。

4)String类较常用构造器(其它看手册):

代码演示:

细节:

 String 是final 类,不能被其他的类继承

String 有属性 private final char value[]; 用于存放字符串内容

 一定要注意:value 是一个final类型, 不可以修改():指的的是value不能指向新的地址,但是单个字符内容是可以变化

package idea.chapter13.string_;

public class String01 {
    public static void main(String[] args) {
        //1.String 对象用于保存字符串,也就是一组字符序列
        //2. "jack" 字符串常量, 双引号括起的字符序列
        //3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
        //4. String 类有很多构造器,构造器的重载
        //   常用的构造器有 
        //String  s1 = new String(); 
        //String  s2 = new String(String original);
        //String  s3 = new String(char[] a);
        //String  s4 =  new String(char[] a,int startIndex,int count)
        //String s5 = new String(byte[] b)
        //5. String 类实现了接口 Serializable[String 可以串行化:可以在网络传输]
        //                 接口 Comparable [String 对象可以比较大小]
        //6. String 是final 类,不能被其他的类继承
        //7. String 有属性 private final char value[]; 用于存放字符串内容
        //8. 一定要注意:value 是一个final类型, 不可以修改():指的的是value不能指向新的地址,但是单个字符内容是可以变化

        //举例
        //一个final修饰的char数组
        final char[] value = {'a', 'b', 'c'};
        //例外一个char数组
        char[] v2 = {'t', 'o', 'm'};
        value[0] = 'H';//修改final修饰的char数组中的内容,不会报错
        //注意,如果让原数组,指向一个新数组,那么是不可以的,下面的这句话就会报错,但是如果去掉final,就不会报错
        //value = v2; 不可以修改 指定是不可以修改value地址,可以修改内容

        String name = "jack";
        name = "tom";

    }
}

两种创建String对象的区别

方式一:直接赋值Strings="jack";

方式二:调用构造器 String s2=new String("jack");

·1.方式一:先从常量池查看是否有"jack"数据空间,如果有,直接指向;如果 没有则重新创建,然后指向。s最终指向的是常量池的空间地址

2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的jack空间。 如果常量池没有"jack",重新创建,如果有,直接通过value指向。最终指向 的是堆中的空间地址。

String习题

第一题

 思路分析:
 1.在执行String a = "abc";这句话的时候,因为是直接赋值,所以会先去常量池中查看是否有abc的数据空间,在查找完之后发现没有,就会在常量池中创建,并让a指向这个空间
 2.在执行String b = "abc";这句话的时候,因为是直接赋值,所以会先去常量池中查看是否有abc的数据空间存在,在查找我之后,发现存在,就不会创建空间,而是让b直接指向

 所以在执行a.equals(b)的时候,因为String类重写了equals方法,判断的是值是否相等,所以这里比较的是内容,因此返回true
 看看String类的equals方法的源码
     public boolean equals(Object anObject) {
         if (this == anObject) {//判断传入参数的类型是否和当前的类型是否相同
             return true;
         }
         if (anObject instanceof String) {//判断传入参数的运行类型是不是String类型或者是String类的子类型
             String anotherString = (String)anObject;//如果是String类型或者是String类的子类型,那么就向下转型
             int n = value.length;
             if (n == anotherString.value.length) {//如果长度相同
                 char v1[] = value;
                 char v2[] = anotherString.value;
                 int i = 0;
                 while (n-- != 0) {//然后一个一个的比较字符
                     if (v1[i] != v2[i])//如果发现两个数组中,有一个字符不相同那么就返回false
                         return false;
                     i++;
                 }
                 return true;//如果两个字符串的所有字符都相等,则返回true
             }
         }
         return false;//如果比较的不是字符串(也就是传入的数据类型,不是String类型或者不是String类型的子类型),则直接返回false
     }

在执行a==b的时候,因为String是引用类型判断的是地址是否相同,因为a和b指向的都是常量池中的同一块空间,所以返回true
package idea.chapter13.string_;

public class StringExercise01 {
    public static void main(String[] args) {
        /*
        结论
         ·1.方式一:先从常量池查看是否有"jack"数据空间,如果有,直接指向;如果
         没有则重新创建,然后指向。s最终指向的是常量池的空间地址

         2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的jack空间。
         如果常量池没有"jack",重新创建,如果有,直接通过value指向。最终指向
         的是堆中的空间地址。
         */
        String a = "abc";
        String b = "abc";

        System.out.println(a.equals(b));

        System.out.println(a == b);
        /*
        思路分析:
        1.在执行String a = "abc";这句话的时候,因为是直接赋值,所以会先去常量池中查看是否有abc的数据空间,在查找完之后发现没有,就会在常量池中创建,并让a指向这个空间
        2.在执行String b = "abc";这句话的时候,因为是直接赋值,所以会先去常量池中查看是否有abc的数据空间存在,在查找我之后,发现存在,就不会创建空间,而是让b直接指向

        所以在执行a.equals(b)的时候,因为String类重写了equals方法,判断的是值是否相等,所以这里比较的是内容,因此返回true
        看看String类的equals方法的源码
            public boolean equals(Object anObject) {
                if (this == anObject) {//判断传入参数的类型是否和当前的类型是否相同
                    return true;
                }
                if (anObject instanceof String) {//判断传入参数的运行类型是不是String类型或者是String类的子类型
                    String anotherString = (String)anObject;//如果是String类型或者是String类的子类型,那么就向下转型
                    int n = value.length;
                    if (n == anotherString.value.length) {//如果长度相同
                        char v1[] = value;
                        char v2[] = anotherString.value;
                        int i = 0;
                        while (n-- != 0) {//然后一个一个的比较字符
                            if (v1[i] != v2[i])//如果发现两个数组中,有一个字符不相同那么就返回false
                                return false;
                            i++;
                        }
                        return true;//如果两个字符串的所有字符都相等,则返回true
                    }
                }
                return false;//如果比较的不是字符串(也就是传入的数据类型,不是String类型或者不是String类型的子类型),则直接返回false
            }

       在执行a==b的时候,因为String是引用类型判断的是地址是否相同,因为a和b指向的都是常量池中的同一块空间,所以返回true
         */


        //在执行String a = "abc";这句话时,会先在常量池中查找是否有abc这个数据空间,如果有直接指向,但是这里没有,所以会重新创建
        //当指向到String b = "abc";这句话时,也会去常量池查找,因为在上面String a = "abc";这句话已经在常量池里创建好了空间
        //因此String b = "abc";不会去创建新的空间而且直接指向,a所创建的空间
    }
}

第二题

思路分析:

1.当执行到String a = "jack";的时候,因为是直接赋值的方式,所以会先去常量池中查找是否有jack这个数据空间,查询完发现不存在就会创建一个空间,并让a指向他
2.当执行到 String b = new String("jack");的时候,因为是创建对象的方式,所以会现在堆中开辟一个空间,里面有一个value属性,然后去常量池中查找,是否有Jack这个空间
  查完,发现已经存在Jack这个数据空间,所以直接人value直接指向,并不是b直接指向,而且是b指向堆中的value属性,然后value属性在指向常量池中的数据空间

所以在执行a.equals(b);的时候,因为String重写了equals方法判断的是值是否相同,所以会返回true

在执行a==b 的时候,因为String是引用类型,因此==在判断的是地址是否相同,因为a指向的是常量池中的地址,而b指向的是堆中的value属性,所以会返回true

在执行a==b.intern();的时候,我们首先要知道b.intern()返回的就是常量池中的地址,而a也是指向的是常量池中的地址,所以两个会返回true
在执行b==b.intern();的时候,我们首先要知道b.intern()返回的就是常量池中的地址,而b指向的是堆中的value属性,两个指向的地方都不同所以返回false

细节:

当调用 intern 方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定)则返回池中的字符串。 否则,将此String对象添加到池中,并返回此String对象的引用

(1)b.intern()方法最终返回的是常量池的地址(对象).

package idea.chapter13.string_;

public class StringExercise03 {
    public static void main(String[] args) {
        /*
        结论:
        1.方式一:先从常量池查看是否有"jack"数据空间,如果有,直接指向;如果
        没有则重新创建,然后指向。s最终指向的是常量池的空间地址

        2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的jack空间。
        如果常量池没有"jack",重新创建,如果有,直接通过value指向。最终指向
        的是堆中的空间地址。
         */

        String a = "jack"; //a 指向 常量池的 “jack”
        String b = new String("jack");//b 指向堆中对象
        System.out.println(a.equals(b));//T  因为string重写了equals方法所以判断的是两值是否相同所以返回true
        System.out.println(a == b);//F   a指向的是常量池中的地址   b指向的是堆中的地址  所以返回false
        System.out.println(a == b.intern());//T  b.intern()方法最终返回的是常量池的地址(对象).所以和a指向的也是常量池中的地址所以两个相同返回true
        System.out.println(b == b.intern()); //F   b.intern()返回的是常量池的地址   b指向的是堆中的地址   所以返回false

        /*
        思路分析:
        1.当执行到String a = "jack";的时候,因为是直接赋值的方式,所以会先去常量池中查找是否有jack这个数据空间,查询完发现不存在就会创建一个空间,并让a指向他
        2.当执行到 String b = new String("jack");的时候,因为是创建对象的方式,所以会现在堆中开辟一个空间,里面有一个value属性,然后去常量池中查找,是否有Jack这个空间
          查完,发现已经存在Jack这个数据空间,所以直接人value直接指向,并不是b直接指向,而且是b指向堆中的value属性,然后value属性在指向常量池中的数据空间

        所以在执行a.equals(b);的时候,因为String重写了equals方法判断的是值是否相同,所以会返回true

        在执行a==b 的时候,因为String是引用类型,因此==在判断的是地址是否相同,因为a指向的是常量池中的地址,而b指向的是堆中的value属性,所以会返回true

        在执行a==b.intern();的时候,我们首先要知道b.intern()返回的就是常量池中的地址,而a也是指向的是常量池中的地址,所以两个会返回true
        在执行b==b.intern();的时候,我们首先要知道b.intern()返回的就是常量池中的地址,而b指向的是堆中的value属性,两个指向的地方都不同所以返回false


         */


        /*
        知识点:
        当调用 intern 方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定)则返回池中的字符串。
        否则,将此String对象添加到池中,并返回此String对象的引用

        解读;(1)b.intern()方法最终返回的是常量池的地址(对象).
         */
    }
}

第三题

思路分析:

1.String s1= "jack";因为是直接赋值,所以指向的是常量池中的地址
2.String s2= "java";因为是直接赋值,所以指向的是常量池中的地址
4.String s4= "java";因为是直接赋值,所以指向的是常量池中的地址
3.String s3 = new String("java");因为并不是直接赋值,而且是在堆中开辟一个空间,里面有一个value属性,value属性指向常量池中的空间

在执行s2 == s3 的时候,因为s2指向的是常量池中地址,而s3指向的是堆中的地址,所以返回false
在执行s2 == s4 的时候,因为s2指向的是常量池中地址,而s4指向的也是常量池中的地址,并且两个指向的是同一块地方,所以返回true
在执行s2.equals(s3)的时候,因为String重写了equals方法,所以判断的是值是否相等,所以返回true
在执行s1 == s2 的时候,因为s1指向的是常量池中的Jack空间,而s2指向的是常量池中Java空间,所以返回false
package idea.chapter13.string_;

public class StringExercise04 {
    public static void main(String[] args) {
        String s1 = "Jack"; //指向常量池”jack”
        String s2 = "java"; //指向常量池”java”
        String s4 = "java";//指向常量池”java”
        String s3 = new String("java");//指向堆中对象
        System.out.println(s2 == s3); // F  S2指向的是常量池中的对象   S3指向的是堆中的对象因此返回一个false
        System.out.println(s2 == s4);  //T   S2指向的常量池中的对象    S4指向的也是常量池中的对象  因此返回一个true
        System.out.println(s2.equals(s3));//T   因为String重写了equals方法所以判断的是是否相等所以返回一个true
        System.out.println(s1 == s2);  //F    S1指向的是常量池中的Jack  S2指向的是常量池中的Java对象  所以返回一个false

        /*
        思路分析:
        1.String s1= "jack";因为是直接赋值,所以指向的是常量池中的地址
        2.String s2= "java";因为是直接赋值,所以指向的是常量池中的地址
        4.String s4= "java";因为是直接赋值,所以指向的是常量池中的地址
        3.String s3 = new String("java");因为并不是直接赋值,而且是在堆中开辟一个空间,里面有一个value属性,value属性指向常量池中的空间

        在执行s2 == s3 的时候,因为s2指向的是常量池中地址,而s3指向的是堆中的地址,所以返回false
        在执行s2 == s4 的时候,因为s2指向的是常量池中地址,而s4指向的也是常量池中的地址,并且两个指向的是同一块地方,所以返回true
        在执行s2.equals(s3)的时候,因为String重写了equals方法,所以判断的是值是否相等,所以返回true
        在执行s1 == s2 的时候,因为s1指向的是常量池中的Jack空间,而s2指向的是常量池中Java空间,所以返回false
        
         */
    }
}

第四题

思路分析:

1.在执行System.out.println(p1.name.equals(p2.name));这句话的时候,因为String已经重写了equals方法,所以判断的是值是否相同,所以返回true
2.在执行System.out.println(p1.name == p2.name);这句话的时候,因为p1.name指向是常量池中的地址   p2.name指向的也是常量池中的地址  因为p1和p2的值是相同的所以指向的都是同一块地方所以返回一个true
3.在执行System.out.println(p1.name == "jack");这句话的时候//"jack"是一个常量,其实本质就是常量池中的一个地址所以 p1.name指向的是常量池中的地址 因此返回的是true
4.在执行System.out.println(s1 == s2);这句话的时候//s1和s2分别指向的是不同的堆空间因此返回的是false
package idea.chapter13.string_;

public class StringExercise05 {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "jack";
        Person p2 = new Person();
        p2.name = "jack";


        System.out.println(p1.name.equals(p2.name));//判断的是值是否相同所以返回一个true
        System.out.println(p1.name == p2.name);//p1.name指向是常量池中的地址   p2.name指向的也是常量池中的地址  因为p1和p2的值是相同的所以指向的都是同一块地方所以返回一个true
        System.out.println(p1.name == "jack");//"jack"是一个常量,其实本质就是常量池中的一个地址所以 p1.name指向的是常量池中的地址 因此返回的是true

        String s1 = new String("bcde");
        String s2 = new String("bcde");
        System.out.println(s1 == s2);//s1和s2分别指向的是不同的堆空间因此返回的是false

        /*
        思路分析:
        1.在执行System.out.println(p1.name.equals(p2.name));这句话的时候,因为String已经重写了equals方法,所以判断的是值是否相同,所以返回true
        2.在执行System.out.println(p1.name == p2.name);这句话的时候,因为p1.name指向是常量池中的地址   p2.name指向的也是常量池中的地址  因为p1和p2的值是相同的所以指向的都是同一块地方所以返回一个true
        3.在执行System.out.println(p1.name == "jack");这句话的时候//"jack"是一个常量,其实本质就是常量池中的一个地址所以 p1.name指向的是常量池中的地址 因此返回的是true
        4.在执行System.out.println(s1 == s2);这句话的时候//s1和s2分别指向的是不同的堆空间因此返回的是false
         */

    }
}

class Person {
    public String name;
}

第五题

思路分析:

package idea.chapter13.string_;

public class StringExercise06 {
    public static void main(String[] args) {
        //1.String是一个final类,代表不可变的字符序列
        //2.字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的
        //以下语句创建了几个对象?2个对象,画出内存布局图
        String s1 = "hello";//会指向常量池中的一个空间
        s1 = "haha";
        //因为字符串是final类的所以在指向到s1="haha";这句话时,并不是把原来的hello替换成haha而且先在常量池里寻找有没有haha如果有直接指向如果没有就在常量池中创建一个新的对象
        //然后让s1指向haha开辟的空间
    }
}

第六题

思路分析:

package idea.chapter13.string_;

public class StringExercise07 {
    public static void main(String[] args) {
        String a = "hello" + "abc";
        //问创建了几个对象,之创建了一个对象
        //创建了一个对象,在底层编译器不会在常量池分别创建两对象  在底层做了优化等价于String a="helloabc";

        //1.编译器不傻,做一个优化,判断创建的常量池对象,是否有引用指向
        //2.String a ="hello"+"abc";=》 String a = "helloabc";
    }
}

第七题

思路分析:        

1.在执行String s1 = "jack";这句话的时候,指向的是常量池中的Jack
2.在执行String s2 = "Java";这句话的时候,指向的是常量池中的java
3.在执行String s5 = "jackjava";这句话的时候,指向的是常量池中的jackjava
4.在执行String s6 = (s1 + s2).intern();这句话的时候,因为intern()方法,返回的是常量池中的地址
所以在执行s5==s6的时候,因为s5指向的时候常量池中的地址,而且s6指向的也是常量池中的地址,因为intern()方法,返回的就是常量池中的地址,所以返回的是true
在执行System.out.println(s5.equals(s6));这句话的时候,因为String已经重写equals()方法,比较的是内容是否相同,很显然他们的内容都是相同的 ,所以返回true
package idea.chapter13.string_;

public class StringExercise09 {
    public static void main(String[] args) {
        String s1 = "jack";  //s1 指向池中的 “jack”
        String s2 = "java"; // s2 指向池中的 “java”
        String s5 = "jackjava"; //s5 指向池中的 “jackjava”
        String s6 = (s1 + s2).intern();//s6返回的时常量池的地址 因为s5已经创建了jackjava因此s6不会在创建新的对象,指向的和s5是常量池中的同一块地方
        System.out.println(s5 == s6); //T
        System.out.println(s5.equals(s6));//T


        /*
        思路分析:
        1.在执行String s1 = "jack";这句话的时候,指向的是常量池中的Jack
        2.在执行String s2 = "Java";这句话的时候,指向的是常量池中的java
        3.在执行String s5 = "jackjava";这句话的时候,指向的是常量池中的jackjava
        4.在执行String s6 = (s1 + s2).intern();这句话的时候,因为intern()方法,返回的是常量池中的地址
        所以在执行s5==s6的时候,因为s5指向的时候常量池中的地址,而且s6指向的也是常量池中的地址,因为intern()方法,返回的就是常量池中的地址,所以返回的是true
        在执行System.out.println(s5.equals(s6));这句话的时候,因为String已经重写equals()方法,比较的是内容是否相同,很显然他们的内容都是相同的 ,所以返回true
         */
    }
}

第八题

思路分析:

//1. 先 创建一个 StringBuilder sb = StringBuilder()
//也就是new了一个StringBuilder  看源码
/*
    public StringBuilder() {
    super(16);
}
 */

//2. 执行  sb.append("hello");    调用StringBuilder的append方法先把a这个字符串追加   看源码
/*
@Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
 */

//3. sb.append("abc");          调用StringBuilder的append方法把b这个字符串追加   看源码
/*
    @Override
    public StringBuilder append(String str) {
           super.append(str);
           return this;
    }
 */

//4. String c= sb.toString()   最后调用toString 方法最后的是new也就是c指向了堆中的value空间  value空间指向常量池中的helloabc
/*
    @Override
    public String toString() {
          // Create a copy, don't share the array
          return new String(value, 0, count);
    }
 */

//最后其实是 c 指向堆中的对象(String) value[] -> 池中 "helloabc"


//小结:底层是StringBuilder sb =new StringBuilder();    sb.append(a);sb.append(b);      sb是在堆中,并且append是在原来字符串的基础上追加的
// 重要规则,String c1=“ab"+"cd”;常量相加,看的是池。String c1=a+b;变量相加,是在堆中
小结:底层是StringBuilder sb =new StringBuilder();    sb.append(a);sb.append(b);      sb是在堆中,并且append是在原来字符串的基础上追加的
// 重要规则,String c1=“ab"+"cd”;常量相加,看的是池。String c1=a+b;变量相加,是在堆中
package idea.chapter13.string_;

public class StringExercise08 {
    public static void main(String[] args) {
        String a = "hello"; //创建 a对象
        String b = "abc";//创建 b对象
        //解读

        //1. 先 创建一个 StringBuilder sb = StringBuilder()
        //也就是new了一个StringBuilder  看源码
        /*
            public StringBuilder() {
            super(16);
        }
         */

        //2. 执行  sb.append("hello");    调用StringBuilder的append方法先把a这个字符串追加   看源码
        /*
        @Override
            public StringBuilder append(String str) {
                super.append(str);
                return this;
            }
         */

        //3. sb.append("abc");          调用StringBuilder的append方法把b这个字符串追加   看源码
        /*
            @Override
            public StringBuilder append(String str) {
                   super.append(str);
                   return this;
            }
         */

        //4. String c= sb.toString()   最后调用toString 方法最后的是new也就是c指向了堆中的value空间  value空间指向常量池中的helloabc
        /*
            @Override
            public String toString() {
                  // Create a copy, don't share the array
                  return new String(value, 0, count);
            }
         */

        //最后其实是 c 指向堆中的对象(String) value[] -> 池中 "helloabc"


        //小结:底层是StringBuilder sb =new StringBuilder();    sb.append(a);sb.append(b);      sb是在堆中,并且append是在原来字符串的基础上追加的
        // 重要规则,String c1=“ab"+"cd”;常量相加,看的是池。String c1=a+b;变量相加,是在堆中
        String c = a + b;
        String d = "helloabc";
        System.out.println(c == d);//真还是假? 是false
        String e = "hello" + "abc";//直接看池, e指向常量池
        System.out.println(d == e);//真还是假? 是true
    }
}

第九题

思路分析:
1.String str = new String("Jack");在执行这句话的时候,会在堆中开辟一个空间,里面有一个value属性,指向常量池中的jack
  final char[] ch = {'j', 'a', 'v', 'a'};在指向这句话的时候 会有一个ch指向数组,
  到此在堆中就开辟了两个对象,一个是指向value属性,一个是指向数组
2.然后创建了一个Test1对象,此时在栈区中就一个对象,指向堆区

3.ex.change(ex.str, ex.ch);我们在调用方法的时候,我们知道每调用一个方法,会开辟一个新的对应的栈区,因为ex.str是一个对象,因此刚刚传入的时候
  在change方法中的str和我们堆中指向的空间是一样的,指向的是堆中的value属性,但是在str = "java"执行到这句话的时候,就会断开原来的指向,而是指向的常量池中新的地址
  然后又将ch[0]='h';又将数组中的第一个元素的值进行了修改
4.在方法结束后,对应生成的栈区也会销毁,此时在通过ex.str去访问堆中的属性的时候,访问到的就是jack ex.ch 访问到的就是 hava
//所以最后的结果时   hsp and hava
package idea.chapter13.string_;

public class StringExercise10 {
    public static void main(String[] args) {

    }
}

/*
思路分析:
1.String str = new String("Jack");在执行这句话的时候,会在堆中开辟一个空间,里面有一个value属性,指向常量池中的jack
  final char[] ch = {'j', 'a', 'v', 'a'};在指向这句话的时候 会有一个ch指向数组,
  到此在堆中就开辟了两个对象,一个是指向value属性,一个是指向数组
2.然后创建了一个Test1对象,此时在栈区中就一个对象,指向堆区

3.ex.change(ex.str, ex.ch);我们在调用方法的时候,我们知道每调用一个方法,会开辟一个新的对应的栈区,因为ex.str是一个对象,因此刚刚传入的时候
  在change方法中的str和我们堆中指向的空间是一样的,指向的是堆中的value属性,但是在str = "java"执行到这句话的时候,就会断开原来的指向,而是指向的常量池中新的地址
  然后又将ch[0]='h';又将数组中的第一个元素的值进行了修改
4.在方法结束后,对应生成的栈区也会销毁,此时在通过ex.str去访问堆中的属性的时候,访问到的就是jack ex.ch 访问到的就是 hava
//所以最后的结果时   hsp and hava
 */
class Test1 {
    String str = new String("Jack");
    //在执行String str = new String("hsp");这句话时会先在堆中创建空间,里面维护了value属性,指向常量池的hsp空间

    final char[] ch = {'j', 'a', 'v', 'a'};
    //在执行final char[] ch = {'j', 'a', 'v', 'a'};这句话时会在堆中创建一个ch对象对象数组

    public void change(String str, char ch[]) {
        str = "java";//在执行到str = "java";这句话时会先去常量池查找有无Java如果没有则在常量池创建一个,这是chang中的str指向的就是Java,而不在指向原来堆中的value属性会断开原来的连接指向的是在常量池中新开辟的Java
        ch[0] = 'h';//在执行到ch[0] = 'h';这句话时会把ch数组的第一个元素修改成h
    }

    public static void main(String[] args) {
        Test1 ex = new Test1();//ex会指向堆中开辟的空间
        ex.change(ex.str, ex.ch);//每调用一个方法会开辟一个新的栈  在传给change方法时ex.str指向的也是堆中value属性中保存的  ex.ch指向的也是堆中的数组
        System.out.print(ex.str + " and ");//当方法调用结束后,之前开辟的栈区就会消失 因此在ex.str时指向的还是最初的value
        System.out.println(ex.ch);//因为数组的元素被修改了所以,输出的内容时hava

        //所以最后的结果时   jack and hava
    }
}

你可能感兴趣的:(java)