Java拼图与反射和字符串 [英] Java Puzzle with reflection and String

查看:106
本文介绍了Java拼图与反射和字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此来源输出 G'Day Mate。这是怎么回事?

  public static void main(String args []){
System.out.println(Hello World);
}

static {
try {
Field value = String.class.getDeclaredField(value);
value.setAccessible(true);
value.set(Hello World,value.get(G'Day Mate。));
} catch(异常e){
抛出新的AssertionError(e);
}
}

如果我们更改主要功能Hello World new String(Hello World)

  System.out.println(new String(Hello World)); 

输出 Hello world



实际发生了什么?

解决方案

这个源代码开辟了一些有趣的技巧的java。让我们逐一检查。



首先,我们需要了解代码的流程。代码的哪一部分将首先执行?



静态初始化块。为什么?让我们参考 Java语言规范(12.4) )


类的初始化包括执行静态初始化器和声明的静态字段(类变量)的初始化器这个班。


什么时候发生?再次来自 JLS(12.4。 1)


T是一个类,调用T声明的静态方法。


因此我们可以得出静态initiazlier将在main方法之前首先执行的结论。



现在,这两行使用反射:

 字段值= String.class.getDeclaredField(value); 
value.setAccessible(true);

为简单起见,我们可以将第一行分成两行:

  Class< String> c = String.class; 
字段值= c.getDeclaredField(value);

第一行是检索 Reflected Class Object ,第二行检索 Field ,表示 String 类的字段。



value.setAccessible(true)表示反射的类对象在使用时应禁止Java语言访问检查。(< a href =http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible%28java.lang.reflect.AccessibleObject%5B%5D,%20boolean%29 rel =nofollow noreferrer>参考)。



下一行有问题

  value.set(Hello World,value.get(G'Day Mate。)); 

如果我们潜入。set()documenation we可以看到我们正在调用 set(Object aObject,Object value)版本的 set value.get(G'Day Mate。)返回G'Day Mate。's value 字段的值,实际上是 char [] 。并且通过调用 set ,它将Hello World对象的值字段的值替换为G'Day Mate。对象的值字段。



static 块的代码解释了。



让我们深入了解主要功能。
这很简单。它应输出 Hello,world 。但它正在输出 G'Day Mate 。为什么?
因为我们在 static 初始值设定项中创建的 Hello,world String对象与<$ c相同$ c> Hello,world 我们在main函数中使用的对象。咨询 JLS 再次阐明它


此外,字符串文字始终引用类String的相同实例。这是因为字符串文字 - 或者更常见的是作为常量表达式(第15.28节)的值的字符串 - 被实例化以便使用String.intern方法共享唯一实例。


答案可帮助您更简洁地了解事实。



所以它显示了不同的值,因为我们已经将 Hello,world 对象的值改为 G'Day,Mate



但如果使用 new String(Hello world)在main函数中,它将直接创建 String 的新实例,而不是检入其池。所以main函数的 Hello world 将不同于我们更改了值的静态初始值设定项的 Hello world 。 / p>

This source outputs G'Day Mate. How this is happening ?

public static void main(String args[]) {
    System.out.println("Hello World");
}

static {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        value.set("Hello World", value.get("G'Day Mate."));
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

And if we change main functions "Hello World" to new String("Hello World"):

System.out.println(new String("Hello World"));

It outputs Hello world .

What is happening actually?

解决方案

This source code opens up some interesting techniques of java. Let's examine one by one.

At first we need to understand the flow of the code. Which part of the code will execute first?

The Static Initialization Block. Why? Let's consult with Java Language Specification (12.4) :

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.

And when does it occur? Again from JLS (12.4.1):

T is a class and a static method declared by T is invoked.

So we can come to the conclusion that static initiazlier will execute first before the main method.

Now, these two lines are using reflection:

Field value = String.class.getDeclaredField("value");
value.setAccessible(true);

We can break the fist line into two lines for simplicity:

Class<String> c = String.class;
Field value = c.getDeclaredField("value");

The first line is retrieving the Reflected Class Object and the second line is retrieving a Field which represents the value field of the String class.

value.setAccessible(true) indicates that the reflected class object should suppress Java language access checking when it is used.(Reference).

Next line under question is

value.set("Hello World", value.get("G'Day Mate."));

If we dive into .set() documenation we can see that we are calling the set(Object aObject,Object value) version of set. value.get("G'Day Mate.") is returning "G'Day Mate."'s value field's value which is actually a char[]. And with the call of set it replaces the value of "Hello World" object's value field with "G'Day Mate." object's value field.

The static block's code is explained.

Lets dive into main funciton. It's pretty simple. It should output Hello, world. But it is outputting G'Day Mate. Why? Because the Hello, world String object we created in the static initializer is the same as Hello, world object we are using in main function. Consulting with JLS again will shed light on it

Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.

This answer can help you to understand the fact more concisely.

So it is showing different value as we have already changed Hello,world object's value to G'Day, Mate.

But if you use new String("Hello world") in main function it will directly create a fresh instance of String rather than checking into its pool. So Hello world of main function would be differnt than Hello world of static initializer of which we have changed the value.

这篇关于Java拼图与反射和字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆