我的 Runnable 实现无法解析已声明接口的对象上的方法

My implementation of a `Runnable` cannot resolve a method on an object of a declared interface

我在 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) 中的编译器无法解析 run 方法的 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) and 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();
    }
}

当运行:

Hello World!

monster = Witch[name=Rowena]

This monster Witch named Rowena casts a spell.

签名 public class MonsterRunnable < Monster > implements RunnableMonsterRunnable 引入了通用参数 Monster。通用参数使 class .. 通用。这意味着您可以将 class 与任何类型一起使用。

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

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

你要的是monster是扩展Monster的类型,简单继承。因此,只需删除通用参数即可获得所需内容:

public class MonsterRunnable implements Runnable

您在评论区的留言:

The actually goal of this entire experiment was to get a generics type declared for a Runnable implementation.

你需要说明 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.