Java 对象';即使不使用put(),也会更改映射中的属性?

Java 对象';即使不使用put(),也会更改映射中的属性?,java,dependency-injection,inversion-of-control,Java,Dependency Injection,Inversion Of Control,嗨,我从一本书上得到了密码: public class Container { Map<String, Object> components; public Container() { components = new HashMap<String, Object>(); Properties properties = new Properties(); try { proper

嗨,我从一本书上得到了密码:

public class Container {

    Map<String, Object> components;

    public Container() {
        components = new HashMap<String, Object>();

        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("components.properties"));
            for (Map.Entry entry : properties.entrySet()) {
                String key = (String) entry.getKey();
                String value = (String) entry.getValue();
                processEntry(key, value);
            }
        } catch (Exception ex) {
            throw new RuntimeException();
        }

    }

    private void processEntry(String key, String value) throws Exception {
        String parts[] = key.split("\\.");

        if (parts.length == 1) {
            Object component = Class.forName(value).newInstance();
            components.put(parts[0], component);
        } else {
            Object component = components.get(parts[0]);
            Object reference = components.get(value);
            PropertyUtils.setProperty(component, parts[1], reference);
        }

    }

    public Object getComponent(String id) {
        return components.get(id);
    }

}

贴图中对象的属性已更改。即使在属性更新后,地图中没有组件.put()来更新对象,对象也会更新。为什么呢

这是因为地图只包含对对象的引用,而不是对象的副本

当您更改对象中的某个内容时,您可以看到该更改,无论您是通过地图中的引用还是不通过地图中的引用

这与做(说)完全相同:


这里,第一个
和第二个
都是对同一个
StringBuilder
对象的引用。。。当您通过
first.append()
更改该对象的内容时,当您通过下一行中的
second
引用查看该对象时,该更改仍然可见。

在java中,每个对象都是对一个对象的引用。因此,如果在地图中放置对象,则只存储引用,而不存储对象的副本。因此,从地图上查找地图时,将看到地图中对象的每次更新。因为从映射检索同一对象时,您将获得对该对象的引用。

Java中的所有句柄(其中句柄是字段、变量等)都是引用,而不是对象本身的副本

您遇到的问题是因为您的对象是可变的,即它们具有更改内部状态(写入所述对象字段的内容)的setter或类似方法。防止系统中任何地方发生您希望阻止的更改的唯一方法是将不应更改的内容建模为不可变类

不变性 创建不可变的类通常被认为是良好的实践。不可变类只会写入构造函数中的字段。Immutable类上的所有其他方法都是只读的

JDK包含几个不可变类的好例子,包括:

  • String,所有方法都创建一个新字符串,通常共享原始字符串中的char[]
  • 整数和所有其他基本包装器
建设者
生成器模式可用于使用多个setter逐步创建可变对象。完成后,可以调用build方法来创建不可变对象。StringBuilder/Buffer是产品字符串生成器模式的好例子。

说每个对象都是对象的引用是不准确的,因为这是一个无限递归语句。您应该说每个变量都是对对象的引用,不包括基元类型变量。
PropertyUtils.setProperty(component, parts[1], reference);
StringBuilder first = new StringBuilder();
StringBuilder second = first;

first.append("Hello");
System.out.println(second); // Prints "Hello"