【问题标题】:Creating Instances of ArrayList using reflection使用反射创建 ArrayList 的实例
【发布时间】:2016-04-16 16:40:01
【问题描述】:

我有一个接受对象的方法。对象是一个列表。该列表可以是任何类型。我想使用反射识别列表的类型并创建列表的实例并对其进行迭代并打印结果。

不同类型的列表

List<Customer> customerList = new ArrayList<Customer>();
List<Service> serviceList = new ArrayList<Service>();
List<Product> productList = new ArrayList<Product>();

接受列表的方法

public void printList(Object genericList){

// identify the type of list
// create the list object
// iterate over the list and print the values

}

【问题讨论】:

  • 我有几个澄清问题: 1. 当您说“识别列表类型”时,您的意思是识别它是否是ArrayList、LinkedList 等,或者识别是否包含类型为Customer、Service、Product 等。 2. 当printList() 创建新列表时,是否必须与genericList 为同一类?例如,如果genericList 是ArrayList 的实例,那么名为newList 的变量是否可以是LinkedList 的实例? 3. 当“迭代列表以打印值”时,您是否期望我们迭代 newList 或 genericList?

标签: java


【解决方案1】:

由于type erasure,没有办法在运行时判断集合的泛型类型(顺便说一下,Object genericList 是矛盾的)。但是,如果您只想打印它们而不考虑类型,则可以将其转换为List&lt;?&gt;:

public void printList(Object obj){
    for (Object o : (List<?>)obj) {
        System.out.println(o.toString());
    }
}

如果您需要更特定于类型的实现,并且您知道列表不会为空,并且您确信列表类型之间没有重叠(即customerList 不能包含Products 和副-反之亦然),那么你可以在技术上做这样的事情:

public void printList(Object obj){
    List<?> list = (List<?>)obj;
    Object firstElement = list.get(0);
    if (firstElement instanceof Customer) {
        printCustomers((List<Customer>)list);
    } else if (firstElement instanceof Product) {
        printProducts((List<Product>)list);
    } //...
}

请注意,编译器会抱怨这些强制转换,这是有充分理由的。它无法知道您是否在说关于泛型类型的真相,至少直到您尝试从列表中读取一个值之前,如果您犯了错误,您将获得ClassCastException。

【讨论】:

  • 不能用ParameterizedType来识别类型吗?如果不能,假设我有办法识别类型,是否可以重新创建对象?
  • @PunterVicky 它不能。如果您尝试在运行时创建类型,则不需要自定义构造。您可以将其转换为您想要的任何泛型类型,因为运行时环境不知道您的泛型参数。查看我的更新。
  • 如果Customer,Product,Service 都继承自同一个类,即BaseClass,您可以使用协变列表并将代码替换为List&lt;? extends BaseClass&gt; list = (List&lt;? extends BaseClass&gt;)obj;
【解决方案2】:

如果你想从列表中判断对象的数据类型并打印出值,我想说判断可能不需要反射,因为instanceof会满足你的需要。要打印出值或对特定对象进行更多操作,您可以使用 java 反射。它非常脆弱。目前我只是列出一个简单模型的代码。如果您确认这是您需要的,那么我们可以进行更多讨论。

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{

    List<Customer> customerList = new ArrayList<>();
    List<Service> serviceList = new ArrayList<>();
    List<Product> productList = new ArrayList<>();
    List result = returnFunc();
    printList(result);

}


public static void printList(List genericList) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
    Object obj=null;
    String type = "";
    Class c1 = null;
    // identify the type of list
    if(genericList.get(0) instanceof Customer){
        c1 = Class.forName("Customer");
    }else if(genericList.get(0) instanceof Service){
        c1 = Class.forName("Service");
    }else if(genericList.get(0) instanceof Product){
        c1 = Class.forName("Product");
    }else{
        System.out.println("Error");
    }
    // create the list object
    Object instance = c1.newInstance();
    // iterate over the list and print the values
    for(Object o : genericList){
        System.out.println(o.toString());

    }
}
//to randomly output a list
public static List returnFunc(){
    ArrayList<List> tmp = new ArrayList<>();
    ArrayList<Object> list_customer = new ArrayList<>();
    list_customer.add(new Customer());
    ArrayList<Object> list_service = new ArrayList<>();
    list_service.add(new Service());
    ArrayList<Object> list_product = new ArrayList<>();
    list_product.add(new Product());
    tmp.add(list_customer);
    tmp.add(list_service);
    tmp.add(list_product);
    Random r = new Random();
    return tmp.get(r.nextInt(3));
}

【讨论】:

    【解决方案3】:

    创建接口,每个类都实现这个接口 也就是说,

    public interface someInterface{
    }
    
    
    public class Customer implements someInterface{
    }
    

    等等……

    【讨论】:

    • 谢谢。这些是作为 jar 文件的一部分提供的类。我想动态识别列表的类型并重新创建列表。
    • 不,我想使用反射识别列表的类型(通用类型),一旦识别出来,想重新创建对象,迭代对象,使用反射确定字段并打印值
    【解决方案4】:

    也许这不是最好的方法,但它可能会让你到达那里

    try{ 
        List<Customer> list = (List<Customer>) genericList; 
        list.get(0).methodOfCustomer(); 
        isCustomer = true;}
    catch(Exception e){
        isCustomer = false
    }
    

    其余的类似条款。

    最后只测试哪个布尔值是真的,或者使用任何其他方式。

    【讨论】:

      猜你喜欢
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 2015-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多