gpt4 book ai didi

java - 在运行时创建 DEEP 不可变对象(immutable对象)

转载 作者:搜寻专家 更新时间:2023-10-31 20:00:44 25 4
gpt4 key购买 nike

我需要使用 Java 在运行时创建对象的不可变副本。我使用了 org.springframework.cglib.beans.ImmutableBean,它可以使用 CGLIB 创建对象的不可变副本。

但问题在于它提供了“一级”不变性:它不允许更改输入对象的属性,但是它允许更改内部对象(例如获取集合并向其添加元素或者获取内部对象并修改它的参数等)

所以问题是:创建对象的深层(递归)不可变副本的正确方法是什么,这样就不能(在任何嵌套级别)更改内部对象?

最佳答案

您可以遍历对象树并使用 CGLIB 通过使用跳过所需方法的拦截器使每个对象不可变。但困难的部分是确定修改对象状态的所有方法 - 对于树中的每个对象。

package ut.test;

import static org.junit.Assert.assertEquals;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import com.google.common.collect.Lists;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyTest {

public static class Inner {
private String data = "hello";

public Inner() {}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

@Override
public String toString() {
return data;
}

}

public static class Outer {
private List<Inner> list = Lists.newArrayList(new Inner());

public Outer() {}

public List<Inner> getList() {
return list;
}

public void setList(List<Inner> list) {
this.list = list;
}
}

public static class GetOnlyDelegatingMethodInterceptor implements MethodInterceptor {
private Object delegate;

public GetOnlyDelegatingMethodInterceptor(Object delegate) {
this.delegate = delegate;
}

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getName().startsWith("get")) {
return makeImmutable(proxy.invoke(delegate, args));
}

if (method.getName().equals("toString")) {
return proxy.invoke(delegate, args);
}

if (method.getDeclaringClass().equals(Object.class)) {
return proxy.invoke(delegate, args);
}

// you may check for other methods here

// skip all others
return null;
}
}

private static Object makeImmutable(Object obj) {
if (obj == null) {
return obj;
}

Enhancer e = new Enhancer();
e.setSuperclass(obj.getClass());
e.setCallback(new GetOnlyDelegatingMethodInterceptor(obj));
return e.create();
}

@Test
public void testImmutable() {
Outer outerImmutable = (Outer) makeImmutable(new Outer());

// this is initial state
assertEquals(outerImmutable.getList().toString(), "[hello]");

// trying to set empty list
outerImmutable.setList(new ArrayList<>());
// but it's still the same
assertEquals(outerImmutable.getList().toString(), "[hello]");

// going deeper
outerImmutable.getList().get(0).setData("bye!");
// but still no changes
assertEquals(outerImmutable.getList().toString(), "[hello]");
}
}

关于java - 在运行时创建 DEEP 不可变对象(immutable对象),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35943632/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com