简体   繁体   English

对泛型类型使用 Class 参数(例如 ArrayList)

[英]Use Class parameter for generic type (e.g ArrayList)

I am trying to create a generic method to handle different types of ArrayLists in Java.我正在尝试创建一个通用方法来处理 Java 中不同类型的 ArrayList。 The types are quite different, but all contain one identical parameter, which I want to evaluate in this method.这些类型完全不同,但都包含一个相同的参数,我想在此方法中对其进行评估。

But I cannot create proper ArrayList<type> with given class information.但是我无法使用给定的类信息创建正确的ArrayList<type>

What am I doing wrong?我究竟做错了什么?

private String test(ArrayList<?> list, Class<?> type) {
    for(type i : list){  // for (type i : (ArrayList<type>) list){
     // do something
    }
    return "xxx"
}

private void init() {
    ArrayList<Type_1> a1 = new ArrayList<>();
    ArrayList<Type_2> a2 = new ArrayList<>();

    String s1 = test(a1, Type_1.class);
    String s2 = test(a2, Type_2.class);
}

Update Found a solution更新找到解决方案

private String test(ArrayList<?> list) {
    for (Object i : list){
        try {
            Method m = i.getClass().getMethod("getName", null);
            System.out.println(m.invoke(i));
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            //Handle Exception
        }
    }
 }

You need to declare an explicit type parameter:您需要声明一个显式类型参数:

  private <T> String test(ArrayList<T> list, Class<T> type) {
      for (T i : list) {
         // do something with 'i'
      }
      return "xxx"
  }

If you don't need Class<T> argument, you can leave it out;如果您不需要Class<T>参数,则可以将其省略; eg例如

  private <T> String test(ArrayList<T> list) {
      for (T i : list) {
         // do something
      }
      return "xxx"
  }

You would normally only need to pass a Class<T> type object if you intended to create instances of that class ... or an array of that class.如果您打算创建该类的实例...或该类的数组,您通常只需要传递一个Class<T> type的对象。


The commented out version of your code would not compile because it is mixing compile-time and runtime types.注释掉的代码版本不会编译,因为它混合了编译时和运行时类型。 In

for (type i : (ArrayList<type>) list) {

the compiler would need to know what type was represented by type at compile time.编译器需要在编译时知道类型代表什么type But it is a runtime variable.但它是一个运行时变量。 But that is invalid even before that because the Java syntax requires the identifier for a type at that point ... not the identifier for a variable.但这甚至在此之前也是无效的,因为 Java 语法在那时需要类型的标识符......而不是变量的标识符。

I created a mixed answer relating to both solutions:我创建了一个与这两种解决方案相关的混合答案:

Implementing Interfaces实现接口

The first is done with a simple interface MyType that defines the contract method(s) for the classes Type_1 and Type_2 .第一个是通过一个简单的接口MyType完成的,该接口定义了Type_1Type_2类的契约方法 This is the clean and proper Java way.这是干净且正确的 Java 方式。 This way the compiler will already tell you if you can do certain operations or not.这样编译器就会告诉你是否可以执行某些操作。 This also shows beginners problems with their concept of implementing ideas.这也表明初学者在实施想法的概念上存在问题。

The downside is that all classes have to implement that interface (which may be defined anywhere along their inheritance hierarchy).缺点是所有类都必须实现该接口(可以在其继承层次结构的任何地方定义)。

But Java is all about the advantage of type safety and compiler warnings.但是 Java 完全是关于类型安全和编译器警告的优势。 So this is clearly the preferred way.所以这显然是首选方式。

Using Reflection使用反射

Using Reflection for this task is possible, yes.可以使用反射来完成这项任务,是的。 But not necessarily a good idea.但不一定是个好主意。 With reflection, there are multiple problems:使用反射,存在多个问题:

  • You will get runtime errors or have to handle those exceptions您将收到运行时错误或必须处理这些异常
  • The project will start, but if your design, your concept, is flawed, this will be a lot harder to pinpoint项目将开始,但如果你的设计、你的概念有缺陷,这将很难确定
  • lots of libraries cannot handle reflections well (Aspect Oriented Programming, Application Containers, special Compilers like the GraalVM NativeImage, etc etc)许多库不能很好地处理反射(面向方面​​的编程、应用程序容器、GraalVM NativeImage 等特殊编译器等)
  • Using reflection will be slower and consume more memory使用反射会更慢并消耗更多内存

So if it's possible and easy to stay away from Reflection, you should steer clear.因此,如果远离反射是可能且容易的,您应该避开。 Especially if this has such a simple proper solution to it.特别是如果这有一个如此简单的适当解决方案。

(I also cleaned up your code with the reflection, there were some minor inconsistencies in there that wouldn't let it compile) (我还用反射清理了你的代码,那里有一些小的不一致,不会让它编译)

Code:代码:

package stackoverflow;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class SimpleInterfacing {
    interface MyType {
        String getName();
    }
    static class Type_1 implements MyType {
        @Override public String getName() {
            return "This is type 1";
        }
    }
    static class Type_2 implements MyType {
        @Override public String getName() {
            return "This is type 2";
        }
    }

    private String test(final ArrayList<? extends MyType> list) {
        String returnValue = null;
        for (final MyType t : list) {
            // do something
            System.out.println("Got name: " + t.getName());
            returnValue = t.getName();
        }
        return returnValue; // returns last value, null is lists are empty
    }

    private void init() {
        final ArrayList<Type_1> a1 = new ArrayList<>();
        a1.add(new Type_1());

        final ArrayList<Type_2> a2 = new ArrayList<>();
        a2.add(new Type_2());

        {
            final String s1 = test(a1);
            System.out.println("s1 is " + s1);
        }
        {
            final String s2 = test(a2);
            System.out.println("s2 is " + s2);
        }
        {
            test_reflection(a1);
            test_reflection(a2);
        }
    }

    public static void main(final String[] args) {
        new SimpleInterfacing().init();
    }

    private String test_reflection(final ArrayList<?> list) {
        for (final Object i : list) {
            try {
                final Method m = i.getClass().getMethod("getName");
                System.out.println("Invoked: " + m.invoke(i));
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                //Handle Exception
                ex.printStackTrace();
            }
        }
        return null;
    }



}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 类型参数为E的子类的泛型E - Generic class E with type parameter to be a subclass of E 如何使用通用类类型参数类 - How to use the generic class type parameter class 传递类类型作为参数以在 ArrayList 中使用? - Pass class type as parameter to use in ArrayList? 为什么我不能使用ArrayList <String> 作为通用ArrayList的参数 <E> 方法? - Why can't I use ArrayList<String> as a parameter for a generic ArrayList<E> method? 如何使用泛型类作为参数并扩展类型? - How to use a generic class as a parameter and extend the type? Java Generics:使用通用 class 作为另一个通用 ZA2F2ED4F8EBC2CBB4C21A29DC40AB6 的类型参数 - Java Generics: Use generic class as type parameter of another generic class 用于泛型类型的Java转换“.class”-operator,例如列表,到“Class <List <?>>”和“Class <List <Integer >>” - Java casting “.class”-operator used on a generic type, e.g. List, to “Class<List<?>>” and to “Class<List<Integer>>” 泛型类型的类参数 - class parameter of generic type 如何为类型参数的类调用.class? 例如清单 <String> 。类 - How to call .class for a class with type parameter? E.g. List<String>.class 具有泛型arraylist返回类型和参数的el函数 - el function with generic arraylist return type and with parameter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM