有没有办法转换这些不可转换的类型?

时间:2013-10-02 14:09:36

标签: java generics

乍一看,我原本希望能够施展

ArrayList<Class<? extends Interface1>> 

ArrayList<Class<?>>

因为第二个显然是第一个限制较少的版本。但是,以下代码无法编译:

import java.util.ArrayList;

public class TypeInvocationConversionTest
{
  private static ArrayList<Class<? extends Interface1>> classList;

  private static ArrayList<Class<?>> lessRestrictiveClassList;

  public static void main(String[] args)
  {
    classList = new ArrayList<Class<? extends Interface1>>();
    lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
  }

  private interface Interface1 {}
}

但产生错误

TypeInvocationConversionTest.java:12: inconvertible types
found   : java.util.ArrayList<java.lang.Class<? extends TypeInvocationConversionTest.Interface1>>
required: java.util.ArrayList<java.lang.Class<?>>
    lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
                                                     ^

我不认为想要转换这两种类型是不合理的:为了激励,这里有一个与我实际处理的更接近的简短程序(此代码无法编译):

import java.util.ArrayList;

public class Mammal
{
  public void produceMilk() {}
}

public class Reptile
{
  public void layEggs() {}
}

public interface Species
{
  String getSpeciesName();
}

public class Dog extends Mammal
  implements Species
{
  @Override
  public String getSpeciesName()
  {
    return "Canis lupus familiaris";
  }
}

public class Cat extends Mammal
  implements Species
{
  @Override
  public String getSpeciesName()
  {
    return "Feles catus";
  }
}

public class Boa extends Reptile
  implements Species
{
  @Override
  public String getSpeciesName()
  {
    return "Boa constrictor";
  }
}

public class Panel3 extends Reptile
  implements Species
{
  @Override
  public String getSpeciesName()
  {
    return "Dromiceiomimus brevitertius";
  }
}

public class AnimalFunTime
{
  public static void main(String[] args)
  {
    ArrayList<Class<? extends Mammal>> listOfMammals;
    ArrayList<Class<? extends Reptile>> listOfReptiles;
    ArrayList<ArrayList<Class<?>>> matrixOfAnimals;

    listOfMammals.add(Dog.class);
    listOfMammals.add(Cat.class);

    listOfReptiles.add(Boa.class);
    listOfReptiles.add(Panel3.class);

    ///////////////////////////////////////////////////////////////////////////
    // The following two lines cause an error.                                //
    ///////////////////////////////////////////////////////////////////////////
    matrixOfAnimals.add( (ArrayList<Class<?>>) listOfMammals);
    matrixOfAnimals.add( (ArrayList<Class<?>>) listOfReptiles);

    // Get milk.
    for (int i = 0 ; i < listOfMammals.size() ; i++) {
      listOfMammals.get(i).produceMilk();
    }

    // Get eggs.
    for (int i = 0 ; i < listOfReptiles.size() ; i++) {
      listOfReptiles.get(i).layEggs();
    }

    // Display all the animals' names.  
    for (int j = 0 ; j < matrixOfAnimals.size() ; j++) {
      ArrayList<Class<?>> currentFamily = matrixOfAnimals.get(j);
      for (int i = 0 ; i < currentFamily.size() ; i++) {
        Class<?> currentAnimal = currentFamily.get(i);
        if (Species.isAssignableFrom(currentAnimal) {
          System.out.println(currentAnimal.getSpeciesName());
        }
        else
        {
          throw new SpeciesNotImplementedException("Please tell us the animal's name!");
        }
      }
    }
  }
}

正如评论所说,此代码无法编译,因为我无法创建包含ArrayList<Class<? extends Mammal>>ArrayList<Class<? extends reptile>>对象的列表。如果我可以将它们都转换为ArrayList<Class<?>> s,那就没关系了。有没有办法进行演员表这样的事情有效吗?

4 个答案:

答案 0 :(得分:5)

这不会(也不应该)起作用的原因之一是lessRestrictiveClassList会引用与classList相同的列表对象。因此,如果您将Class<?>类型的对象(其中?未扩展Interface1)添加到该列表中,则classList的合同突然被破坏:

ArrayList<Class<? extends Interface1>> classList = new ArrayList<>();

// assume this is allowed:
ArrayList<Class<?>> lessRestrictiveClassList = (ArrayList<Class<?>>) classList;

// now add an element to the less restrictive list
lessRestrictiveClassList.add(String.class);

// and obtain it from the original list
// this code will crash, because String does not implement Interface1
Class<? extends Interface1> cls = classList.get(0);

最后一行会遇到大问题,因为它可能会导致意外的代码失败。

您应该复制到限制较少的列表,而不是两次引用数组列表:

ArrayList<Class<? extends Interface1>> classList = new ArrayList<>();
ArrayList<Class<?>> lessRestrictiveClassList = new ArrayList<>();

lessRestrictiveClassList.addAll(classList);

答案 1 :(得分:3)

忘记泛型并转换为原始类型ArrayList。

ArrayList<ArrayList> matrixOfAnimals = new ArrayList<>();
matrixOfAnimals.add(listOfMammals);

答案 2 :(得分:3)

  

因为第二个显然是第一个限制较少的版本。

不是。即使List<A>List<B>的子类型,A也不是B的子类型。 Heuster说明了为什么它不安全。

如果您不需要使用第二个列表引用添加元素,则应使用ArrayList<? extends Class<?>>。您可以ArrayList<Class<? extends Interface1>>转换为该内容。

答案 3 :(得分:2)

你可以通过连续两次演员来完成你想要的演员表:

lessRestrictiveClassList = (ArrayList<Class<?>>) (ArrayList<?>) classList;

编译。