简体   繁体   English

反思和不变性如何共同发挥作用

[英]How does reflection and immutability supposed to work together

According to JSR-133 immutable objects are thread safe and don't need synchronization. 根据JSR-133,不可变对象是线程安全的,不需要同步。 However it's possible to update values of final fields using reflection: 但是,可以使用反射更新最终字段的值:

package com.stackoverflow;

import java.lang.reflect.Field;

public class WhatsGoingOn {

    static class Immutable {
        private final int value;

        public Immutable(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        final Immutable immutable = new Immutable(Integer.MIN_VALUE);

        final Field f = Immutable.class.getDeclaredField("value");
        f.setAccessible(true);

        System.out.println(immutable.getValue());
        f.set(immutable, Integer.MAX_VALUE);
        System.out.println(immutable.getValue());
    }
}

Given number of frameworks (Spring and Hibernate are only a few) which rely on reflection I'm curious what does spec says about this scenario. 鉴于依赖于反射的框架数量(Spring和Hibernate只有少数),我很好奇规范说明了这个场景。 Eg if I put field update into synchronized block will that guarantee visibility in other threads, or value will be cached in registers as per spec for final. 例如,如果我将字段更新放入synchronized块中将保证其他线程中的可见性,或者值将根据spec的最终版本缓存在寄存器中。

http://download.oracle.com/otndocs/jcp/memory_model-1.0-pfd-spec-oth-JSpec/ http://download.oracle.com/otndocs/jcp/memory_model-1.0-pfd-spec-oth-JSpec/

An object is considered immutable if its state cannot change after it is constructed. 如果一个对象的状态在构造后不能改变,则该对象被认为是不可变的。 http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

You are using that Object as mutable since you are changing its state. 您正在使用该Object作为可变对象,因为您正在更改其状态。

It is true that the use of Reflection breaks immutability as defined in the tutorial, since you can use it to change non-constant final fields. 确实,使用Reflection会破坏教程中定义的不变性,因为您可以使用它来更改非常量的最终字段。

An example of a Reflection-resistant immutable object would be the following: 反射抗性不可变对象的示例如下:

static class Immutable {
    // This field is a constant, and cannot be changed using Reflection
    private final int value = Integer.MIN_VALUE;

    public int getValue() {
        return value;
    }
}

public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    final Immutable immutable = new Immutable();

    final Field f = Immutable.class.getDeclaredField("value");
    f.setAccessible(true);

    System.out.println(immutable.getValue());
    f.set(immutable, Integer.MAX_VALUE);
    System.out.println(immutable.getValue());
}

In this instance your reflection test will fail, and the value will remain Integer.MIN_VALUE . 在这种情况下,您的反射测试将失败,并且值将保持为Integer.MIN_VALUE But hey, we could always use native code or a memory editor to change that value to something else. 但是,嘿,我们总是可以使用本机代码或内存编辑器将该值更改为其他值。

If you go this far into hacking with reflection, you might as well not call your field final and provide methods for manipulating it. 如果你用反射进行黑客攻击,你最好不要将你的领域称为最终并提供操纵它的方法。

All bets are off with reflection if you insist on switching access control off and doing naughty things. 如果你坚持关闭访问控制和做顽皮的事情,所有的赌注都会被反思。

Static constants are usually inlined at compile time so changing their value probably would have no impact anyway. 静态常量通常在编译时内联,因此改变它们的值可能无论如何都没有影响。 The result really depends on how clever the optimiser is when compiling, and how clever the JIT compiler is at run time. 结果实际上取决于编译时优化器的巧妙程度,以及JIT编译器在运行时的巧妙程度。

End result: "Here be dragons, fear all who dare to tread here!" 最终结果:“这里有龙,害怕所有敢于踩到这里的人!”

Memory consistency errors happen in this scenario: 在这种情况下发生内存一致性错误:

1 thread 1 reads a field with b1.getField1() and gets 1 1个线程1使用b1.getField1()读取一个字段并获得1

2 thread 2 changes the field with b1.setField1(2) 2个线程2用b1.setField1(2)更改字段

3 now when thread 1 calls b1.getField1() it may get 1 again, because in absence of synchronization JVM is allowed to optimize this call and return a cached value. 3现在,当线程1调用b1.getField1()时,它可能再次获得1,因为在没有同步的情况下,允许JVM优化此调用并返回缓存值。

But if we initialized a mutable bean only once during instantiation (possibly with reflection, like Spring container does) and other threads will only read it after initialization, there will be no memory consistency errors even without any syncronization 但是如果我们在实例化期间只初始化一个可变bean(可能有反射,就像Spring容器一样),而其他线程只会在初始化后读取它,即使没有任何同步,也不会有内存一致性错误

The same rules apply to immutable objects when you change their fields with reflection. 当您使用反射更改其字段时,相同的规则适用于不可变对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM