【问题标题】:Changing value of interface implemented by superclass from subclass affects all instances [duplicate]从子类更改超类实现的接口的值会影响所有实例[重复]
【发布时间】:2014-09-16 16:22:56
【问题描述】:

考虑以下程序:

SomeClass.java:

package somepackage;

import java.util.List;

public class SomeClass implements SomeInterface {

    public SomeClass(boolean add){}

    public static void main(String[] args){
        SomeSubclass sub1 = new SomeSubclass(false);
        for (String s : sub1.getList())
            System.out.println("before: " + s);
        SomeSubclass sub2 = new SomeSubclass(true);
        for (String s : sub1.getList())
            System.out.println("after: " + s);
    }

    @Override
    public void addToList(String s) {
        someList.add(s);
    }

    @Override
    public List<String> getList() {
        return someList;
    }

}

SomeSubclass.java:

package somepackage;

public class SomeSubclass extends SomeClass {

    public SomeSubclass(boolean add){
        super(add);
        if (add)
            this.addToList("a");
    }

}

SomeInterface.java:

package somepackage;

import java.util.ArrayList;
import java.util.List;

public interface SomeInterface {

    List<String> someList = new ArrayList<String>();

    public void addToList(String s);

    public List<String> getList();

}

程序在运行时会输出以下内容:

after: a

第一个调试消息没有发送,因为 SomeSubclass 的第一个实例的列表是空的。但是,一旦将元素添加到第二个实例的列表中,第一个实例也会添加该元素。这分别在使用 JDK 1.8 和 Java SE 8 编译和运行时发生。据我了解,这不应该发生。是否是故意的,如果是,完成这项任务的正确方法是什么?

我也觉得我应该提到这个简化代码的实际实现。我正在维护的 API 中有一个类,它实现了一个名为 Metadatable 的接口,该接口存储其实例的元数据映射。最近快照中的此类可能会被使用 API 的程序通过方法覆盖,完成此操作后,元数据有效地变为静态。不用说,这会破坏 API 的整个元数据部分。

【问题讨论】:

  • 我认为这绝对应该发生。因为那是您打印调试消息的地方。在此之前,它只存储消息,不做任何事情。
  • 虽然 Java 8 引入了行为的多重继承(通过默认方法),但 Java 中仍然没有状态的多重继承。接口无法定义instance variables

标签: java inheritance interface superclass


【解决方案1】:

这里的问题是someList 隐含地是static(和final),因为它是在接口中定义的。

Section 9.3 of the JLS 状态:

接口主体中的每个字段声明都隐含为publicstaticfinal。允许为此类字段冗余地指定任何或所有这些修饰符。

整个接口只有一个someList 实例,所以所有实现类和子类都在同一个列表上运行。

您可以做以下两件事之一:

  1. 将您的接口更改为abstract 类,这样someList 就不会隐含static

  2. someList 的声明移动到SomeClass,这样它就不是隐含的static

【讨论】:

    猜你喜欢
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多