我有两个不同的列表:
List<MyFirstClass> list1;
List<MySecondClass> list2;
现在我需要一个以List
作为输入的方法。我在这个方法中所做的事情对于两个列表几乎是相同的,只是略有不同。因为我不能超载它们,所以我这样做了:
private String myMethod(List<?> myList) {...}
但是现在我需要检查?
是什么类型,以便在方法中给出与list-element-type相关的差异。
我该怎么做?或者有更好的方法吗?
谢谢!
修改
除了一个方法调用list1.method1()
和list2.method2()
之外,这两种方法实际上是相同的。这就是为什么我不想制作两种不同的方法。
答案 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()
,instanceof
或Class
参数,但这些参数往往会导致丑陋,脆弱的代码。如果你能提供帮助,请不要去那里。
最好的方法是使用抽象类或接口将所需的逻辑放入列表项中。列表对象将直接执行所需的任何操作。
原帖似乎表明这是不可能的,所以让我们继续讨论方法2.
使用函数参数。
public <T> String myMethod(List<T> myList, Function<T, String> func)
该函数将对列表中的每个项目起作用,并返回您的方法可以处理的内容。
使用包装类。您可以将每个列表项包装在知道如何处理它们的类中。包装类都将从单个基类继承,允许您的方法如下所示:
public String myMethod(List<Wrapper> myList)