Home > Software design >  Finding out the type of a set
Finding out the type of a set

Time:07-15

Given a Set<X>, I want to write a method that acts differently depending on the class X is. In actuality, I'd have 2 cases: A or B.

The method looks like:

public<X> boolean myMethod(Set<X> mySet)
{
 // if X is actually the class A
 ...
 // if X is B
 ...
}

I am not sure how to check this. I tried X::getClass, but it wouldn't let me use equals method.

CodePudding user response:

In a general sense, this is not possible

Due to type erasure, a Java Set does not have a generic type at runtime. Generics act as compile-time checks on the objects passed into methods, but consequently the specific values are not available at runtime. A Set<String> is the same class as a Set<Map<Integer, Thread>> and the same class as a bare Set.

Potential workaround with class parameter

If you really need to know this, you could change the signature of your method to be:

public <X> boolean myMethod(Set<X> mySet, Class<X> clazz)

Now you have a Class instance available at runtime, which is guaranteed to be compatible with X. This you can introspect (e.g. String.class.isAssignableFrom(clazz)).

There are two drawbacks to this approach: firstly, you'll have to explicitly pass in the extra parameter each time the method is called. Secondly, if A and B can be subclasses of one another, this is not going to work; you could pass in e.g. B.class even when the generic parameter was A.

However, this feels like a code smell

You shouldn't be trying to do fundamentally different things based on a generic parameter. Instead of switching behaviour in your method here, do something different within the classes A and B:

public<X> boolean myMethod(Set<X> mySet)
{
   boolean result = false;
   for (X x : mySet) {
      result &= x.doSomething();
   }

   return result;
}

class A implements MyDoSomethingInterface {
    public boolean doSomething() {
        // Here you put the logic for "if X is A"
    }
}

class B implements MyDoSomethingInterface {
    public boolean doSomething() {
        // Here you put the logic for "if X is B"
    }
}

And if your reaction is that this won't work because A and B are built-in classes, you'll need to wrap them in your own domain objects (which is the correct approach anyway because you want to associate this extra behaviour with them).

CodePudding user response:

I suggest you take one object from set and check class of single object like below, please check

public<X> boolean myMethod(Set<X> mySet)
{
    Object tmpObj = null;
    
    for(Object obj : set){
        tmpObj = obj;
        break;
    }
    if(tmpObj instanceof A){
        // if X is actually the class A
    }else if(tmpObj instanceof B){
        // // if X is B
    }
}
  • Related