例如,假设你有两个类:

public class TestA {}
public class TestB extends TestA{}

我有一个返回List<TestB>的方法,我想将该列表中的所有对象强制转换为TestB,以便最终得到List<TestB>。


当前回答

class MyClass {
  String field;

  MyClass(String field) {
    this.field = field;
  }
}

@Test
public void testTypeCast() {
  List<Object> objectList = Arrays.asList(new MyClass("1"), new MyClass("2"));

  Class<MyClass> clazz = MyClass.class;
  List<MyClass> myClassList = objectList.stream()
      .map(clazz::cast)
      .collect(Collectors.toList());

  assertEquals(objectList.size(), myClassList.size());
  assertEquals(objectList, myClassList);
}

这个测试演示了如何将List<Object>转换为List<MyClass>。但是需要注意的是,objectList必须包含与MyClass相同类型的实例。当List<T>使用时,可以考虑这个例子。为此,在构造函数中获取字段Class<T> clazz,并使用它来代替MyClass.class。

更新

实际上,在强类型Java AFAIK中,你不能从超类型转换为子类型。但是可以引入超类型实现的接口。

interface ITest {
}

class TestA implements ITest {
}

class TestB extends TestA {
}

public class Main {

  public static void main(String[] args) {
    List<ITest> testAList = Arrays.asList(new TestA(), new TestA());

    Class<ITest> clazz = ITest.class;
    List<ITest> testBList = testAList.stream()
        .map(clazz::cast)
        .collect(Collectors.toList());

    System.out.println(testBList.size());
    System.out.println(testAList);
  }
}

或者可以从子类型转换为超类型。是这样的:

class TestA {
}

class TestB extends TestA {
}

public class Main {

  public static void main(String[] args) {
    var a = new TestA();
    var b = new TestB();
    System.out.println(((TestA) b));

    List<TestB> testBList = Arrays.asList(new TestB(), new TestB());

    Class<TestA> clazz = TestA.class;
    List<TestA> testAList = testBList.stream()
        .map(clazz::cast)
        .collect(Collectors.toList());

    System.out.println(testAList.size());
    System.out.println(testAList);
  }
}

供参考,我最初的答案指出了与泛型一起使用它的可能性。事实上,我从Hibernate DAO代码中获取了它。

其他回答

简单地转换为List<TestB>就可以了;但它不起作用,因为您不能将一个参数的泛型类型强制转换为另一个参数。然而,你可以通过一个中间通配符类型进行强制转换,这是允许的(因为你可以强制转换到通配符类型,只是有一个未选中的警告):

List<TestB> variable = (List<TestB>)(List<?>) collectionOfListA;

在Java 8中,实际上可以做到

List<TestB> variable = collectionOfListA
    .stream()
    .map(e -> (TestB) e)
    .collect(Collectors.toList());

泛型的强制转换是不可能的,但是如果你以另一种方式定义列表,则可以将TestB存储在其中:

List<? extends TestA> myList = new ArrayList<TestA>();

在使用列表中的对象时,仍然需要进行类型检查。

很奇怪,手动强制转换列表仍然没有提供一些实现如下功能的工具箱:

@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T extends E, E> List<T> cast(List<E> list) {
    return (List) list;
}

当然,这不会逐个检查项,但如果我们清楚地知道我们的实现只提供子类型,那么这正是我们在这里要避免的。

class MyClass {
  String field;

  MyClass(String field) {
    this.field = field;
  }
}

@Test
public void testTypeCast() {
  List<Object> objectList = Arrays.asList(new MyClass("1"), new MyClass("2"));

  Class<MyClass> clazz = MyClass.class;
  List<MyClass> myClassList = objectList.stream()
      .map(clazz::cast)
      .collect(Collectors.toList());

  assertEquals(objectList.size(), myClassList.size());
  assertEquals(objectList, myClassList);
}

这个测试演示了如何将List<Object>转换为List<MyClass>。但是需要注意的是,objectList必须包含与MyClass相同类型的实例。当List<T>使用时,可以考虑这个例子。为此,在构造函数中获取字段Class<T> clazz,并使用它来代替MyClass.class。

更新

实际上,在强类型Java AFAIK中,你不能从超类型转换为子类型。但是可以引入超类型实现的接口。

interface ITest {
}

class TestA implements ITest {
}

class TestB extends TestA {
}

public class Main {

  public static void main(String[] args) {
    List<ITest> testAList = Arrays.asList(new TestA(), new TestA());

    Class<ITest> clazz = ITest.class;
    List<ITest> testBList = testAList.stream()
        .map(clazz::cast)
        .collect(Collectors.toList());

    System.out.println(testBList.size());
    System.out.println(testAList);
  }
}

或者可以从子类型转换为超类型。是这样的:

class TestA {
}

class TestB extends TestA {
}

public class Main {

  public static void main(String[] args) {
    var a = new TestA();
    var b = new TestB();
    System.out.println(((TestA) b));

    List<TestB> testBList = Arrays.asList(new TestB(), new TestB());

    Class<TestA> clazz = TestA.class;
    List<TestA> testAList = testBList.stream()
        .map(clazz::cast)
        .collect(Collectors.toList());

    System.out.println(testAList.size());
    System.out.println(testAList);
  }
}

供参考,我最初的答案指出了与泛型一起使用它的可能性。事实上,我从Hibernate DAO代码中获取了它。