Common args types that are specific to an expanding class?

I want to have a class that implements an interface that defines a specific subclass as a parameter.

public abstract Task implements TaskStatus<Task> { TaskStatus<T> listener; protected complete() { // ugly, unsafe cast callback.complete((T) this); } } public interface TaskStatus<T> { public void complete(T task); } 

But instead of a simple task, or, I want to guarantee that the arg type is used for a specific class that extends this one.

So, the best I came up with is:

 public abstract Task<T extends Task> implements TaskStatus<T> { } 

You can expand this by writing:

 public class MyTask extends Task<MyTask> { } 

But this is also true:

 public class MyTask extends Task<SomeOtherTask> { } 

And the callback call will explode ClassCastException. So, is this approach just wrong and broken, or is there a right way to do this, somehow I missed it?

+4
source share
4 answers

It is not clear what you are trying to do inside the Task . However, if you define a generic Task<T> class as follows:

 class Task<T extends Task<T>> { ... } 

The following two are possible:

 class MyTask extends Task<MyTask> { ... } class YourTask extends Task<MyTask> { ... } 

But it is forbidden:

 class MyTask extends Task<String> { ... } 

The above definition of Task uses F-restricted polymorphism, a rather advanced feature. You can check the research article " F-Bounded Polymorphism for Object-Oriented Programming " for more information.

+2
source

I suggest adding getThis, which should return this appropriately printed. Of course, subclasses can behave badly, but this is always true. What you are avoiding is throwing and throwing a ClassCastException.

 public abstract class Task<THIS extends Task<THIS>> { private TaskStatus<THIS> callback; public void setCallback(TaskStatus<THIS> callback) { this.callback = callback==null ? NullCallback.INSTANCE : callback; } protected void complete() { // ugly, unsafe cast callback.complete(getThis()); } protected abstract THIS getThis(); } public interface TaskStatus<T/* extends Task<T>*/> { void complete(T task); } public class MyTask extends Task<MyTask> { @Override protected MyTask getThis() { return this; } } 

This problem often occurs with developers.

+1
source

I have problems understanding what you are trying to achieve through this. Could you provide more details?

My code reading says that you have these tasks that will be subclassed and after completing the tasks the executable thread will call complete () for the task. At this point, you want to call a callback and pass it a subclass object. I think this is a problem. You are trying to put knowledge of potential subclasses into your abstract class, which does not matter.

This also raises the question of whether this call can cause a call that will make with a subclass that is different from the superclass?

0
source

I can really see how this works if you use the arg type in the constructor. Via. introspection and Class.getSuperType () you can check the args types and make sure that the arg type matches this class.

Somthing line by line:

 assert getClass() == ((ParameterizedType) getSuperType()).getTypeArguments()[0]; 

(This is from the top of the head, check out JavaDocs to check).

I'm not sure where the callback is created in your code. You lowered it at the top.

Another route would be to remove unsafe castings like atm. I do not see the full flow to understand why you need unsafe casting.

0
source

Source: https://habr.com/ru/post/1277329/


All Articles