0

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);
    }
}
0range
  • 2,088
  • 1
  • 24
  • 32
  • 3
    Change #printDict to accept Set extends NNB>. – Nevay May 08 '17 at 20:53
  • 1
    See also PECS: http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super – JB Nizet May 08 '17 at 20:57
  • Don't use mutable `public` fields. Make the field `final` and/or `private`, and make a getter. That way you can utilize polymorphism if you decide to override the getter. – 4castle May 08 '17 at 20:57
  • @4castle Thanks; I agree, I should have done that. I was trying to keep the code samples short as they are quite long already. But I agree, it is bad style. – 0range May 08 '17 at 21:06

1 Answers1

5

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)?

Community
  • 1
  • 1
shmosel
  • 49,289
  • 6
  • 73
  • 138