I have this class:
public abstract class Addressable {
abstract <T extends "this" Addressable> void hardEquals(T t);
}
The method hardEquals(T t) is not bounded as I want. What I want is bound T to be same class of this
. In other words when I extend the class Addressable
, with the concrete class MyAddressable
, I want that the method hardEquals()
has the signature:
void hardEquals(MyAddressable t);
For completeness:
public class MyAddressable extends Addressable {
void hardEquals(MyAddressable t);
}
The Class object has a getName() method that returns the name of the class. So your displayClass() method can call getClass(), and then getName() on the Class object, to get the name of the class of the object it finds itself in.
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example is Number .
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.
Definitions: A class that is derived from another class is called a subclass (also a derived class, extended class, or child class). The class from which the subclass is derived is called a superclass (also a base class or a parent class).
It’s not possible in general. The problem becomes clear when think a bit longer about your scenario. You have that class Addressable
and its method hardEquals
which demands that its parameter has the type equal to this. Then you have the subclass
public class MyAddressable extends Addressable {
void hardEquals(MyAddressable t);
}
that seems to work as intended. Now imagine a subclass of the subclass:
public class GrandChild extends MyAddressable {
void hardEquals(MyAddressable t);
}
Here, you have a class which must accept MyAddressable
as hardEquals
’ parameter as it is not allowed to override a method by narrowing the parameter types, i.e. not accepting things that the superclass accepted. After all, you can always have a variable of type MyAddressable
that actually refers to an instance of GrandChild
. It would be impossible to restrict the parameters to hardEquals
to match the actual runtime type of the object.
So the desired “parameter type must match this
type” rule conflicts with the “subclass methods must accept all parameters the superclass did” rule.
Note that this is often confused with an actual limitation of the type system, that the same thing doesn’t work for return types. Since return types are allowed to be narrowed for subclasses, the desire to guaranty to return the this
type could be reasonable in some scenarios, e.g.:
class Base {
Base/*actually this type*/ clone() { … }
}
class SubClass extends Base {
SubClass/*actually this type*/ clone() { … }
}
class GrandChild extends SubClass {
GrandChild/*actually this type*/ clone() { … }
}
works, but there is no formal way to specify the guaranty that the this
type is returned so it’s up to the programmer’s discipline to add the correct override to every subclass.
But, as said, for parameter types this doesn’t work in general as you can’t narrow the type of a parameter in a subclass.
You could borrow a trick from Comparable
, and specify the generic type in the class declaration itself:
public abstract class Addressable<T> {
abstract <T> void hardEquals(T t);
}
This results in slightly clunky class definitions, but it should fulfill your requirement
public class HomeAddress extends Addressable<HomeAddress> {
void hardEquals(HomeAddress t) {
// implementation
}
}
I'm not aware of a clean solution for your problem.
You could think about something like this:
public abstract class Addressable<T extends Addressable<T>> {
abstract void hardEquals(T other);
}
public class MyAddressable extends Addressable<MyAddressable> {
@Override
void hardEquals(MyAddressable other) {
// ...
}
}
But this could fail in some cases, e.g.:
public class FakeAddressable extends Addressable<MyAddressable> {
@Override
void hardEquals(MyAddressable aT) {
// ...
}
}
If you are looking for a hardEquals
that can only be used with objects with exactly the same type then something like this should work:
public abstract class Addressable<T extends Addressable<T>> {
abstract boolean hardEquals(T t);
}
class X extends Addressable<X> {
@Override
boolean hardEquals(X t) {
return true;
}
}
class Y extends Addressable<Y> {
@Override
boolean hardEquals(Y t) {
return true;
}
}
public void test() {
X x = new X();
if ( x.hardEquals(x)) {
System.out.println("Ok");
}
Y y = new Y();
// Fails!
if ( x.hardEquals(y)) {
System.out.println("Not OK");
}
}
As @Holger rightly points out - this does not help when extending the sub-classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With