Consider the following program:
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();
}
The program, when run, outputs the following:
after: a
The first debug message is not sent, because the list of the first instance of SomeSubclass is empty. However, once an element is added to the list of the second instance, the first instance also has the element added. This occurs when compiled and run with JDK 1.8 and Java SE 8, respectively. From what I understand, it shouldn't be happening. Is it intentional, and if so, what is the proper way of accomplishing this task?
I also feel as though I should mention the practical implementation of this simplified code. An API I'm maintaining has a class in it which implements an interface called Metadatable, which stores a map of metadata of its instances. This class in recent snapshots may be overridden by the program using the API via a method, and when this is done, metadata effectively becomes static. Needless to say, this breaks the entire metadata portion of the API when it happens.
The problem here is that someList
is implicitly static
(and final
) because it's defined in an interface.
Section 9.3 of the JLS states:
Every field declaration in the body of an interface is implicitly
public
,static
, andfinal
. It is permitted to redundantly specify any or all of these modifiers for such fields.
There is only one instance of someList
for the entire interface, so all implementing classes and subclasses are operating on the same list.
You can do one of two things:
Change your interface into an abstract
class, so that someList
isn't implicitly static
.
Move the declaration of someList
into SomeClass
so it's not implicitly static
.