Overload / generics in Java

I want to run specific tests on lists. Lists can contain completely different classes.

I have one method for checking the consistency of the list - not empty, not empty, no more than x elements. This is common to all listings. Then I want to test each of the objects using overload.

The idea would be this:

public static <T> void check(List<T> list) { //do general checks for (T element : list) { check(element); } } 

and then

 public static void check(SomeType element) {...} public static void check(SomeOtherType element) {...} 

But I also had to add a method like this:

 public static void check(T element) {...} 

And this was called at runtime - not my other methods with specific classes. Although the class was exactly the same. I obviously do not understand the understanding of generics.

Now, if I do not use the general method at all and try to solve it as follows:

  public static void check(List<SomeType> list) {...} public static void check(List<SomeOtherType> list) {...} 

Compiler Error - "Method Check (List) has the same erase check (List) as another method ..."

So, is there an elegant solution for this? I could just use different method names, but I would like to know how this is possible without it.

Thanks!

+8
java generics
source share
5 answers

Since the type of the variable is lost in check(List<T> list) , you have two options:

1. Perform different actions by checking the type of execution

 check(T element) { if (element.getClass().equals(SomeType.class)) { check((SomeType) element); } elseif (element.getClass().equals(SomeOtherType.class)) { check((SomeOtherType) element); } 

This can be made a little more complicated, for example by wrapping each check in Callable and using Map<Class, Callable>

It looks like a visitor pattern.

2. Calling a virtual method for the item being checked

If the validation logic can be clicked on an object that will be verified by itself (this is not necessarily bad), you do not need to check the types:

 interface Checkable { void check(); } class SomeType implements Checkable { .... } class SomeOtherType implements Checkable { .... } 

Then:

 public static <T extends Checkable> void check(List<T> list) { for (T element : list) { element.check(); } } 

These are the only two options, any implementation should be a variation on one of these

+1
source share

This is not something about the generics you are missing. There is no double dispatch in Java. The check call must be allowed at compile time, and check(T) is the only match since the compiler cannot determine if T SomeType or SomeOtherType in this scenario. He must choose one method for the call that will work for all possible T s.

This is sometimes solved using a template.

+9
source share

You can use instanceof to send:

 public static <T> void check(List<T> list) { for (T element : list) { check(element); } } public static void check(T t) { if (t instanceof SomeType) { SomeType someType = (SomeType) t; // code for SomeType ... } else if (t instanceof OtherType) { OtherType otherType = (OtherType) t; // code for OtherType ... } else { // we got a type that we don't have a method for } } 
+4
source share

The problem must be resolved by the caller. When it initiates your class with a specific type for T, it must also pass an instance of Checker<T> with the same specific type:

 public class SomeClass<T> { private List<T> list; private Checker<T> checker; public SomeClass(Checker<T> checker) { this.checker = checker; } public void check() { checker.check(list); } } public interface Checker<T> { public void check(List<T> list); } ... SomeClass<Foo> someClass = new SomeClass<Foo>(new Checker<Foo>() { @Override public void check(List<Foo> list) { // do whatever you want here } }); 
+4
source share

Using generics, the type parameter is actually deleted at compile time, and the list object knows nothing about the static type of the object it contains. Since he does not know this, he cannot use overloading to call methods with different parameters, because Java does not support multiple sending .

You have three options:

  • Make your objects an implementation of the Checked interface using a validation method that executes validation logic. The disadvantage is that the validation logic is now scattered in several places, and this is impractical if you have objects of classes in which you do not control.
  • Use instanceof to explicitly call the check methods according to the dynamic type of the object. The downside is that you potentially end up with a big if / else block, which is a little harder to maintain.
  • Implement the template. The downside is that you also have to change the classes of the objects, but the check logic will remain in one place.
+2
source share

All Articles