更改超类从子类实现的接口值会影响所有实例

时间:2014-07-24 22:34:27

标签: java inheritance interface superclass

考虑以下计划:

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发生时打破整个元数据部分。

1 个答案:

答案 0 :(得分:3)

此处的问题是,someList隐含static(和final),因为它是在界面中定义的。

Section 9.3 of the JLS州:

  

界面正文中的每个字段声明都隐含publicstaticfinal。允许为这些字段冗余地指定任何或所有这些修饰符。

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

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

  1. 将您的界面更改为abstract课程,以便someList隐含static

  2. someList的声明移至SomeClass,这样就不会隐含static