获取List中的元素类型

时间:2018-05-15 20:41:57

标签: java list generics

我有两个不同的列表:

List<MyFirstClass> list1;
List<MySecondClass> list2;

现在我需要一个以List作为输入的方法。我在这个方法中所做的事情对于两个列表几乎是相同的,只是略有不同。因为我不能超载它们,所以我这样做了:

private String myMethod(List<?> myList) {...}

但是现在我需要检查?是什么类型,以便在方法中给出与list-element-type相关的差异。

我该怎么做?或者有更好的方法吗?

谢谢!

修改 除了一个方法调用list1.method1()list2.method2()之外,这两种方法实际上是相同的。这就是为什么我不想制作两种不同的方法。

5 个答案:

答案 0 :(得分:5)

文字解决方案是使用instanceof来区分对象的类型。

private void myMethod(List<?> list) {
    for(Object o : list) {
        if(o instanceof MyFirstClass) {
            MyfirstClass p = (MyFirstClass)o;
            p.myFirstMethod();
        } else if(o instanceof MySecondClass) {
            MySecondClass p = (MyFirstClass)o;
            p.mySecondMethod();
        }
    }
}

如果项目的设计约束是不可变的,那么这是您的最佳解决方案。

但更好的解决方案是使用继承

这个问题确实证明了你的整体设计几乎肯定存在缺陷。如果您事先无法知道自己是否会获得List<MyFirstClass>List<MySecondClass>,那么您的证据很明确问题域。通过使它们实现一个接口来指示在这种情况下行为应该如何不同,强制执行必要的约束要好得多。

public interface MyInterface {
    void invokeMyMethod();
}

public class MyFirstClass implements MyInterface {
    public void invokeMyMethod() {myFirstMethod();}
    /*...*/
}
public class MySecondClass implements MyInterface {
    public void invokeMyMethod() {mySecondMethod();}
    /*...*/
}

//In some other class...

private void myMethod(List<MyInterface> list) {
    for(MyInterface o : list) {
        o.invokeMyMethod();
    }
}

myMethod也可以在这种情况下重写,您不确定自己是否会获得List<MyFirstClass>List<MySecondClass>List<MyInterface>:< / p>

private <T extends MyInterface> void myMethod(List<T> list) {
    for(MyInterface o : list) {
        o.invokeMyMethod();
    }
}

答案 1 :(得分:0)

您可以使用继承来解决问题。为此,请使两个类继承自公共基类(或接口)。然后创建一个List来存储子类的元素。存储子类中每种类型特定的特殊逻辑。这是一个例子:

class BaseClass {
  public void foo() {}
}

class ClassA extends BaseClass {
  public void foo() { /* ClassA logic here */ }
}

class ClassB extends BaseClass {
  public void foo() { /* ClassB logic here */ }
}

List<BaseClass> list = new ArrayList<BaseClass>();
list.add(new ClassA());
list.add(new ClassB());
for(BaseClass element : list) {
  element.foo();
}

答案 2 :(得分:0)

您无法根据List<?>中的类型直接调整您的方法。不过,还有其他方法可以获得你想要的东西。这是一种方式(这些名称会很糟糕,因为我没有为你正在尝试做的事情提供很多背景信息):

interface MethodCaller<T> {
  void callMethod(T target);
}

class Class1Caller implements MethodCaller<MyFirstClass> {
  @Override
  public void callMethod(MyFirstClass target) {
    target.method1();
  }
}

class Class1Caller implements MethodCaller<MySecondClass> {
  @Override
  public void callMethod(MySecondClass target) {
    target.method2();
  }
}

然后更改您的方法以获取与列表相同类型的MethodCaller,如下所示:

private <T> String myMethod(List<T> myList, MethodCaller<T> methodCaller) {
   // wherever you'd call your method, instead use methodCaller.callMethod() instead
}

现在要调用您的方法,您可以使用myMethod(list1, new Class1Caller())myMethod(list2, new Class2Caller())

答案 3 :(得分:0)

您可以使用lambda来提取不同的调用,并将其作为参数传递给您的方法:

private <T> myMethod(List<? extends T> myList, Consumer<T> method) {
    for (T item : myList) {
        // some stuff
        method.accept(item);
    }
}

然后简单地称之为:

myMethod(list1, MyFirstClass::method1);
myMethod(list2, MySecondClass::method2);

这假设您正在调用0-arg,void方法。如果不是这种情况,您可以使用lambda,和/或使用其中一个standard functional interfaces或创建自己的。

请注意,这基本上是@jacobm's solution的更简洁版本。

答案 4 :(得分:0)

虽然您可以使用.getClass()instanceofClass参数,但这些参数往往会导致丑陋,脆弱的代码。如果你能提供帮助,请不要去那里。

方法#1

最好的方法是使用抽象类或接口将所需的逻辑放入列表项中。列表对象将直接执行所需的任何操作。

原帖似乎表明这是不可能的,所以让我们继续讨论方法2.

方法#2

使用函数参数。

public <T> String myMethod(List<T> myList, Function<T, String> func)

该函数将对列表中的每个项目起作用,并返回您的方法可以处理的内容。

方法#3

使用包装类。您可以将每个列表项包装在知道如何处理它们的类中。包装类都将从单个基类继承,允许您的方法如下所示:

public String myMethod(List<Wrapper> myList)