【问题标题】:My implementation of a `Runnable` cannot resolve a method on an object of a declared interface [duplicate]我的“Runnable”实现无法解析声明接口的对象上的方法[重复]
【发布时间】:2020-12-06 23:24:56
【问题描述】:

我在 Java 15 中有一个简单的 Runnable 实现。

package work.basil.example;

public class MonsterRunnable < Monster > implements Runnable
{
    private final Monster monster;

    // Constructor
    public MonsterRunnable ( Monster monster )
    {
        this.monster = monster;
    }

    @Override
    public void run ( )
    {
        this.monster.actOut(); // ???? Compiler error: Cannot resolve method 'actOut' in 'Monster'
    }
}

我的 IDE (IntelliJ 2020.3) 中的编译器无法解析 this.monster.actOut(); 方法的 this.monster.actOut(); 行上的方法 actOut

然而,该方法在接口上已明确定义,如下所示。

package work.basil.example;

public sealed interface Monster
        permits Demon, Witch
{
    String name ( ); // This getter method implemented implicitly by `record` in our concrete classes `Demon` & `Witch`.

    public void actOut ( );  // ???? Method is declared, yet cannot be resolved in `Runnable`. 
}

我的小演示应用正在使用 Java 15 预览功能 JEP 360: Sealed Classes (Preview)JEP 384: Records (Second Preview)。但我看不出这可能会成为麻烦的根源。


我想上面的代码应该足够了。但我可以展示接口的一对实现,DemonWitch

package work.basil.example;

public record Demon(String name) implements Monster
{
    @Override
    public void actOut ( )
    {
        System.out.println( "This monster " + this.getClass().getSimpleName() + " named " + this.name + " buys a soul." );
    }
}

……和……

package work.basil.example;

public record Witch(String name) implements Monster
{
    @Override
    public void actOut ( )
    {
        System.out.println( "This monster " + this.getClass().getSimpleName() + " named " + this.name + " casts a spell." );
    }
}

最后,这里是 actOut 方法工作的演示 - 如果我在有问题的 run 方法中删除 this.monster.actOut(); 行。

package work.basil.example;

/**
 * Hello world!
 */
public class MonterMash
{
    public static void main ( String[] args )
    {
        System.out.println( "Hello World!" );
        MonterMash monterMash = new MonterMash();
        monterMash.demo();
    }

    private void demo ( )
    {
        Monster monster = new Witch( "Rowena" );
        System.out.println( "monster = " + monster );
        monster.actOut();
    }
}

运行时:

世界你好!

怪物 = 女巫[name=Rowena]

这个名叫罗薇娜的怪物女巫会施法。

【问题讨论】:

  • 问题是你使用 Monster 作为你的泛型类型。尝试使其不通用:public class MonsterRunnable { 或者如果它需要通用使用 T
  • @sprinter 是的!删除泛型作品。将public class MonsterRunnable &lt; Monster &gt; implements Runnable 更改为public class MonsterRunnable implements Runnable 会使编译器满意。但为什么?整个实验的实际目标是为Runnable 实现声明一个泛型类型。请发布一个答案让我接受。
  • 因为Monster 只使用了一个没有边界的泛型类型,所以它可以是任何东西。就像List&lt;E&gt; 一样,E 也可以是任何东西(这里你的MonsterE 完全相同)。这就是为什么你应该很少对泛型类型使用实际的词,这可能会造成混淆。

标签: java interface compiler-errors runnable


【解决方案1】:

签名public class MonsterRunnable &lt; Monster &gt; implements RunnableMonsterRunnable 引入了一个通用参数Monster。泛型参数使类.. 泛型。这意味着您可以使用任何类型的类。

例如当您使用List&lt;String&gt; 时,&lt;String&gt; 是参数,即元素的类型。 List 本身被声明为 public interface List&lt;E&gt; extends Collection&lt;E&gt;。注意E 是通用参数; List&lt;String&gt; 类型的变量使用该参数来引用Strings 的列表。您还可以参考Integers 的列表:List&lt;Integer&gt;。您可以通过具有泛型参数EList 与任何元素类型一起使用,因为它是泛型的。 E 用于“元素”并且是 Java 约定:参见 Type Parameter Naming ConventionsEList中使用,表示方法等。

因此,在您的示例中,泛型参数Monster“隐藏”了Monster 类型,即您的 类。引入的泛型类型Monster 没有方法actOut,这是编译器告诉你的。

您想要的是monster 是扩展Monster 的类型,简单继承。因此,只需删除通用参数,您就会得到您想要的:

public class MonsterRunnable implements Runnable

您在评论部分的注释:

整个实验的实际目标是为 Runnable 实现声明一个泛型类型。

你需要表示MonsterRunnable中的泛型是Monster的实现:

package work.basil.example;

public class MonsterRunnable < T extends Monster > implements Runnable
{
    private final T monster;

    // Constructor
    public MonsterRunnable ( T monster )
    {
        this.monster = monster;
    }

    @Override
    public void run ( )
    {
        this.monster.actOut();
    }
}

现在MonsterRunnable 是通用的,使用T,它仅限于扩展(实现)Monster

【讨论】:

    猜你喜欢
    • 2013-04-23
    • 2013-09-23
    • 2013-05-05
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多