使用反射从扩展实例中获取特定属性

Using reflection to get a specific attribute from a extended instance

我想制作一个通用方法来从参数对象中获取列表。

问题是因为我有一个已声明的对象,其中包含另一个 class 的实例,它扩展了已声明的 class。 我不想使用 instanceof 解决方案,因为扩展 LimitedValue 的 classes 的数量可能很大。

我想使用反射作为解决方案,但我不知道如何将它与对象实例一起使用,在这部分代码中:

    Class cls = Class.forName(limitedValue.getClass().getName());
    Object obj = cls.newInstance();
    //This is wrong, I don't want a new instance.

    Method[] methods = cls.getDeclaredMethods();
    for(int x= 0; x < methods.length; x++) {
        Method method = methods[x];
        if ("java.util.List".equals(method.getReturnType().getName())) {
            //How to get the value of this method from limitedValue instance ?
        }
    }

这是我的完整代码:

public class CalculatorLimitedValue {

    public static void main(String[] args) throws Exception {
        StoreItem storeItem = new StoreItem(1L, "Name of StoreItem", 50L);
        List listOfStoreItems = new ArrayList();
        listOfStoreItems.add(storeItem);
        LimitedValue limitedValue0 = new Store(listOfStoreItems);

        List firstList = calculator(limitedValue0);
        //do something with the list

        SupermarketItem supermarketItem = new SupermarketItem(1L, "Name of SupermarketItem", 21L);
        List listOfSupermarketItems = new ArrayList();
        listOfSupermarketItems.add(supermarketItem);
        LimitedValue limitedValue1 = new Supermarket(listOfSupermarketItems);

        List secondList = calculator(limitedValue1);
        //do something with the list
    }

    /** This is the method that I'd like to make generic to return a List */
    private static List calculator(LimitedValue limitedValue) throws Exception{

        Class cls = Class.forName(limitedValue.getClass().getName());
        Object obj = cls.newInstance();
        //This is wrong, I don't want a new instance.

        Method[] methods = cls.getDeclaredMethods();
        for(int x= 0; x < methods.length; x++) {
            Method method = methods[x];
            if ("java.util.List".equals(method.getReturnType().getName())) {
                //How to get the value of this method from limitedValue instance ?
            }
        }

        /* I don't want to use this one way, because my classes that extends LimitedValue 
        can be big. I would like to made a generic way to get de list of classes. */
        if (limitedValue instanceof Store) {
            System.out.println("This is a store");
            return ((Store) limitedValue).getStoreItems();
        } else if (limitedValue instanceof Supermarket) {
            System.out.println("This is a supermarket");
            return ((Supermarket) limitedValue).getSupermarketItems();
        }
        return null;
    }
}

如果有帮助,这些是我的其他 classes:

LimitedValue.class

public class LimitedValue { }

StoreItem.class

public class StoreItem {
    private Long id;
    private String nameOfStoreItem;
    private Long valueOfStoreItem;

    public StoreItem(Long id, String nameOfStoreItem, Long valueOfStoreItem){ 
        this.id = id;
        this.nameOfStoreItem = nameOfStoreItem;
        this.valueOfStoreItem = valueOfStoreItem;
    }
//getters and setters...
}

SupermarketItem.class

public class SupermarketItem {
    private Long id;
    private String nameOfSupermarketItem;
    private Long valueOfSupermarketItem;

    public SupermarketItem() {
    }

    public SupermarketItem(Long id, String nameOfSupermarketItem, Long valueOfSupermarketItem) {
        this.id = id;
        this.nameOfSupermarketItem = nameOfSupermarketItem;
        this.valueOfSupermarketItem = valueOfSupermarketItem;
    }
//getters and setters...
}

Store.class

public class Store extends LimitedValue {
    private List<StoreItem> storeItems;

    public Store(List<StoreItem> storeItems) {
        this.storeItems = storeItems;
    }
    //getters and setters
}

Supermarket.class

public class Supermarket extends LimitedValue {
    private List<SupermarketItem> supermarketItems;

    public Supermarket(List<SupermarketItem> supermarketItems) {
        this.supermarketItems = supermarketItems;
    }
    //getters and setters
}

要获得 List 值,请使用 Method#invoke:

List list = method.invoke(limitedValue);

您不需要 Object obj = cls.newInstance(); - 您根本没有在方法中使用它。

无论如何,你自己都很难过。你也可以定义一个接口

public interface HasList<E> {
    List<E> getList();
}

并让所有 类 执行此操作。

你可以在这里尝试使用反射来尝试实现你想要的,但最好重新考虑你的整体设计并尝试使用更好的面向对象设计来解决手头的问题。

特别是,假设我们考虑将名为 getItems 的方法添加到 LimitedValue class 中 returns 项目列表,可能是 SupermarketItem 或可能是 StoreItems。如果它的结构正确,您将不需要知道实际类型,因为代码将以多态方式对其进行抽象。

public abstract class LimitedValue {    
  List<? extends Item> getItems();
}

我们现在已经在 LimitedValue 上定义了一个新方法,但我们还必须考虑到我们已经引入了这个新的 Item 东西。我注意到 SupermarketItemStoreItem 都共享相似的属性,nameidvalue,因此似乎可以使用一个class代表他们。

public abstract class Item {
  final Long id;
  final String name;
  final Long value;

  public Item(final Long id, final Long name, final Long value) {
    this.id = id;
    this.name = name;
    this.value = value;
  }

  String getName() {
    return name;
  }
  // other getters and setters
}

public class SupermarketItem extends Item {
  public SupermarketItem(final Long id, final Long name, final Long value) {
    super(id, name, value);
  }
}

public class StoreItem extends Item {
  public StoreItem(final Long id, final Long name, final Long value) {
    super(id, name, value);
  }
}

现在我们已经完全抽象掉了访问这些对象时对任何反射的需要——你可以简单地调用 item.getValue() 因为你会知道列表中的每个项目都是 Item 类型。

当然,你还需要重构 Store 和 SuperMarket classes,例如:

public class Supermarket extends LimitedValue {
    private List<SupermarketItem> supermarketItems;

    public Supermarket(List<SupermarketItem> supermarketItems) {
        this.supermarketItems = supermarketItems;
    }

    public List<? extends Item> getItems() {
      return supermarketItems;
    }
}

并且因为您只返回一个 List<Item>,所以您总是知道其中的内容,并且您可以更改主代码以使用它。

这是一个更清洁的长期解决方案。