Problem with Java Generics Method Parameter

I have a problem passing a parameter to a generic method. The code is as follows:

public class View<T extends View<T,PM>, PM extends Source> { protected PM source; protected EventManager<T, PM> eventManager; public View(PM s){ this.source = s; eventManager = new EventManager<T, PM>(); eventManager.setTarget(this); //error: "The method setTarget(T) in the type //EventManager<T,PM> is not applicable for the arguments (View<T,PM>)" eventManager.setSource(s); } public void setBinding(Topic topic, IEventAction<T,PM> action){ eventManager.setEventAction(topic, action) } } /** * EventManager class has to remain completely generic. The type parameters cannot "extends" * anything because the EventManager is used also in other parts where T and S will have to be * classes other than "View" and "Source" */ public class EventManager<T, S> { protected T target; protected S source; private LinkedHashMap<Topic, IEventAction<T, S>> eventActions; public EventManager(T target, S source){ this.target = target; this.source = source; } public void setTarget(T target){ this.target = target; } public void setSource(S source){ this.source = source; } public void setEventAction(Topic topic, IEventAction<T, S> action) { //some code here ... omissis... eventActions.put(topic, action); omissis... } //other methods down here...omissis } 

Eclipse gives me an error that I introduced in the comment on the line "eventManager.setTarget (this);". I cannot understand why this gives me this error. Anyway, I found a solution (apparently), but I'm not sure if I did a “clean” or a “dirty” thing. The solution is this:

  eventManager.setTarget((T)this); 

but this gives me a warning: “Security type: the checkbox from“ View in T ”is unchecked. To exclude the warning, I also added the following constructor method:

 @SuppressWarnings("unchecked") 

It seems to work, but what's wrong? Do you have another “cleaner” solution (if one exists)? Do you think this is a dirty approach?

Any colds are very welcome.

+4
source share
6 answers

In line

 public class View<T extends View<T,PM>, PM extends Source> { 

it seems to you that T should be "type this ". But it is not expressed in language.

Typically, the approach is to make the class abstract and add an abstract getThis method:

 public abstract class View<THIS extends View<THIS,PM>, PM extends Source> { protected abstract THIS getThis(); ... eventManager.setTarget(getThis()); ... public final class SomeView extends View<SomeView,SomeSource> { protected SomeView getThis() { return this; } ... 
+3
source

The error occurs because you create an EventManager using T, which can be any subclass of View at runtime, but you are definitely viewing the View (known at compile time). Since you usually cannot pass a superclass when a subclass is required, your code does not compile.

The solution (without changing the code), of course, should distinguish the superclass from the subclass (this is what you are doing) and try not to get a ClassCastException.

If you are sure that you will never pass incompatible types, then this is normal, I think (albeit very confusing). Maybe try remaking it somehow.

+4
source

The error is due to the fact that the event manager is initialized to store the type "T" during construction, but you are trying to assign an instance of "View" (T extends View, which makes viewing the superclass), which is not right.

+1
source

I agree with what Tudor said, but it's also better not to suppress unverified warnings for the method / constructor. This will hide any other thrown exceptions. I suggest doing this for the line you need. The following is an example.

 @SuppressWarnings("unchecked") T t = (T)this; eventManager.setTarget(t); 
0
source

I think that in order to execute the declaration, EventManager should expand the view, because T on line eventManager = new EventManager<T, PM>(); defined as T extends View<T,PM> - naming templates the same way confuses.

0
source

I don’t know what you are actually doing, but here is something.

Solution 1

 public class View<PM extends Source> { protected PM source; protected EventManager<View<PM>, PM> eventManager; public View(PM s){ this.source = s; eventManager = new EventManager<>(); // diamond notation (Java 7 only) eventManager.setTarget(this); eventManager.setSource(s); } } 

You can still have subclasses of View and setTarget will always get the correct expected type.

Solution 2:

EventManager should only accept Source (or a subclass) as the source, no?

 public class View { protected Source source; protected EventManager<View> eventManager; public View(Source s){ this.source = s; eventManager = new EventManager<>(); // diamond notation (Java 7 only) eventManager.setTarget(this); eventManager.setSource(s); } } public class EventManager<T> { protected T target; protected Source source; public void setTarget(T t) ... public void setSource(Source s) ... } 

Decision 3

You must have a Target class or interface, so the EventManager will not be parameterized at all, and the View will extend or implement Target . You will not have any generics at all. If simple inheritance can do the job, there is no need for generics.

Note : as mentioned in Scorpion, you should not avoid this in the constructor; you can get some kind of event that fires access to the View before it is fully built.

0
source

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


All Articles