Java 反射和不变性应该如何协同工作

Java 反射和不变性应该如何协同工作,java,reflection,concurrency,jvm,immutability,Java,Reflection,Concurrency,Jvm,Immutability,据了解,不可变对象是线程安全的,不需要同步。但是,可以使用反射更新最终字段的值: package com.stackoverflow; import java.lang.reflect.Field; public class WhatsGoingOn { static class Immutable { private final int value; public Immutable(int value) { this.v

据了解,不可变对象是线程安全的,不需要同步。但是,可以使用反射更新最终字段的值:

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());
    }
}
考虑到依赖反射的框架的数量(Spring和Hibernate只是少数),我很好奇spec对这个场景怎么说。例如,若我将字段更新放在同步块中,那个么这将保证在其他线程中的可见性,或者值将按照规范缓存在寄存器中,以供最终使用


如果你坚持关闭访问控制并做一些淘气的事情,那么所有的赌注都会随着反射而取消

静态常量通常在编译时内联,因此更改它们的值可能不会产生任何影响。结果实际上取决于优化程序在编译时的聪明程度,以及JIT编译器在运行时的聪明程度


最终结果:“这里有龙,害怕所有敢于践踏这里的人!”

在这种情况下会发生内存一致性错误:

1线程1读取带有b1.getField1()的字段并获取1

2线程2用b1更改字段。设置字段1(2)

3现在,当线程1调用b1.getField1()时,它可能会再次得到1,因为在没有同步的情况下,JVM可以优化此调用并返回缓存值

但是,如果我们在实例化期间只初始化了一次可变bean(可能是使用反射,就像Spring容器那样),而其他线程只在初始化之后读取它,那么即使没有任何同步,也不会出现内存一致性错误

使用反射更改不可变对象的字段时,同样的规则也适用于不可变对象

如果对象的状态在构造后无法更改,则认为该对象是不可变的。

您正在将该对象用作可变对象,因为您正在更改其状态

确实,反射的使用打破了教程中定义的不变性,因为您可以使用它来更改非常量的final字段

抗反射不可变对象的示例如下:

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());
}
在这种情况下,反射测试将失败,并且该值将保持为
Integer.MIN\u value
。但是,我们可以使用本机代码或内存编辑器将该值更改为其他值

如果您深入到使用反射进行黑客攻击,那么最好不要调用字段final并提供操作方法