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
}
}