定义一个通用列表

huangapple go评论69阅读模式
英文:

Defining a Generic List

问题

以下是翻译好的内容:

我对泛型相当新,真的很感谢这里的一些帮助。我有一个方法,

public static List<classA> convertA(List<List<Object>> dataframe) throws Exception {
    List<classA> objA = new ArrayList<classA>();
    for (List<Object> objs : dataframe) {
        if (objs != null) {
            classA a = new classA();
            
            // 通用逻辑,将值从 objs 设置到对象 `a`,不考虑 `a` 的类型。
            
            objA.add(a);
        }
    }
    
    return objA;
}

该方法基本上将 List<List<Object>> 类型的 dataframe 的值赋给了 classA 的列表。

我还有另一个方法 convertB,它具有与 convertA 相同的逻辑和参数,只是它将 dataframe 的值存储到 classB 的列表中(List<classB>),如下所示,

public static List<classB> convertB(List<List<Object>> dataframe) throws Exception {
    List<classB> objB = new ArrayList<classB>();
    for (List<Object> objs : dataframe) {
        if (objs != null) {
            classB b = new classB();
            
            // 通用逻辑,将值从 objs 设置到对象 `b`,不考虑 `b` 的类型。
            
            objB.add(b);
        }
    }
    
    return objB;
}

因此,我试图将这两个方法合并成一个单一的方法,编写一个通用的泛型方法,返回类型为 List<T>,参数包括 T 的类型(可以是 classA、classB 等),如下所示,

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Class<T> clazz) {
    List<T> objList = new ArrayList<T>();
    for (List<Object> objs : dataframe) {
        if (objs != null) {
            try {
                T instance = clazz.newInstance();
                
                // 通用逻辑,将值从 objs 设置到对象 `instance`,不考虑 `instance` 的类型。
                
                objList.add(instance);
            } catch (Exception e) {
                // 处理异常
            }
        }
    }
    
    return objList;
}

但我不确定如何以通用的方式编写第 2、5 和 7 行。

所以,有人能指点我正确的方向吗?

请注意:

方法 convertAconvertB 都是独立的,用于处理两种不同的情况。除了这两者都有将 List<Object> objs 转换为其相应对象 a(classA)b(classB) 的相同逻辑外,它们之间没有任何关系。

我不想维护两个单独的方法,如 convertA()convertB(),我只是想将其合并成一个方法,通过传递参数调用,例如:

List<ClassA> ls = convertGeneric(dataframe, ClassA.class); 代替 convertA()

以及

List<ClassB> ls1 = convertGeneric(dataframe, ClassB.class); 代替 convertB()

英文:

I'm fairly new to Generics, and would really appreciate some help here. I've got a method,

1 public static List&lt;classA&gt; convertA(List&lt;List&lt;Object&gt;&gt; dataframe) throws Exception {
2		List&lt;classA&gt; objA = new ArrayList&lt;classA&gt;();
3		for (List&lt;Object&gt; objs : dataframe) {
4			if (objs != null) {
5				classA a = new classA();
						
6				//generic logic to set value from objs to object `a` irrespective of type of `a`. 
						
7				objA.add(a);
8			}
9		}
			
10		return objA;
11	}

The method basically assigns the values of List&lt;List&lt;Object&gt;&gt; dataframe to a list of classA.

I also have another method convertB which has the same logic and argument of convertA except that it stores the values of dataframe to a list of classB(List&lt;classB&gt;), like so,

21 public static List&lt;classB&gt; convertB(List&lt;List&lt;Object&gt;&gt; dataframe) throws Exception {
22		List&lt;classB&gt; objA = new ArrayList&lt;classB&gt;();
23		for (List&lt;Object&gt; objs : dataframe) {
24			if (objs != null) {
25				classB b = new classB();
						
26				//generic logic to set value from objs to object `b` irrespective of type of `b`. 
						
27				objA.add(b);
28			}
29		}
			
30		return objA;
31	}

So I'm trying to combine the 2 methods into a single one to write a common generic method with return type of List&lt;T&gt; and arguments including type of T(which can be classA, classB,..), something like so,

public static List&lt;T&gt; convertGeneric(List&lt;List&lt;Object&gt;&gt; dataframe, T t) 

But I'm not sure how to write the lines 2,5,7 in a generic manner.

So could someone point me in the right direction?

Please Note:

Both the methods convertA and convertB are independant of each other and are used to handle 2 seperate scenarios. There is no relation between the two, except the fact that both have the same logic to convert List&lt;Object&gt; objs to its respective object namely a(classA) or b(classB).

Rather than maintaining 2 seperate methods like convertA() and convertB(), I'm just trying to make it into a single one which I can call by passing arguments like

List&lt;ClassA&gt; ls = convertGeneric(dataframe, ClassA.class); instead of convertA() and

List&lt;ClassB&gt; ls1 = convertGeneric(dataframe, ClassB.class); instead of convertB().

答案1

得分: 1

用通用方法解决方案

将通用方法定义为:

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter)

即第一个参数是对象的集合,第二个参数是从Object到目标类的转换函数。该方法返回一个List<T>。(注意static后面的<T>,这是声明通用方法所必需的。)

该方法的实现可以是:

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter) {
    
    List<T> result = new ArrayList<>();
    
    for (List<Object> objects : dataframe) {
        for (Object object : objects) {
            T t = converter.apply(object);
            result.add(t);
        }
    }
    
    return result;
}

或者使用流另一种实现方式:

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter) {
    
    return dataframe.stream()
            .flatMap(Collection::stream)    // 从内部列表获取对象
            .map(converter)                 // 将对象转换为T
            .collect(Collectors.toList());  // 将所有内容放入新列表中
}

转换函数可以作为lambda表达式来实现,例如:

Function<Object, Foo> fooLambda = object -> {
    Foo foo = new Foo();
    // 将obj映射到foo的逻辑
    return foo;
};

List<List<Object>>转换为List<Foo>

List<Foo> fooList = GenericMethodConverter.convertGeneric(dataFrame, fooLambda);

我认为你之前在解决这个问题时遇到困难的原因是你试图在通用方法中同时处理抽象和具体的部分。你意识到通用方法需要额外的信息来确定要使用哪个具体实现(在你的版本中,通过将目标类型作为第二个参数传递来进行转换)。在上述解决方案中,通用方法需要一个转换函数Function<Object,T>,即一个将对象映射到目标类型T的函数。通用方法将此函数应用于所有对象,并将结果放入返回的列表中。将object映射为Foo的具体实现以lambda表达式的形式提供,从而将通用的T实例化为Foo。根据需要可以添加其他转换函数。

另一种方法

这是一种使用面向对象/类而不是静态方法的解决方案:

定义一个抽象基类GenericConverter,其中包含对列表的迭代,并声明一个抽象方法来将Object转换为目标类型:

public abstract class GenericConverter<T> {

    public List<T> convertGenerically(List<List<Object>> dataFrame) {

        List<T> tList = new ArrayList<>();

        for (List<Object> objectList : dataFrame) {
            for (Object obj : objectList) {
                T t = convert(obj);
                tList.add(t);
            }
        }
        return tList;
    }

    protected abstract T convert(Object obj);
}

为每个目标类添加一个实现,例如将Object转换为Foo

public class FooConverter extends GenericConverter<Foo> {
    
    @Override
    protected Foo convert(Object obj) {
        Foo foo = new Foo();
    
        // 将obj映射到foo的逻辑
    
        return foo;
    }
}

然后通过调用实现类的方法来转换Objects

List<Foo> foos = fooConverter.convertGenerically(dataFrame);
英文:

A Solution Using a Generic Method

Define your generic method as

public static &lt;T&gt; List&lt;T&gt; convertGeneric(List&lt;List&lt;Object&gt;&gt; dataframe, Function&lt;Object, T&gt; converter)

i.e. the first argument is your collection of objects, and as the second argument you provide a conversion function from Object to the target class. The method returns a List&lt;T&gt;. (Note the &lt;T&gt; after static which is required to declare a generic method.

An implementation of the method could be

public static &lt;T&gt; List&lt;T&gt; convertGeneric(List&lt;List&lt;Object&gt;&gt; dataframe, Function&lt;Object, T&gt; converter) {

  List&lt;T&gt; result = new ArrayList&lt;&gt;();

  for (List&lt;Object&gt; objects : dataframe) {
    for (Object object : objects) {
      T t = converter.apply(object);
      result.add(t);
    }
  }

  return result;
}

or another one using streams:

public static &lt;T&gt; List&lt;T&gt; convertGeneric(List&lt;List&lt;Object&gt;&gt; dataframe, Function&lt;Object, T&gt; converter) {

  return dataframe.stream()
          .flatMap(Collection::stream)    // get the objects from the inner list
          .map(converter)                 // convert object to T
          .collect(Collectors.toList());  // put everything in a new list
}

The conversion function can be implemented as a lambda, e.g.

Function&lt;Object, Foo&gt; fooLambda = object -&gt; {
  Foo foo = new Foo();
  // logic for mapping obj to foo
  return foo;
};

And converting a List&lt;List&lt;Object&gt;&gt; to a List&lt;Foo&gt; becomes:

List&lt;Foo&gt; fooList = GenericMethodConverter.convertGeneric(dataFrame, fooLambda);

I think the reason why you were struggling with the problem is that you tried to do everything (the abstract and the concrete part) in the generic method. You were aware that the generic method then requires additional information what concrete implementation to use (in your version by passing as the second argument the target type for the conversion). In the above solution, the generic method requires a conversion function Function&lt;Object,T&gt;, i.e a function that maps an object to the target type T. The generic method applies this function to all objects and puts the results in the returned list. The concrete implementation for mapping an object to a Foo is supplied as a lambda expression thus reifying the generic T to Foo. Other conversion functions can be added as required.

Another Approach

This is a solution using object orientation / classes instead of static methods:

Define an abstract base class GenericConverter that contains the iteration to over the list and declares an abstract method how to convert an Object to the target type:

public abstract class GenericConverter&lt;T&gt; {

  public List&lt;T&gt; convertGenerically(List&lt;List&lt;Object&gt;&gt; dataFrame) {

    List&lt;T&gt; tList = new ArrayList&lt;&gt;();

    for (List&lt;Object&gt; objectList : dataFrame) {
      for (Object obj : objectList) {
         T t = convert(obj);
         tList.add(t);
       }
    }
    return tList;
  }

  protected abstract T convert(Object obj);
}

Add an implementation for each target class, e.g. for converting Object to Foo:

public class FooConverter extends GenericConverter&lt;Foo&gt; {

    @Override
    protected Foo convert(Object obj) {
        Foo foo = new Foo();

        // logic for mapping obj to foo

        return foo;
    }
}

And then convert the Objects by calling the method of implementing class:

List&lt;Foo&gt; foos = fooConverter.convertGenerically(dataFrame);

答案2

得分: 0

如果我理解正确,您需要创建接口并在您的classAclassB中实现它。然后将此接口用作通用占位符。示例:

public class ClassA implements Interface {
}

public class ClassB implements Interface {
}

ArrayList<Interface> objA = new ArrayList<>();
objA.add(new ClassA());
objA.add(new ClassB());
for (Interface obj : objA) {
    //逻辑处理
}
英文:

If I get you right you need to create interface and implement it in your classA and classB. Then use this interface as generic placeholder. Example:

public class ClassA implements  Interface {
}

public class ClassB implements  Interface {
}



 ArrayList&lt;Interface&gt; objA = new ArrayList&lt;&gt;();
        objA.add(new ClassA());
        objA.add(new ClassB());
        for (Interface obj : objA) {
            //logic
            }
        }

huangapple
  • 本文由 发表于 2020年3月15日 16:52:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/60691163.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定