例如,假设你有两个类:

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代码中获取了它。

其他回答

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

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

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

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

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

简单的答案

你不能直接类型转换。

解决方案

 public <T> List<T> getSubItemList(List<IAdapterImage> superList, Class<T> clazz) {
        return superList.stream()
                .map(item -> clazz.isInstance(item) ? clazz.cast(item) : null)
                .collect(Collectors.toList());
    }

使用

private final List<IAdapterImage> myList = new ArrayList<>();

List<SubType> subTypeList = getSubItemList(myList,SubType.class);

所以这是一个简单的工作,我用来转换我的列表与超级类型到列表与子类型。我们使用的是java 8中引入的流api,在我们的超列表上使用map,我们只是检查传递的参数是否是我们的超类型的实例,返回项目。最后,我们收集成一个新的列表。当然,我们需要把result放到一个新的列表中。

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代码中获取了它。

最安全的方法是实现AbstractList并在实现中强制转换项。我创建了ListUtil helper类:

public class ListUtil
{
    public static <TCastTo, TCastFrom extends TCastTo> List<TCastTo> convert(final List<TCastFrom> list)
    {
        return new AbstractList<TCastTo>() {
            @Override
            public TCastTo get(int i)
            {
                return list.get(i);
            }

            @Override
            public int size()
            {
                return list.size();
            }
        };
    }

    public static <TCastTo, TCastFrom> List<TCastTo> cast(final List<TCastFrom> list)
    {
        return new AbstractList<TCastTo>() {
            @Override
            public TCastTo get(int i)
            {
                return (TCastTo)list.get(i);
            }

            @Override
            public int size()
            {
                return list.size();
            }
        };
    }
}

您可以使用cast方法盲目地转换列表中的对象,并使用convert方法进行安全转换。 例子:

void test(List<TestA> listA, List<TestB> listB)
{
    List<TestB> castedB = ListUtil.cast(listA); // all items are blindly casted
    List<TestB> convertedB = ListUtil.<TestB, TestA>convert(listA); // wrong cause TestA does not extend TestB
    List<TestA> convertedA = ListUtil.<TestA, TestB>convert(listB); // OK all items are safely casted
}