String的一点特殊性质

      在常量的处理上,String和基本类型的处理有些类似的地方,那就是Constant Folding,暂且翻译成常量折叠吧。

      废话不说,直接看代码:

public class Test {
    public static void main(String[] args) {
        System.out.println(TestFinal.str);
        System.out.println(TestFinal.i);
    }
}

 

使用的TestFinal类的代码:

public class TestFinal {
    public static final int i=5;
    public static final String str="Hello world";
}

直接反汇编Test.class文件:

javap -verbose Test >test.txt

结果:

Compiled from "Test.java"
public class Test extends java.lang.Object
  SourceFile: "Test.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method    #7.#16;    //  java/lang/Object."<init>":()V
const #2 = Field    #17.#18;    //  java/lang/System.out:Ljava/io/PrintStream;
const #3 = String    #19;    //  Hello world
const #4 = Method    #20.#21;    //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #5 = Method    #20.#22;    //  java/io/PrintStream.println:(I)V
const #6 = class    #23;    //  Test
const #7 = class    #24;    //  java/lang/Object
const #8 = Asciz    <init>;
const #9 = Asciz    ()V;
const #10 = Asciz    Code;
const #11 = Asciz    LineNumberTable;
const #12 = Asciz    main;
const #13 = Asciz    ([Ljava/lang/String;)V;
const #14 = Asciz    SourceFile;
const #15 = Asciz    Test.java;
const #16 = NameAndType    #8:#9;//  "<init>":()V
const #17 = class    #25;    //  java/lang/System
const #18 = NameAndType    #26:#27;//  out:Ljava/io/PrintStream;
const #19 = Asciz    Hello world;
const #20 = class    #28;    //  java/io/PrintStream
const #21 = NameAndType    #29:#30;//  println:(Ljava/lang/String;)V
const #22 = NameAndType    #29:#31;//  println:(I)V
const #23 = Asciz    Test;
const #24 = Asciz    java/lang/Object;
const #25 = Asciz    java/lang/System;
const #26 = Asciz    out;
const #27 = Asciz    Ljava/io/PrintStream;;
const #28 = Asciz    java/io/PrintStream;
const #29 = Asciz    println;
const #30 = Asciz    (Ljava/lang/String;)V;
const #31 = Asciz    (I)V; </init></init></init>

{
public Test();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return
  LineNumberTable:
   line 1: 0 </init>

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=1, Args_size=1
   0:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:    ldc    #3; //String Hello world
   5:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:    iconst_5
   12:    invokevirtual    #5; //Method java/io/PrintStream.println:(I)V
   15:    return
  LineNumberTable:
   line 3: 0
   line 4: 8
   line 5: 15

}

      从里面可以看到,这个类根本没有TestFinal类的信息,使用的常量都直接替换为对应的值了。

所以,如果修改了TestFinal中的String常量和基本类型常量的值的话,一定要记得把相关的使用到该类中的变量的java文件(这里是Test.java)重新编译。

     另外,众所周知,String是Immutable类,平时常见的Immutable类有很多,比如基本类型的wrapper类,Integer,Float等。但是分析问题的时候一定要注意场景,不要什么都和Immutable联系起来,比如这个例子:

public class Test {
    public static void main(String[] args) {
        String str="ImmutableString";
        StringBuilder builder=new StringBuilder("可变的StringBuilder");
        System.out.println(str);
        System.out.println(builder);
        change(str);
        change(builder);
        System.out.println(str);
        System.out.println(builder);
    }
    public static void change(String str){
        str="新的String";//
    }
    public static void change(StringBuilder builder){
        builder=new StringBuilder("新的StringBuilder!");
    }
}

     只要对参数变量使用了赋值“=”处理,一切改变对外都是没有作用的,因此这个例子跟String的不变性没有任何关系。根本原因还是java的“pass by value”问题。关于这一点不想多说了,使用The Java Programming Language中的说法。

你可能感兴趣的:(java)