未检查的转换警告

moiiocjp  于 2021-07-07  发布在  Java
关注(0)|答案(2)|浏览(258)

我的ide(intellij)警告我未经检查的转换:
未检查的重写:返回类型需要未检查的转换。找到'com.company.main.cat',需要't'
尽管如此,我的代码还是像预期的那样工作。我能做些什么来防止这个警告,还是我的代码有“设计”缺陷?
以下mcve再现了中的警告 public Cat copy() 为了 Cat .

public static void main( String[] args )
   {
      Cat cat = new Cat( "Mimi" );
      Cat copyCat = cat.copy();
   }

   public static class Cat extends Animal
   {
      public String name;

      public Cat( final String name )
      {
         this.name = name;
      }

      @Override
      public Cat copy() // Unchecked conversion warning
      {
         return new Cat( this.name );
      }

   }

   public abstract static class Animal
   {
      abstract < T extends Animal > T copy();
   }
lsmd5eda

lsmd5eda1#

如果你想要一个普通的 copy() 方法以您期望的方式工作,我会这样更改两个类:

public abstract static class Animal<T extends Animal> {
   abstract T copy();
}

public static class Cat extends Animal<Cat> {
    public String name;

    public Cat(final String name) {
        this.name = name;
    }

    @Override
    public Cat copy() {
        return new Cat(this.name);
    }
}

往这边走 Animal 类可以有泛型方法,子类可以是 Cat ,知道要为类型变量插入什么类型 T ,指定具体类。
现在, Animal.copy() 已知返回 Animal (确切地说:某种类型 T 延伸 Animal ),和 Cat.copy()Cat ,正是我们所期望的。

论方法泛型

关于方法的泛型类型参数的一个注解,如您的 Animal.copy() 方法。如果没有具有该变量类型的方法参数,则在99%的情况下都是错误的。
像这样的方法

public <T extends Animal> T copy(T originalAnimal) { ... }

会没事的。然后,参数的编译时类型告诉编译器预期的结果是什么,这是可能的(例如,使用 clone() )实现一个方法,该方法返回作为其参数的同一类的示例。
但是用这样的方法

public <T extends Animal> T copy() { ... }

编译器已经很难确定 T 类型(有时可以从变量中赋值,也可以提供 <Cat> 键入中缀)。
但更重要的是,你不知道 T 在运行时键入,并且在方法实现中没有任何可用信息 T 在某种程度上 Cat , Dog 或者别的什么。所以您不能实现遵循此签名的方法。
经验法则:与类相比,更喜欢泛型类型参数,而不是方法。

q5iwbnjs

q5iwbnjs2#

你的 Animal.copy 方法是泛型的,表明调用方可以指定他们想要的动物类型。。。但是你的实现不是通用的。
例如,这里有一个稍微扩充和修改过的代码版本—请注意 main 方法,它只使用 Animal 作为变量类型,但为 copy 方法:

public class Test {
    public static void main(String[] args) {
        Animal cat = new Cat("Mimi");
        Dog copyCat = cat.<Dog>copy();
    }

    public static class Cat extends Animal {
        public String name;

        public Cat(final String name) {
            this.name = name;
        }

        @Override
        public Cat copy() {
            return new Cat(this.name);
        }

    }

    public abstract static class Dog extends Animal {
    }

    public abstract static class Animal {
        abstract <T extends Animal> T copy();
    }
}

这个 main 方法在没有警告的情况下编译-没关系。
但在执行时:

Exception in thread "main" java.lang.ClassCastException: Test$Cat cannot be cast to Test$Dog
        at Test.main(Test.java:6)

所以是的,你的代码有一个设计缺陷,并且只在你开始的用例中按预期工作。你几乎肯定不想让这个方法泛化。您可以使类泛型化,也可以只声明抽象 copy 方法作为返回 Animal :

public abstract static class Animal {
    abstract Animal copy();
}

现在这将允许 Dog.copy() 宣布归还 Cat 当然。。。但至少很简单。

相关问题