0range 0range - 4 months ago 16
Java Question

Is there a way in Java to hand over HashSet<Class> arguments to a method so that the method will accept HashSets of subclasses of Class?

Question & Explanation

Is there a way in Java to hand over

HashSet<Class>
arguments to a method so that the method will accept HashSets of subclasses of
Class
?

This would be useful if there are several subclasses of a class the differences of which are not relevant to the method in question. If this is not possible, the only options to handle this seem to be


  • to write as many methods as there are subclasses

  • to loop through the HashSet in the calling function and call a similar method with the individual class instances as argument instead of the HashSets



... both are not very practical.

The version is Java 8 (openjdk 1.8.0).

Example

All files are assumed to be in the same directory so that we do not have to worry about packages and files importing each other. Consider a classes NNB and a subclass NNC (subclass of NNB).

NNB.java
:

import java.util.HashMap;
import java.util.Map;


public class NNB {

public final Map<Long, Double> dict;

public NNB () {
this.dict = new HashMap<Long, Double>();
int c = 0;
while (c<10) {
Long XX = (long)10;
Double YY = 2.0;
this.dict.merge(XX, YY, Double::sum);
System.out.println(dict);
c++;
}
}
}


NNC.java
:

import java.util.HashMap;
import java.util.Map;


public class NNC extends NNB {

private Map<Long, Double> dict2;

public NNC () {
super();
this.dict2 = new HashMap<Long, Double>();
}
}


Now assume, we want to call a method over a list of instances of NNB and NNC (say, to print
NNB.dict
and
NNC.dict
).

This does not work:
NNA2.java
:

import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

public class NNA2 {

public void printDict(HashSet<NNB> nnbs) {
for (NNB nnb : nnbs) {
System.out.println(nnb.dict);
}
}

public static void main(String args[]) {
NNA2 inst = new NNA2();
HashSet<NNB> x = new HashSet<NNB>(Arrays.asList(new NNB()));
HashSet<NNC> y = new HashSet<NNC>(Arrays.asList(new NNC()));

inst.printDict(x);
inst.printDict(y); //here it fails
System.exit(0);
}
}


Error:

NNA2.java:26: error: incompatible types: HashSet<NNC> cannot be converted to HashSet<NNB>
inst.printDict(y);


This works (but is not quite what we wanted and would be unpractical if we wanted to perform more complex operations):
NNA1.java
:

import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

public class NNA1 {

public void printOneDict(NNB nnb) {
System.out.println(nnb.dict);
}

public static void main(String args[]) {
NNA1 inst = new NNA1();
HashSet<NNB> x = new HashSet<NNB>(Arrays.asList(new NNB()));
HashSet<NNC> y = new HashSet<NNC>(Arrays.asList(new NNC()));

for (NNB nnb : x) {
inst.printOneDict(nnb);
}

for (NNC nnb : y) {
inst.printOneDict(nnb);
}

System.exit(0);
}
}

Answer Source

If I understand you correctly, you're looking for this:

public void printDict(HashSet<? extends NNB> nnbs) {
    // ...
}

See also Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic? and What is PECS (Producer Extends Consumer Super)?