'Java generic method Cannot resolve method 'getX()' in 'T'
Say I have a couple of Objects (=classes) which each has a method getX()
:
public class A{
/* some code */
public float getX(){}
}
public class B{
/* some code */
public float getX(){}
}
Now I want to write a generic static method as the following:
public static <T> boolean isOverlaps(T obj) {
if (obj == null || (!obj.getClass().isInstance(A.class) && !obj.getClass().isInstance(B.class)))
return false;
return obj.getX() >= 0 && /*some logic*/; // here it falls
}
IDE says:
Cannot resolve method 'getX()' in 'T'
How can I resolve the method properly without casting (since it is a generic method)? Is it even possible?
Solution 1:[1]
Using an interface is the preferred way to solve this, but the statement "you need an interface" is incorrect.
You can achieve this without an interface too. In some situations (i.e. where you can't modify A or B), this may be the best you can do.
public static boolean isOverlaps(Object obj) {
float x = -1;
if (obj instanceof A) {
x = ((A) obj).getX();
}
else if (obj instanceof B) {
x = ((B) obj).getX();
}
return x >= 0 && /*some logic*/;
}
Solution 2:[2]
public static <T> boolean isOverlaps(T obj) {
This isn't really a generic method. OK, it is a generic method, because it has a type variable; it's just not a usefully generic method. You can pass anything to it: it's essentially equivalent to:
public static boolean isOverlaps(Object obj) {
That is, you can't access anything inside that method which isn't a method on Object
.
If you want to use this, and you can't use the common interface approach, you could do an instanceof
chain:
public static boolean isOverlaps(Object obj) {
if (obj instanceof A) {
return /* logic */;
} else if (obj instanceof B) {
// Do something.
return /* logic */;
}
return false;
}
The problem with this is that you're losing the compile-time safety of not being allowed to pass things other than A
s and B
s to it (e.g. you could call isOverlaps("Hello world!")
, which is presumably nonsensical).
It's actually better to define two overloads:
public static boolean isOverlaps(A obj) { return /* logic */; }
public static boolean isOverlaps(B obj) { return /* logic */; }
because now trying to pass in anything other than an A
or a B
results in a compile-time error; but it's a compile-time error at the call site, not in these methods.
If /* logic */
depends on some property which can be derived from A
and B
, e.g. a getter, you can consolidate the repeated logic into a helper:
public static boolean isOverlaps(A obj) { return helper(obj.getX()); }
public static boolean isOverlaps(B obj) { return helper(obj.getX()); }
private static boolean helper(SomeType value) {
return /* logic */
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Michael |
Solution 2 |