从包含不同类的对象的列表的每个对象中检索实例变量的特定值



我有一个列表,其中包含不同类的对象,例如a, B, C, D, E, F, G。每个对象(a, B, C, D, E, F, G)都有一个实例变量" name ";在里面。我想遍历列表并检索存储在每个对象的name变量中的值。

I tried below code

List<String> str = new ArrayList<String>();
for(Object obj: list_containing_different_objects) {
str.add(obj.name) or  str.add(obj.getName());
}

但是obj.name会给出错误,因为我不知道list_containing_different_objects中存储A,B,C,D,E,F的确切索引(因为每次都不同)。而且,如果我知道指数,我也不知道它的解。有人能帮我脱下来吗?

这取决于A,B,C,D,E,FG是否有一个共同的基类或接口。

通用基型

如果没有,您可以,例如,创建一个这样的接口:

interface Nameable {
String getName();
}

,然后让每个类实现这个接口。然后,您可以轻松地在每个对象上调用getName()方法:

for (Nameable nameable : listContainingDifferentObjects) {
str.add(nameable.getName());
}

instanceof

否则,如果类不会或不能实现公共接口或扩展基类,则这些类是不相关的

在这种情况下,您最终必须检查每个类型,强制转换它并使用字段1:
for (Nameable nameable : listContainingDifferentObjects) {
if (obj instanceof A) {
str.add(((A) obj).name);
}
else if (obj instanceof B) {
str.add(((B) obj).name);
}
// et cetera
}

如果你的类没有实现一个通用的类型,但仍然有一个相同名称的字段,我会重新考虑设计。

反映vsdawg提出使用反射来动态调用getName()方法或访问name字段。虽然一个确实可以使它工作,但如果可能的话,您应该避免使用它,并且只在没有其他方法时使用它。➤更多细节


1从版本16开始,Java支持模式匹配,这简化了检查类型、强制转换和使用值的仪式。例如:

for (Object obj : listContainingDifferentObjects) {
if (obj instanceof A a) {
str.add(a.name());
}
else if (obj instanceof B b) {
str.add(b.name());
}
// et cetera
}

详情请参阅本文。

使用反射

假设类不共享包含方法的公共基类或接口,您可以使用反射来调用该方法。要使其正常工作,需要进行大量的错误处理,但下面的示例将这些错误处理掉,并强制调用者处理它。

public String getName(Object named)
throws NoSuchMethodException, 
SecurityException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
Method method = named.getClass().getMethod("getName");
return (String) method.invoke(named);
}

下面迭代一个对象List并调用上面的方法。由于异常是向上渗透的,这个方法必须处理它们。您可以在这里捕获Exception,但为了完整起见,我留下了完整的列表。

public void printNames(List<Object> namedObjects) {
for (Object obj : namedObjects) {
try  {
System.out.println(getName(obj));
} catch (NoSuchMethodException |
SecurityException |
IllegalAccessException |
IllegalArgumentException |
InvocationTargetException e) {
System.err.println("Failed to invoke getName on object - skipping");
}
}
}

我喜欢MC Emperor关于公共基类的回答,这是应该走的路。但是,如果您没有那个公共类并且无法更改代码。反射可以用来实现需要的东西。

下面的代码甚至不需要getter (getName()),它只需要一个'name'字段。

class A {
public A(String aName) {
name = aName;
}
public String name;
}
class B {
public B(String aName) {
name = aName;
}
public String name;
}
class C {
public C(String aName) {
name = aName;
}
public String name;
}
@Test
public void testClasses() {
List<String> str = new ArrayList<>();
List<? extends Object> list_containing_different_objects = Lists.list(new A("a"), new B("b"),
new C("c"), new A("aa"));

for (Object commonObj : list_containing_different_objects) {
try {
Field field = commonObj.getClass().getField("name");
String nameValue = (String) field.get(commonObj);
str.add(nameValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
// print the results
str.forEach(System.out::println);
}
这个测试执行的结果如下所示:
a
b
c
aa

希望这对你有帮助。

相关内容

  • 没有找到相关文章

最新更新