I had a question about similar generics yesterday, and as solution I implemented a sort of self-reference in some classes, like this:
public interface Action { }
public interface Result { }
public interface Player<A extends Action, R extends Result, P extends Player<A, R, P>> {
default public void onPostAction(final P target, final A action, final R result) { }
}
abstract public class GesturePlayer<A extends Action, R extends Result, P extends GesturePlayer<A, R, P>> implements Player<A, R, P> { }
abstract public class RPSPlayer extends GesturePlayer<RPSGesture, RPSResult, RPSPlayer> { }
public class RPSHumanPlayer extends RPSPlayer {
#Override
public void onPostAction(final RPSHumanPlayer target, final RPSGesture gesture, final RPSResult result) { }
}
This code does not compile, hoewver I am unable to figure out why.
It does work if in the #Override I use RPSPlayer, however RPSHumanPlayer is simply a subclass of it, should it not work the same as the following?
List<T> list = new ArrayList<>();
Which also has the type definied as the superclass (List resp RPSPlayer), and the referenced object's type as the subclass (ArrayLast resp RPSHumanPlayer).
My aim with this question is to gather insight on how the generics exactly work, and I want to keep the method signature as it is defined in RPSHumanPlayer.
What I think I understand about generics:
T is a typed parameter, like List<String>, etc. Also able to use it for own classes and methods. This also captures all subclasses of T.
? captures all possible Objects. Used to ensure that something is generic and not raw.
? extends T capture a specific subclass of T.
This code is written on Java 8.
In order to achieve the desired method signature in RPSHumanPlayer, you will need to generify RPSPlayer like this:
abstract public class RPSPlayer<P extends RPSPlayer<P>> extends GesturePlayer<RPSGesture, RPSResult, P> { }
Then you can define:
public class RPSHumanPlayer extends RPSPlayer<RPSHumanPlayer>
In Java, parameter types are part of the method signature, so they can't be changed (not even subclassed). Since Java 5, you can use covariant return types, but that's as far as it goes.
Your problem boils down to this:
public interface Player {
default public void onPostAction(Player target) {}
}
public abstract class HumanPlayer implements Player {
#Override
public void onPostAction(HumanPlayer target) {}
}
This cannot work, because onPostAction(HumanPlayer) cannot override onPostAction(Player), because then what would happen if it was called with a Player that was not a HumanPlayer?
Related
Consider the following code
#Test
public void testFunction() {
// This cause error
callDoSomething(new myInterfaceImpl());
}
public interface myInterface {
int doSomething();
}
public class myInterfaceImpl implements myInterface {
public int doSomething() {
return 1;
}
}
public void callDoSomething(Class<? extends myInterface> myVar) {
System.out.println(myVar.doSomething());
}
On this line callDoSomething(new myInterfaceImpl()); I get the following error.
Error:(32, 25) java: incompatible types: com.myProject.myTest.myInterfaceImpl
cannot be converted to java.lang.Class<? extends com.myProject.myTest.myInterface>
How do I satisfy the parameter type? If only an interface is provided to me.
I want to bound the class that has an interface, but it seems like this is not avaiable to me
Class<? implements myInterace>
Edit:
The reason I want to do this is because I want to provide a custom kafka partitioner.
public Builder<K, V> withCustomPartitionner(Class<? extends Partitioner> customPartitioner) {
this.customPartitioner = customPartitioner;
return this;
}
It looks like you want to be able to call methods on the parameter that's given. In that case, you'll want the actual instance of your interface, not the Class associated with it.
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
Class<> is used when you want to use reflection to do something with the specific class type that you're interested in:
public void outputClassInfo(Class<? extends myInterface> myClass) {
System.out.println(myClass.getName());
}
If that's what you're going for, you'll want to provide the class at compile time like this:
outputClassInfo(myInterfaceImpl.class);
Or, if you won't know which class you're dealing with until runtime, you can use reflection:
myInterface thing = getThing();
outputClassInfo(thing.getClass());
So, in the example you're providing in your edit, I'm guessing you want:
public Builder<K, V> withCustomPartitioner(Class<? extends Partitioner> customPartitioner) {
this.customPartitioner = customPartitioner;
return this;
}
// Usage
builder
.withCustomPartitioner(FooPartitioner.class)
...
This type Class<? extends myInterface> myVar corresponds to a Class instance not to an instance of myInterface.
You generally don't pass a class as parameter (but for reflection purposes or to bypass generics erasures). So what you need as parameter is probably :
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
That you could invoke :
#Test
public void testFunction() {
// This cause error
callDoSomething(new myInterfaceImpl());
}
The parameter to callDoSomething shouldn't be a class. It must be an instance of that class or it's subclass.
public <T extends myInterface> void callDoSomething(T myVar) {
System.out.println(myVar.doSomething());
}
On a side note, don't name Java classes/interfaces starting with lower case.
As rightly mentioned by Andy Turner#, there is no need to use a type parameter here and you can just refer to the type as myInterface
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
You need to pass the Class not an instance.
callDoSomething(MyInterfaceImpl.class);
public class BinaryVertex {
public BinaryVertex parent,left,right;
}
public class BSTVertex extends BinaryVertex {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
I'm making a tree / graph api for school, approaching it from a oop standpoint. But im trying to figure out a way for the inherited class to treat some of its base class variables as its own type (i.e. parent,left,right should be treated as BSTVertex when called from BSTVertex but treated as BinaryVertex when called from BinaryVertex) without casting.
I'm thinking of generics but I'm not sure how to implement that in this situation.
UPDATE
Nice, didnt know you could use extend in generics. But I'm getting a BSTVertex<T> cannot be converted to T error with this:
public class Test {
public static void main(String[] args) {
new AVLVertex();
BSTVertex<BSTVertex> v = new BSTVertex<BSTVertex>();
v.foo();
}
class BinaryVertex<T extends BinaryVertex> {
public T parent, left, right;
}
class BSTVertex<T extends BSTVertex> extends BinaryVertex<T> {
public T foo() {
return this; //error here
}
}
class AVLVertex extends BSTVertex<AVLVertex> {
// this might probably end up being abstract too
}
foo needs to return a vertex of the same type as caller, i.e. if AVLVertex calls foo its expecting to get AVLVertex not BSTVertex
Yes, you can use generics like this:
public class BinaryVertex<T extends BinaryVertex<T>> {
public T parent, left, right;
}
public class BSTVertex extends BinaryVertex<BSTVertex> {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
The same way the Comparable interface implemented, so subclasses receive the same type to compareTo method. For example, Integer implements Comparable<Integer>, so its compareTo method receives Integer argument.
Also please note the it would be better to create your own random number generator like this:
public class BSTVertex extends BinaryVertex<BSTVertex> {
private static final Random r = new Random();
public void foo() {
left = new BSTVertex();
if(r.nextBoolean()) left.foo();
}
}
UPDATE
In your updated code (in future please ask new question instead) you cannot safely cast, because you can potentially write later:
class RBVertex extends BSTVertex<RBVertex>{}
class AVLVertex extends BSTVertex<RBVertex>{}
This is ok from the compiler's point of view, but your AVLVertex generic argument is actually not an AVLVertex. That's why you have a compilation error in foo() method: your class can be later possibly extended in the way that would make your T incompatible with this.
You can fix this problem by doing an unchecked cast:
#SuppressWarnings("unchecked")
public T foo() {
return (T) this;
}
In this way if you mistakenly create class AVLVertex extends BSTVertex<RBVertex>{}, it will still compile, but upon calling AVLVertex.foo() you may have a runtime ClassCastException.
I have an interface A, and wish to write an generic interface B such that any T that implements B must also have implemented both A and Comparable. A is not currently a generic interface.
Is this possible? Do I need to make A generic?
I had hoped to be able to write something like:
public interface B<T implements Comparable, A> {}
But this does not seem to work... Can anyone point me in the right direction?
I do not believe this is a duplicate of the question that has been linked.
What you are looking for here are multi-bounded generic types:
public interface B<T extends A & Comparable> {}
Note that if either of the bounded types is a class instead of an interface, it has to be the first bound defined after extends. Also, you cannot use multi-bounded generic types on more than one class(since there is no multiple-inheritance in Java)
Just make B to extend A and Comparable.
public interface A {
public void methodA();
}
public interface B<T> extends A, Comparable<T> {
public T methodB();
}
public class BImpl<T> implements B<T> {
#Override
public T methodB() {
return null;
}
#Override
public void methodA() {
}
#Override
public int compareTo(T o) {
return 0;
}
}
I have this generic interface:
public interface TjbListener<T> {
public void hearChange(T t);
}
Which I use like this:
public interface ObjectOneListener extends TjbListener<ClassOne> {
}
I would like to write an abstract generic class A which takes a generic type U as a parameter and has a method (1) which itself calls a method (2) on U. Below is my attempt U should extend (or implement maybe?) the generic TjbListener interface.
public abstract class ListenerInformer<U extends TjbListener<"what should I write here">> {
List<U> mListeners = new ArrayList<U>();
public void addListener(U u){
mListeners.add(u);
}
public void informAll("what should I write here"){
for(U u:mListeners){
u.hearChange("what should I write here");
}
}
}
One solution I thought of as I was writing this question is below, but I don't know if it's really a solution, or if it has subtle problems I don't understand:
public abstract class ListenerInformer<U extends TjbListener<T>,T> {
List<U> mListeners = new ArrayList<U>();
public void addListener(U u){
mListeners.add(u);
}
public void informAll(T t){
for(U u:mListeners){
u.hearChange(t);
}
}
}
UPDATE: BEWARE
I have just discovered that this approach is almost useless for my particular case because the same class cannot implement the same interface with different parameters. See the question linked below. This means that I cannot have one class be a listener of two different types with my (or Johanna's) solution, without using a different strategy like composition.
How to make a Java class that implements one interface with two generic types?
Your second example should work. But if it is as simple as that, then there is no need for the Generic U, because every instance of a subclass of TjbListener also is an instance of TjbListener.
You can do more simple:
public abstract class ListenerInformer<T> {
List<TjbListener<T>> mListeners = new ArrayList<TjbListener<T>>();
public void addListener(TjbListener<T> u){
mListeners.add(u);
}
public void informAll(T t){
for(TjbListener<T> u:mListeners){
u.hearChange(t);
}
}
}
That works as your code does and is easier to handle.
Two generic types is necessary if you need the final implementation type of the subclass of TjbListener as return value of parameter, for example if you have
public U informAll2(T t){
for(U u:mListeners){
u.hearChange(t);
if (...)
return u;
}
}
In this case your declaration with two generic types is correct (just I'm not sure if it is possible to declare the generic U, which depends of T, before you declare T, of if you have to declare T first, like public abstract class ListenerInformer<T, U extends TjbListener<T>> )
I have some problems implementing a Java feature.
I have a list of Sensors. I have different kinds of them, they all extend the base class Sensor.
I have some abstract functions in the base class, and I want these functions to take an Enum as a parameter. The problem is that the Enum is unique for each sub class, and therefore, I can't declare the Enum in the base class.
The code below has Enum as parameter. I know it's not legal syntax, but I just want to illustrate that this is where I want to have the sub class Enum as parameter.
private Vector<Sensor> sensors;
public abstract class Sensor {
public Sensor() {}
public abstract int getParam(Enum param);
public abstract void setParam(Enum param, int value);
}
public class TempSensor extends Sensor {
// Parameter names
public static enum TEMP_PARAMETERS{ PARAM_ALARM_HI, PARAM_ALARM_LO }
public TempSensor() {}
#Override
public int getParam(TEMP_PARAMETERS param) {
// Will do some stuff here
return 0;
}
#Override
public void setParam(TEMP_PARAMETERS param, int value) {
// Will do some stuff here
}
}
If the different Enums implement an interface, I can use the interface as the parameter type in the abstract methods, but then I can pass Enums that don't belong to the respective class as parameter. Is there a way to avoid that?
Looks like you want contradictory things. The whole point of using polymorphism is to take advantage of the substitution principle.
If you want to have a class hierarchy and be sure the right type is entered to the right object, you may consider using the factory pattern.
I strongly recommend against inheritance on Enums; Java doesn't handle that well.
You're on the right track. Assuming you have a marker interface called MyEnumTypeInterface, just have your different enums implement that inferface. Then use MyEnumTypeInterface as the type of the formal parameter for your methods that accept the enum. However, you need to ensure that you're getting an enum that implements MyEnumTypeInterface and not just any other class that implements MyEnumTypeInterface:
public <E extends Enum<E> & MyEnumTypeInterface>void getParam(E e)
This ensures that the formal parameter is an enum and that it implements MyEnumTypeInterface; the methed won't accept as a parameter, another class that also implements MyEnumTypeInterface.
So your classes end up looking like this:
public interface MyEnumTypeInterface {
}
public abstract class Sensor {
public Sensor() {}
public abstract <E extends Enum<E> & MyEnumTypeInterface>int getParam(E param);
public abstract <E extends Enum<E> & MyEnumTypeInterface>void setParam(E param, int value);
}
public enum TempEnum extends MyEnumTypeInterface {
PARAM_ALARM_HI,
PARAM_ALARM_LO
}
public class TempSensor extends Sensor {
public TempSensor() {}
#Override
public<E extends Enum<E> & MyEnumTypeInterface>int getParam(E param) {
return 0;
}
#Override
public <E extends Enum<E> & MyEnumTypeInterface>void setParam(E param, int value) {
// Will do some stuff here
}
}
So you want each Sensor to work a particular param type? That would mean making Sensor generic.
public abstract class Sensor<P extend Enum<P>> {
public Sensor() {}
public abstract int getParam(P param);
public abstract void setParam(P param, int value);
}
There are probably bigger problems with you design. Fixing those could remove the requirement for the get and set.