简体   繁体   English

获取列表中元素的类型

[英]Get type of elements in List

I have two different Lists: 我有两个不同的列表:

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

Now I need a method taking a List as input. 现在,我需要一个以List为输入的方法。 The stuff I do in this method is almost the same for both lists and just slightly different. 我在此方法中所做的工作对于两个列表几乎相同,只是稍有不同。 Since I can't just overload them, I did this: 由于我不能只是让它们过载,所以我这样做了:

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

But now I need to check what type ? 但是现在我需要检查什么类型? is, to make the slighly differences in the method in relation to which list-element-type is given. 就是要在与给出list-element-type有关的方法上稍有不同。

How do I do this? 我该怎么做呢? Or is there any better way to do this? 还是有更好的方法来做到这一点?

Thanks! 谢谢!

Edit The two methods are really the same except one method call list1.method1() and list2.method2() . 编辑这两个方法实际上是相同的,只是一个方法调用list1.method1()list2.method2() That is why I don't want to make two different methods. 这就是为什么我不想使用两种不同的方法。

The literal solution is to use instanceof to differentiate between the types of objects. 字面上的解决方案是使用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();
        }
    }
}

And if the design constraints of your project are immutable, this is your best solution. 而且,如果您的项目的设计约束是一成不变的,那么这就是您的最佳解决方案。

But a better solution uses Inheritance 但是更好的解决方案是使用继承

This problem does demonstrate that you almost certainly have a flaw in your overall design. 该问题确实表明,您几乎可以肯定在整体设计中存在缺陷。 If you don't/can't know in advance whether you'll get a List<MyFirstClass> or List<MySecondClass> , then that's pretty strong evidence you have a poorly defined problem domain. 如果您事先不知道是否会得到List<MyFirstClass>List<MySecondClass> ,则有力证据表明您的问题域定义不明确。 It's much better to enforce the necessary constraints by making them implement an interface that instructs how behavior should differ in this situation. 最好通过使必要的约束实现一个接口来强制执行必要的约束,该接口指示在这种情况下行为应如何不同。

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 could also be rewritten in this scenario where you're not sure whether you'll get List<MyFirstClass> , List<MySecondClass> , or List<MyInterface> : 在不确定您将获得List<MyFirstClass>List<MySecondClass>还是List<MyInterface>情况下, myMethod也可以重写:

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

You might be able to use inheritance to solve your problem. 您也许可以使用继承来解决问题。 To do so, make both classes inherit from a common base class (or interface). 为此,使两个类都从一个公共基类(或接口)继承。 Then make a List to store elements of the sub classes. 然后创建一个列表来存储子类的元素。 Store the special logic that is specific to each type within the sub classes. 在子类中存储特定于每种类型的特殊逻辑。 Here is an example: 这是一个例子:

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();
}

You can't adjust your method directly based off of what the type in List<?> is. 您不能直接基于List<?>的类型来调整方法。 There are other ways of getting what you want, though. 不过,还有其他方法可以获取您想要的东西。 Here's one way (these names are going to be awful because I don't have a lot of context for what you're trying to do): 这是一种方法(这些名称会很糟糕,因为我想了解的内容并不多):

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();
  }
}

Then change your method to take a MethodCaller of the same type as the list, like so: 然后更改您的方法以采用与列表相同类型的MethodCaller ,如下所示:

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

Now to call your method you'd use myMethod(list1, new Class1Caller()) or myMethod(list2, new Class2Caller()) . 现在调用您的方法,您将使用myMethod(list1, new Class1Caller())myMethod(list2, new Class2Caller())

You can use a lambda to extract the distinct call and pass it as an argument to your method: 您可以使用lambda提取非重复调用并将其作为参数传递给您的方法:

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

Then simply call it like this: 然后像这样简单地调用它:

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

This assumes you're calling 0-arg, void methods. 假设您正在调用0-arg, void方法。 If that's not the case, you can use a lambda instead, and/or use one of the other standard functional interfaces or create your own. 如果不是这种情况,则可以改用lambda和/或使用其他标准功能接口之一或创建自己的接口

Note that this is essentially a more concise version of @jacobm's solution . 请注意,这实际上是@jacobm解决方案的更简洁的版本。

While you could use .getClass() , instanceof , or a Class parameter, those tend to result in ugly, fragile code. 尽管可以使用.getClass()instanceofClass参数,但它们往往会导致难看,脆弱的代码。 Please don't go there if you can help it. 如果可以的话,请不要去那里。

Method #1 方法1

The best approach is to use an abstract class or interface to put the required logic into the list items. 最好的方法是使用抽象类或接口将所需的逻辑放入列表项。 The list objects would directly perform whatever operation is required. 列表对象将直接执行所需的任何操作。

The original post seems to indicate that this isn't possible, so let's go on to method 2. 原始帖子似乎表明这是不可能的,因此让我们继续方法2。

Method #2 方法#2

Use a function parameter. 使用功能参数。

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

The function will act on each item in the list, and return something your method can handle. 该函数将作用于列表中的每个项目,并返回您的方法可以处理的内容。

Method #3 方法#3

Use wrapper classes. 使用包装器类。 You can wrap each list item inside classes that know how to handle them. 您可以将每个列表项包装在知道如何处理它们的类中。 The wrapper classes would all inherit from a single base class, allowing your method to look like this: 包装器类都将从单个基类继承,从而使您的方法看起来像这样:

public String myMethod(List<Wrapper> myList)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM