簡體   English   中英

從包含不同類對象的列表的每個 object 中檢索實例變量的特定值

[英]Retrieve specific values of instance variable from each object of a list containing Objects of different classes

我有一個列表,其中包含不同類的對象,比如 A、B、C、D、E、F、G。每個對象(A、B、C、D、E、F、G)都有一個實例變量“name “ 在里面。 我想遍歷列表並檢索存儲在每個對象的名稱變量中的值。

我試過下面的代碼

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

但是obj.name會出錯,因為我不知道存儲 A、B、C、D、E、F 的list_containing_different_objects中的確切索引(因為每次都可能不同)。 另外,如果我知道該索引,我將無法找到任何解決方案。有人可以幫助我嗎?

這取決於類ABCDEFG是否具有公共基類 class 或接口。

共基型

如果沒有,您可以創建一個如下所示的界面:

interface Nameable {
    String getName();
}

然后讓每個類實現這個接口。 然后您可以輕松地在每個對象上調用getName()方法:

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

instanceof

否則,如果這些類不會或不能實現公共接口或擴展基類 class,那么這些類是不相關的,盡管有一個同名的字段。

在這種情況下,您最終必須檢查每種類型,對其進行轉換並使用字段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
}

如果你的類沒有實現通用類型,但仍然有一個同名的字段,我會重新考慮設計。

反射

vsfDawg 提出了使用反射來動態調用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
}

有關更多詳細信息,請參閱本文

使用反射

假設這些類不共享一個公共基礎 class 或包含您可以使用反射調用該方法的方法的接口。 有很多錯誤處理可以使其正常工作,但下面的示例將錯誤處理掉並強制調用者處理它。

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

以下迭代對象列表並調用上述方法。 由於異常正在滲透,因此此方法必須處理它們。 您可以在此處捕獲異常,但為了完整起見,我保留了完整列表。

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's answer about common base class,這是通往go的方式。但是,如果你沒有那個公共class並且無法更改代碼。 可以使用反射來實現所需要的。

下面的代碼甚至不需要 getter (getName()),它只需要一個“名稱”字段。

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

我希望這可以幫到你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM