Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否可以重新引用任何最终字符串变量。请告诉我在给定的程序中发生了什么_Java - Fatal编程技术网

Java 是否可以重新引用任何最终字符串变量。请告诉我在给定的程序中发生了什么

Java 是否可以重新引用任何最终字符串变量。请告诉我在给定的程序中发生了什么,java,Java,我已经用两种不同的方式编写了一个相同的程序,它们都给了我不同的输出。我不明白为什么。 请纠正我。 在第一个程序中,我得到这个输出 原件:乌梅什 更改:Xmesh 在第二个程序中,我得到了这个输出 原件:乌梅什 更改:乌梅什 方案-1 import java.lang.reflect.Field; public class SomeClass { public static void main(final String[] args) throws Throwable { final

我已经用两种不同的方式编写了一个相同的程序,它们都给了我不同的输出。我不明白为什么。 请纠正我。 在第一个程序中,我得到这个输出

原件:乌梅什

更改:Xmesh

在第二个程序中,我得到了这个输出

原件:乌梅什

更改:乌梅什

方案-1

import java.lang.reflect.Field;

public class SomeClass {
  public static void main(final String[] args) throws Throwable {
    final String s = "Umesh";
    changeString(s);
  }

  // We need a method so the compiler won't inline "s":
  static void changeString(final String s) throws Throwable {

    System.out.println("Original: " + s);
    final Field field = String.class.getDeclaredField("value");
    field.setAccessible(true);
    final char[] value = (char[]) field.get(s);
    value[0] = 'X';
    System.out.println("Changed: " + s);
  }
}
方案-2

import java.lang.reflect.Field;

public class SomeClass {
  public static void main(final String[] args) throws Throwable {
    final String s = "Umesh";
    System.out.println("Original: " + s);
    final Field field = String.class.getDeclaredField("value");
    field.setAccessible(true);
    final char[] value = (char[]) field.get(s);
    value[0] = 'X';
    System.out.println("Changed: " + s);
  }

}

首先我要说的是,你真的,真的不应该这样胡闹。:-)

在第一个示例中,您没有“重新引用”任何内容(也就是说,您没有更改字符串
s
所引用的内容),您所做的是修改它所引用的字符串。尽管正式的字符串是不可变的,但您使用反射作为后门来修改Oracle JDK中
String
实现的未记录内部(其他JDK的实现可能不同,导致代码失败)。但是
s
参考是不变的。即使使用反射,也不能更改
final
局部变量的值。(您可以通过反射更改
final
字段,但这样做会导致出现与本例中相同的不一致。)

在第二个示例中,由于
s
是一个
final
变量,因此您在
main
中给它一个文本值,就编译器而言,它是一个编译时常量,因为
String
是正式不可变的。编译器(非常)了解字符串,并围绕字符串进行了相当多的优化,例如将
“a”+“b”+“c”
转换为简单的
“abc”
。所以稍后,当它看到
“Original:+s
,它可以很高兴地用
“Original:Umesh”
来代替它。最后,当它看到
更改时:“+s
可以用
“Changed:Umesh”
替换它。它最终就像您实际编写的
System.out.println(“Original:Umesh”)
系统输出打印项次(“更改:Umesh”)

编译器无法在第一个示例中执行此操作,因为
s
是函数的参数,而不是在
main
中声明的
final

您可以看到字节码中的差异。编译它们中的每一个,然后通过
javac-psomeclass
反汇编它们。下面是我得到的(我称它们为
Example1
Example2
):

$javap-c示例1 从“Example1.java”编译而来 公共课示例1{ 公共示例1(); 代码: 0:aload_0 1:invokespecial#1//方法java/lang/Object。“:()V 4:返回 publicstaticvoidmain(java.lang.String[])抛出java.lang.Throwable; 代码: 0:ldc#2//String-Umesh 2:invokestatic#3//方法changeString:(Ljava/lang/String;)V 5:返回 静态void changeString(java.lang.String)抛出java.lang.Throwable; 代码: 0:getstatic#4//fieldjava/lang/System.out:Ljava/io/PrintStream; 3:new#5//class java/lang/StringBuilder 6:dup 7:invokespecial#6//方法java/lang/StringBuilder。”“:()V 10:ldc#7//字符串原件: 12:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15:aload_0 16:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19:invokevirtual#9//方法java/lang/StringBuilder.toString:()Ljava/lang/String; 22:invokevirtual#10//方法java/io/PrintStream.println:(Ljava/lang/String;)V 25:ldc#11//class java/lang/String 27:ldc#12//字符串值 29:invokevirtual#13//方法java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field; 32:astore_1 33:aload_1 34:iconst_1 35:invokevirtual#14//方法java/lang/reflect/Field.setAccessible:(Z)V 38:aload_1 39:aload_0 40:invokevirtual#15//方法java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 43:checkcast#16//class“[C” 46:checkcast#16//class“[C” 49:astore_2 50:aload_2 51:iconst_0 52:bipush 88 54:卡斯托 55:getstatic#4//Field java/lang/System.out:Ljava/io/PrintStream; 58:new#5//class java/lang/StringBuilder 61:dup 62:invokespecial#6//方法java/lang/StringBuilder。”“:()V 65:ldc#17//字符串已更改: 67:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 70:aload_0 71:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 74:invokevirtual#9//方法java/lang/StringBuilder.toString:()Ljava/lang/String; 77:invokevirtual#10//方法java/io/PrintStream.println:(Ljava/lang/String;)V 80:返回 } 及

$javap-c示例2 从“Example2.java”编译而来 公共课示例2{ 公共示例2(); 代码: 0:aload_0 1:invokespecial#1//方法java/lang/Object。“:()V 4:返回 publicstaticvoidmain(java.lang.String[])抛出java.lang.Throwable; 代码: 0:getstatic#2//Field java/lang/Sys $ javap -c Example1 Compiled from "Example1.java" public class Example1 { public Example1(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]) throws java.lang.Throwable; Code: 0: ldc #2 // String Umesh 2: invokestatic #3 // Method changeString:(Ljava/lang/String;)V 5: return static void changeString(java.lang.String) throws java.lang.Throwable; Code: 0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 3: new #5 // class java/lang/StringBuilder 6: dup 7: invokespecial #6 // Method java/lang/StringBuilder."":()V 10: ldc #7 // String Original: 12: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: aload_0 16: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 25: ldc #11 // class java/lang/String 27: ldc #12 // String value 29: invokevirtual #13 // Method java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field; 32: astore_1 33: aload_1 34: iconst_1 35: invokevirtual #14 // Method java/lang/reflect/Field.setAccessible:(Z)V 38: aload_1 39: aload_0 40: invokevirtual #15 // Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 43: checkcast #16 // class "[C" 46: checkcast #16 // class "[C" 49: astore_2 50: aload_2 51: iconst_0 52: bipush 88 54: castore 55: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 58: new #5 // class java/lang/StringBuilder 61: dup 62: invokespecial #6 // Method java/lang/StringBuilder."":()V 65: ldc #17 // String Changed: 67: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 70: aload_0 71: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 74: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 77: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 80: return } $ javap -c Example2 Compiled from "Example2.java" public class Example2 { public Example2(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]) throws java.lang.Throwable; Code: 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Original: Umesh 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: ldc #5 // class java/lang/String 10: ldc #6 // String value 12: invokevirtual #7 // Method java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field; 15: astore_2 16: aload_2 17: iconst_1 18: invokevirtual #8 // Method java/lang/reflect/Field.setAccessible:(Z)V 21: aload_2 22: ldc #9 // String Umesh 24: invokevirtual #10 // Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 27: checkcast #11 // class "[C" 30: checkcast #11 // class "[C" 33: astore_3 34: aload_3 35: iconst_0 36: bipush 88 38: castore 39: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 42: ldc #12 // String Changed: Umesh 44: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 47: return }