Reputation: 168
I have 2 warnings:
unchecked cast, required: A found: capture#1 of ?
unchecked cast, required: A found: Congress
I know that the class is in fact an Event.
Where Event is an Interface and Exhibition and Congress both implement the Event interface.
public static <A extends Event> A copy(A event) {
Class<?> eventType = event.getClass(); // --> Warning 1
return (A) eventType.getConstructor(eventType).newInstance(event);
return event;
}
The second Warning:
public static <A extends Event> A create(EventType type) {
if(type == EventType.CONGRESS){
return (A) new Congress() // --> Warning 2
}else(){
return (A) new Exhibition() // --> Same as warning 2 but for Exibition
}
}
Now the question is: How can i resolve this two warnings without using:
@SuppressWarning("unchecked")
Upvotes: 1
Views: 3816
Reputation: 273610
Seems like you are misusing generics. If the method gets to decide what type to return, you should not use generics. Generics are used when the caller decides what type to return.
So create
should be like this:
public static Event create(EventType type) {
if(type == EventType.CONGRESS){
return new Congress();
}else {
return new Exhibition();
}
}
For the first warning, you can do something like this.
public static <A extends Event> A copy(A event) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
return (A) event.getClass().getConstructor(event.getClass()).newInstance(event);
}
Upvotes: 2
Reputation: 370
I would recommend using TypeTags aka ClassTags. Something like:
public static <A extends Event> Optional<A> create(Class<A> classTag) {
try {
return Optional.of(classTag.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
return Optional.empty();
}
}
Call it like so:
public static void main(String[] args) {
Optional<Exhibition> e = create(Exhibition.class);
e.ifPresent(System.out::println);
}
Upvotes: 0
Reputation: 20195
You can resolve the first warning by declaring eventType
as Class<? extends A>
. This makes the cast to A
superfluous.
If you cannot change the return type of the first method, there is no option to resolve this compilation issue without resorting to casting. The compilation issue can be resolved by changing the return type of the method to Event
. If you change the return type to Event
, you can fully drop the generic parameter:
public static Event copy(Event e)
throws NoSuchMethodException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
Class<? extends Event> cls = e.getClass();
return cls.getConstructor(cls).newInstance();
}
For the second warning, you can also fully drop the generic type of the method:
public Event create(EventType type) {
if (type == EventType.CONGRESS) {
return new Congress();
} else {
return new Exhibition();
}
}
This assumes that Congress extends Event
and Exhibition extends Event
.
Upvotes: 0
Reputation: 15018
Why would you make this a static method?
public static <A extends Event> A copy(A event) {
Class<?> eventType = event.getClass(); // --> Warning 1
return (A) eventType.getConstructor(eventType).newInstance(event);
return event;
}
You have an instance of Event, let the Event
class be able to create a copy of itself.
abstract class Event<E extends Event<E>> {
public E createCopy(E toCopy);
}
with
class Exhibition extends Event<Exhibition> {
// ...
public Exhibition createCopy() {
return new Exhibition(this);
}
}
What you can to get rid of the second warning is adjusting EventType
to
public enum EventType {
CONGRESS { public Event createEvent() { return new Congress(); }},
EXHIBITION { public Event createEvent() { return new Exhibition(); }};
public abstract Event createEvent();
}
which will result in
public static Event create(EventType type) {
return type.createEvent();
}
If it's really necessary to know the exact type of event that's returned, you should really reconsider the design at this point.
Upvotes: 0