【问题标题】:Can anyone explain me why this code returns false谁能解释我为什么这段代码返回 false
【发布时间】:2013-10-22 16:59:14
【问题描述】:

我遇到了一位朋友发给我的 sn-p。它有一个非常奇怪的行为。我尝试用谷歌搜索代码,看看我是否在互联网上找到了一些东西,但没有运气。我无法联系到我的朋友,所以我很好奇它在做什么。

    public class Test {

        public static void main(String[] args) throws MalformedURLException {
            System.out.println(Boolean.TRUE); //This prints false
        }

        static {
            try {
                Field value = Boolean.class.getDeclaredField("value");
                value.setAccessible(true);
                value.set(Boolean.TRUE, value.get(Boolean.FALSE));
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        }

    }

我认为,就像声明为静态的那段代码一样,它将首先运行 main 方法,并且在该静态代码内部正在更改所有 Boolean 实例的值(?)。我不知道,我需要专家意见来确认这一点。

【问题讨论】:

  • static 部分是一个静态初始化块,在类首次加载时执行。此块使用(讨厌的)反射将静态字段TRUE 的值更改为等于false。查看initializing fields了解更多详情

标签: java semantics


【解决方案1】:
public static final Boolean TRUE = new Boolean(true);

常量 TRUE 是一个对象的引用点,final 意味着你不能改变它来指向另一个对象。因为你已经把value 常量改成了false,所以现在对象的值是false。

【讨论】:

    【解决方案2】:
    Field value = Boolean.class.getDeclaredField("value");
    value.setAccessible(true);
    value.set(Boolean.TRUE, value.get(Boolean.FALSE));
    

    通过反射,Boolean.TRUE 的常量值设置为Boolean.FALSE。那是..正如您在代码中所读到的那样。

    static 初始化程序块在 main 方法之前执行,不要让顺序欺骗您认为它会在以后发生。

    引用this帖子:

    假设没有 SecurityManager 阻止您这样做,您可以使用 setAccessible 绕过 private 并重置修饰符以摆脱 final,并实际修改私有静态 final 字段。

    【讨论】:

    • 好吧,但不是Boolean.TRUEBoolean.FALSE 常量声明为final。所以反射可以欺骗final关键字?
    • 反射是编程的秘籍:你可以完成原本不可能完成的事情。
    • 是的,我意识到了很多奇怪的事情。首先发生这种情况是因为Boolean.FALSEBoolean.TRUE 都是布尔值的实例,而不是原语。如果你用原语尝试这个相同的例子,一切都会正常运行。此外,Boolean 对象的value 字段是final 并且未初始化,因此,在反射的某个地方,同一个布尔类必须更改他自己的值字段值。男孩你很奇怪 java Boolean.java
    • @astinx Boolean.value 在构造函数Boolean(boolean) 中赋值。构造函数(和初始化器)被允许分配最终字段(一次),这没什么奇怪的。
    【解决方案3】:

    这是因为执行顺序保证了静态初始化块将在类实例的其他初始化之前执行。加载类时进行静态初始化;通常在类的第一个引用处。

    由于静态块在调用main 方法之前更改了Boolean.TRUE 的值,因此它会打印更改的值。

    考虑以下示例 (source):

    /*
     * Here we will learn to see how the different part (Ananymous Block, Constructor and Static Block ) of class will behave
     * and what would be the order of execution. 
     */
    class JBTCLass {
    
        /*
         * Here Creating the Ananymous Block
         */
        {
            System.out.println("Inside Ananymous Block");
        }
    
        /*
         * Now Creating the Static Block in Class
         */
        static {
            System.out.println("Inside Static Block");
        }
    
        /*
         * Here Creating the Constructor of Class
         */
        JBTCLass() {
            System.out.println("Inside Constructor of Class");
        }
    
        public static void main(String[] args) {
    
            // Creating the Object of the Class
            JBTCLass obj = new JBTCLass();
    
            System.out.println("*******************");
    
            // Again Creating Object of Class
            JBTCLass obj1 = new JBTCLass();
    
        }
    
    }
    

    结果:

    Inside Static Block
    Inside Ananymous Block
    Inside COnstructor of Class
    *******************
    Inside Ananymous Block
    Inside COnstructor of Class
    

    【讨论】:

      猜你喜欢
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      • 2017-04-22
      • 1970-01-01
      相关资源
      最近更新 更多