How to declare a variable according to an unknown List type of the input variable in Java?

636 Views Asked by At

How to declare a variable according to an unknown List type of the input variable in Java?

For example::

You are given arr1, you need to (shallow) copy from arr1 to arr2. But you don't know what type of list arr1 is.

This is the code that I use, if I want to declare arr2, I have to go through all possible cases of types of List.

  static List<Object> funcOri(List<Object> arr1, List<Object> arr2) {
    if (arr1 instanceof ArrayList<?>) {
      arr2 = new ArrayList<Object>(arr1);
    } else if (arr1 instanceof LinkedList<?>) {
      arr2 = new LinkedList<Object>(arr1);
    } else if (...) {
      ;
    }
    return arr2;
  }

Is there a simpler way to declare arr2 according to the type of arr1 is?

Maybe something that simply looks like::

  static List<Object> funcWanted(List<Object> arr1, List<Object> arr2) {
    arr2 = new XXXList<Object>(arr1); // where XXXList is base on the type of list the arr1 is
    return arr2;
  }
2

There are 2 best solutions below

2
hfontanez On

Unless I am completely misunderstanding your problem, this is what you need (Java 8)

public class ListCopyDemo {
    
    public static void main (String[] args) {
        List<String> original = new ArrayList<>();
        original.add("Hello World!");
        original.add("Welcome to Java");
        
        List<?> copy = ListCopyDemo.funcOri(original); // should return a copy of the original
    }
    
    public static List<Object> funcOri(List<?> arr1) {
        return arr1.stream().collect(Collectors.toList());
    }
}

If you were to change original List type to List<Integer> or LinkedList<String>, the funcOri will work the same.

0
DarkMatter On

You can always try to create a new instance of arr1's class using reflections.

public class ListClone {

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        List<String> al = new ArrayList<>();
        al.add("abc");

        List<String> ll = new LinkedList<>();
        ll.add("123");

        List<String> alc = funcOri(al);
        List<String> llc = funcOri(ll);

        System.out.println(alc.getClass().getSimpleName());
        System.out.println(llc.getClass().getSimpleName());

        alc.add("def");
        llc.add("456");

        System.out.println(al);
        System.out.println(alc);

        System.out.println(ll);
        System.out.println(llc);
    }

    static <T> List<T> funcOri(List<T> arr1) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Constructor<? extends List> constructor = arr1.getClass().getConstructor(Collection.class);
        constructor.setAccessible(true);
        return constructor.newInstance(arr1);
    }
}

Output:

ArrayList
LinkedList
[abc]
[abc, def]
[123]
[123, 456]

Edit

This assumes that the list type of arr1 has a constructor to take a Collection. It's of course entirely possible that there are List implementations that don't. A slightly safer solution might be to go for a default constructor and use List.addAll() to copy the contents but we can still not be certain that all List implementations have a default constructor. It will then throw NoSuchMethodException.