动态更改方法的返回类型

时间:2016-02-13 22:09:44

标签: java

我想动态更改方法的返回类型。例如,我有这样的代码:

class A {

}

class B extends A {
    public void animate1() { }
    public void animate2() { }
}

class C extends A {
    public void animate3() { }
    public void animate4() { }
}

class Registry {

    private Map<String, A> mMap;

    public <T> T get(String key) {
        A data = mMap.get(key);

        /*
        * I would like to implement like this:
        * if(data.getClass() == B.class)
        *       T = B;
        * else if(data.getClass() == C.class)
        *       T = C;
        */

        return (T) data;
    }

    public void put(String key, A data) {
        mMap.put(key, data);
    }

}

现在我可以这样做:

        mRegistry.put("key_b", new B());
        mRegistry.put("key_c", new C());
        ((B) mRegistry.get("key_b")).animate1();
        ((C) mRegistry.get("key_c")).animate4();

我想实现这样的代码(没有强制转换):

        mRegistry.put("key_b", new B());
        mRegistry.put("key_c", new C());
        mRegistry.get("key_b").animate1();
        mRegistry.get("key_c").animate4();

该方法可以在某些数据中更改其后续返回类型,类似于第一个代码(注释时)。 也许有人知道,如何以另一种方式解决这个问题,但是没有在类注册表外部强制转换?

2 个答案:

答案 0 :(得分:2)

A类必须有animate1()和animate4()

class A {
    void animate1() {
        throw new UnsupportedOperationException();
    }

    void animate4() {
        throw new UnsupportedOperationException();
    }
}

所以这个编译因为get()方法返回A

mRegistry.get("key_b").animate1();
mRegistry.get("key_b").animate4();

答案 1 :(得分:1)

如果您知道密钥与类具有一对一的关系,也就是说,您知道存储的是X类型的实例但是您对保存特定实例感兴趣,则可以使用{{ 1}}令牌作为密钥:

Class

class Registry { private Map<Class<? extends A>, A> mMap; public <T extends A> T get(Class<T> key) { A data = mMap.get(key); return (T) data; } public void put(Class<? extends A> key, A data) { mMap.put(key, data); } } // Usages would look like: reg.put(C.class, new C()); C myC = reg.get(C.class); // No cast required 方法还需要使用类标记而不是使用put从值中提取类标记的原因有两个:

  1. 它允许您注册为&#34; C类&#34;的实例一个不需要完全属于C类的对象,但只能是派生类型的对象。因此,如果您有data.getClass(),则可以执行class C1 extends C,并且会在密钥reg.put(C.class, new C1());下检索该对象。
  2. 不直接禁止将C.class输入注册表(如果您想允许)。显然,特定的null实现可能不允许它,并且如果您尝试使用不存在的键,它始终是返回的默认值。但是,它可能(或可能不是)在您的设计中很重要。