【问题标题】:Variable implementing two interfaces实现两个接口的变量
【发布时间】:2017-04-20 23:45:12
【问题描述】:

我见过很多类似的问题,但我认为没有一个是完全同构的,也没有一个能完全回答我的问题。

假设有两个接口,TreeNamed。进一步假设给了我一个签名为

的方法

public <T extends Tree & Named> T getNamedTree();

如何将返回值保存到变量中,同时仍保留它同时实现TreeNamed 的信息?我找不到像

这样声明变量的方法

public <T extends Tree & Named> T mNamedTree;

并尝试将其转换为扩展 TreeNamed 的接口会导致类转换异常。

【问题讨论】:

  • 您需要知道该方法在实现中实际返回什么,从签名我可以告诉您它使用未经检查的强制转换。

标签: java generics types


【解决方案1】:

假设没有第三个接口同时继承NamedTree,您无法静态保留有关这两个接口的信息。编译器将要求您对其中一个或两者进行强制转换:

Object namedTree = getNamedTree();
Tree asTree = (Tree)namedTree;
Named asNamed = (Named)namedTree;

两个转换都应该成功。

如果您对类的 API 设计有影响,请要求作者引入结合 NamedTree 的接口,并返回该接口的实例。

【讨论】:

  • 实际上,该签名表示返回特定类型,该类型将 向上转换 到任一接口,而不是您选择显示的向下转换。实际上,向上转型与返回类型无关。泛型是关于具体类型的类型断言。例如,public <T extends Serializable & Comparable<T>> maximum(T left, T right) 可以遇到 Integer max = maximum(Integer.valueOf(102), Integer.valueOf(-1)):。没有演员表!
  • 您是否尝试在此处编译您的建议?
  • @LewBloch 它可以完美编译(参见demo)。为什么要问?
  • @LewBloch 就您的第一条评论而言,请重新阅读 OP 的问题,尤其是“进一步假设我得到一个签名为 ... 的方法”部分。他没有实现一个方法,他必须满足单个类的要求。他正在取回一个已经满足双接口要求的对象。问题是,OP 没有给出该对象类型。
【解决方案2】:

一种可能的解决方案是创建另一个 extends TreeNamedinterface,并将其存储为变量:

interface NamedTree extends Tree, Named {

}

public NamedTree namedTree;

public NamedTree getNamedTree();

【讨论】:

    【解决方案3】:

    变量必须有什么作用域?

    这里有三种可能。

    A) 变量只是一个局部变量。在这种情况下,您几乎已经有了答案……您只需要为该类型的封闭方法声明一个类型参数:

    interface ItfA { Number propA(); };
    interface ItfB { Number propB(); };
    
    class Main {
    
      private <T extends ItfA & ItfB> T getT() {
         return null;
      }
    
      private <TT extends ItfA & ItfB> void doStuffWithT() {
         TT theT = getT();
         System.err.println(theT.propA());
         System.err.println(theT.propB());
      }
    
    }
    

    B) 作用域是对象的生存期,在这种情况下是成员字段。 显而易见的答案是使类通用并且类型参数将 具有相同的&amp; 约束:

    interface ItfA { Number propA(); };
    interface ItfB { Number propB(); };
    
    class Main<T extends ItfA & ItfB> {
    
      T theT;
    
      public void setT(T newT) {
         theT = newT;
      }
    
      public void doStuffWithT() {
         System.err.println(theT.propA());
         System.err.println(theT.propB());
      }
    
    }
    

    C) 作用域是程序的生命,那么变量是静态类成员。在这里,您没有泛型解决方案。

    C.1) 显然,如果您要处理的值的类是已知的,那么您只需使用该类作为字段类型。

    C.2) 如果不是,您可以限制代码仅处理实现扩展 ItfA 和 ItfB 的接口的类。那个界面,比如ItfAB。将是字段类型。

    C.3) 现在,不强加那个约束怎么样?允许代码处理实现这些接口的任何类的对象怎么样?

    不幸的是,没有一个明确的解决方案:

    C.3.a) 您可以键入字段 Object 并提供将其作为 ItfA 或 ItfB 访问的方法(基本上隐藏了强制转换)。

    C.3.b) 或者,不是直接持有对对象的引用,而是使用实现这些接口并将对这些接口方法的调用委托给原始“T”类型值的代理对象。该代理的类本身可以是一个接受任意&lt;T extends ItfA &amp; ItfB&gt; 值的泛型(类似于上面的 B. 示例)。

    【讨论】:

    • "A" 足够接近;不完全是我希望的存在,但使用 getter(以及与内部 Object 关联的 setter)而不是直接使用变量并不太糟糕。
    猜你喜欢
    • 2018-11-11
    • 2017-08-18
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 2019-11-14
    • 2013-12-25
    • 1970-01-01
    相关资源
    最近更新 更多