Generic Method Type Safety

Tags: generics java
By : SCdF
Source: Stackoverflow.com
Question!

I have the concept of NodeTypes and Nodes. A NodeType is a bunch of meta-data which you can create Node instances from (a lot like the whole Class / Object relationship).

I have various NodeType implementations and various Node implementations.

In my AbstractNodeType (top level for NodeTypes) I have ab abstract createInstance() method that will, once implemented by the subclass, creates the correct Node instance:

public abstract class AbstractNodeType {
  // ..

  public abstract <T extends AbstractNode> T createInstance();
}

In my NodeType implementations I implement the method like this:

public class ThingType {
  // ..

  public Thing createInstance() {
    return new Thing(/* .. */);
  }
}

// FYI
public class Thing extends AbstractNode { /* .. */ }

This is all well and good, but public Thing createInstance() creates a warning about type safety. Specifically:

Type safety: The return type Thing for createInstance() from the type ThingType needs unchecked conversion to conform to T from the type AbstractNodeType

What am I doing wrong to cause such a warning?

How can I re-factor my code to fix this?

@SuppressWarnings("unchecked") is not good, I wish to fix this by coding it correctly, not ignoring the problem!

By : SCdF


Answers

Two ways:

(a) Don't use generics. It's probably not necessary in this case. (Although that depends on the code you havn't shown.)

(b) Generify AbstractNodeType as follows:

public abstract class AbstractNodeType<T extends AbstractNode> {
  public abstract T createInstance();
}
public class ThingType<Thing> {
  public Thing createInstance() {
    return new Thing(...);
  }
}
By : UlfJack


Something like that should work:

interface Node{
}
interface NodeType<T extends Node>{
	T createInstance();
}
class Thing implements Node{}
class ThingType implements NodeType<Thing>{
	public Thing createInstance() {
		return new Thing();
	}
}
class UberThing extends Thing{}
class UberThingType extends ThingType{
	@Override
	public UberThing createInstance() {
		return new UberThing();
	}
}
By : jrudolph


You can just replace <T extends AbstractNode> T with AbstractNode thanks to the magic of covariant returns. Java 5 added support, but it didn't receive the pub it deserved.

By : Hank Gay


This video can help you solving your question :)
By: admin