Java集合通过可覆盖变量提供类型

时间:2014-06-23 19:41:51

标签: java

示例代码:

public abstract class AbstractEvent
{
    // extended by AbstractEvent subclasses, used as a lambda function interface
    // (all sub-interfaces define one method)
    public interface EventListener
    {
    }
    // assigned by subclasses in a static block
    protected static Class<? extends EventListener> listenerClass;
    // this line obviously does not work
    protected static Set<listenerClass> listeners = new HashSet<>();

    public final boolean addListener(listenerClass listener)
    {
        return listeners.add(listener);
    }

    public final boolean removeListener(listenerClass listener)
    {
        return listeners.remove(listener);
    }
}

这样的东西甚至可以在Java中使用,如果是这样,怎么样? 我在Scala中通过在抽象类中定义一个没有body的类型并在子类中定义它(并且它工作得很好)来创建它,但是我还想在Java中创建它。

关键是我想避免在AbstractEvent的所有子类中复制set代码。

2 个答案:

答案 0 :(得分:2)

您可以使用泛型完成此操作:

public abstract class AbstractEvent<T extends EventListener>
{
    public interface EventListener
    {
    }

    protected static Set<T> listeners = new HashSet<T>();

    public final boolean addListener(T listener)
    {
        return listeners.add(listener);
    }

    public final boolean removeListener(T listener)
    {
        return listeners.remove(listener);
    }
}

编辑1: 为避免必须为每个接口创建单独的文件,您可以使用以下代码:

public static void main(String[] args)
{
    EventListener anEventListener = new EventListener() {
       // Any methods that you override for EventListener go in here
    };

    SomeEvent evt = new SomeEvent();

    // You can even pass an anonymous one as a parameter.
    evt.addListener(new EventListener() {
    });
} 

您也可以执行以下操作:

public class SomeClass
{
    // This event listener is a private member of a class
    private EventListener mEventListener = new EventListener() {
           // Any methods that you override for EventListener go in here
    };
}

答案 1 :(得分:1)

您不能覆盖静态变量(请参阅Is there a way to override class variables in Java?),并且从子类的静态块为protected static变量赋值将无法正常工作:

class Base {
    protected static String value = "Base";

    public static String getValue() {
        return value;
    }
}

class Derived extends Base {
    static {
        value = "Derived";
    }
}

class Main {
    public static void main(String[] args) throws Exception {
        // Make sure we run static initializer for Derived class
        Class.forName("Derived");
        System.out.println(Derived.getValue());
        System.out.println(Base.getValue());
    }
}

这将打印:

Derived
Derived

这可能不是你想要的。出于同样的原因,您当前的代码将listeners设置为在不同的子类之间共享。

如果您对addListenerremoveListener非静态感觉不错,可以选择以下内容:

// AbstractEvent.java
public abstract class AbstractEvent<T extends AbstractEvent.EventListener> {
    public interface EventListener { }

    protected static Map<Class<? extends AbstractEvent>, Set<EventListener>> listeners = new HashMap<>();

    public final boolean addListener(T listener) {
        Set<EventListener> eventListeners = listeners.getOrDefault(getClass(), new HashSet<>());
        if (!listeners.containsKey(getClass())) {
            listeners.put(getClass(), eventListeners);
        }
        return eventListeners.add(listener);
    }

    public final boolean removeListener(T listener) {
        Set<EventListener> eventListeners = listeners.get(getClass());
        if (eventListeners != null) {
            return eventListeners.remove(listener);
        }
        return false;
    }
}

// SomeEvent.java
public class SomeEvent extends AbstractEvent<SomeEvent.SomeEventListener> {
    public interface SomeEventListener extends AbstractEvent.EventListener {
        void someMethod();
    }
}

如果您想要addListenerremoveListener静态,那么泛型不会帮助您,因为您无法从静态方法引用类型参数。在这种情况下,我担心你将不得不在每个子类中明确声明它们。