Java Type Erasure Problem - java

I've made an example to demonstrate my problem:
Metrical.java
public interface Metrical<T>
{
double distance(T other);
}
Widget.java
public class Widget implements Metrical<Widget>
{
private final double value;
public Widget(double value) { this.value = value; }
public double getValue() { return value; }
public double distance(Widget other) { return Math.abs(getValue() - other.getValue()); }
}
Pair.java
public class Pair<T>
{
private final double value;
private final T object1, object2;
public Pair(T object1, T object2, double value)
{
this.object1 = object1;
this.object2 = object2;
this.value = value;
}
public T getObject1() { return object1; }
public T getObject2() { return object2; }
public double getValue() { return value; }
}
Algorithm.java
import java.util.Set;
public class Algorithm<T extends Metrical<T>>
{
public void compute(Set<T> objects)
{
}
public void compute(Set<Pair<T>> pairs)
{
}
}
So, in Algorithm.java, Set< Pair< T >> is being seen as a Set< T > and thus I am having type erasure problems. However, is there any way I can get away with something like this without naming the methods differently? Both variants of the algorithm are meant to operate on T's, but I need to allow for different arguments. They compute the same thing, so in an effort to avoid confusion, I would rather not name them differently. Is there any way to accommodate this?

No there isn't.
You have to remember that someone could call your method with just a vanilla Set, in which case which one would be called?
That's why you can't do it. Just like you can't do:
interface A {
void blah(Set set);
void blah(Set<T> set);
}
Same problem.
The type information isn't available at runtime (ie type erasure).

Sorry, the bad news is that you cannot do this:
public class Algorithm<T extends Metrical<T>> {
public void compute(Set<T> objects) {
}
public void compute(Set<Pair<T>> pairs) {
}
}
Due to erasure, both will erase to the same signature. There is no way around this short of renaming one of the methods.

Sadly, this is the major area where Java Generics falls down... there is just no good solution.
I've generally resorted to making a new class, with the interface as Set<Pair<T>>, but that wraps Set<Pair<T>> (without extending it, which would cause the same problem).

I've written an article about type erasure which can be of your interest.
It gives the common widely known solution and also a tricky way to circumvent the problem.
I don't know if it will be relevant for you. Anyway, it contains some techniques which may be useful under certain circumstances.
See also: Using TypeTokens to retrieve generic parameters
I hope it helps.

Use public class Widget<K, P> implements Metrical<K extends Widget<P>>.
public double distance(Widget other) {} becomes public double distance(Widget<P> other) {}

Related

What is the prefered way to deep copy a generic field in java

So I have a generic class which I want to have the method copy():
public class MyGenericClass<T> {
public MyGenericClass( T value ) {
this.value = value;
}
public T value;
public MyGenericClass<T> copy() {
/* Some way to deep copy 'this' */
}
}
One way I know to do this uses lambda expressions:
import java.util.function.UnaryOperator;
public class MyGenericClass<T> {
public MyGenericClass( T value, UnaryOperator<T> copyLambda ) {
this.value = value;
this.copyLambda = copyLambda;
}
public T value;
private final UnaryOperator<T> copyLambda;
public MyGenericClass<T> copy() {
return new MyGenericClass<>( copyLambda.apply( value ), copyLambda )
}
}
However this can quickly end up with a huge amount of constructor arguments which would be hard for an individual to manage.
Another way is to require the generic type to implement an interface:
public interface Copyable<T implements Copyable<T>> {
T copy();
}
public class MyGenericClass<T implements Copyable<T>> implements Copyable<MyGenericClass<T>> {
public MyGenericClass( T value ) {
this.value = value;
}
public T value;
#Override
public MyGenericClass<T> copy() {
return new MyGenericClass<>( value.copy )
}
}
(java.util.function.Supplier can be used in exactly the same way only the method would be called get() not copy())
But this is also annoying for the end user as all generics they wish to use have to implement this unnecessary interface.
And apparently there is some way to deep copy using serialize and deserialize which sounds rather hacky.
Which one of these approaches should I use?
Do I use lambda expressions for copying things and create a factory class to deal with the long constructors?
Or do I require all generics that end up as field types to implement an interface?

It is posible to improve this Java Generics scenario [duplicate]

I have a generic interface like this:
interface A<T> {
T getValue();
}
This interface has limited instances, hence it would be best to implement them as enum values. The problem is those instances have different type of values, so I tried the following approach but it does not compile:
public enum B implements A {
A1<String> {
#Override
public String getValue() {
return "value";
}
},
A2<Integer> {
#Override
public Integer getValue() {
return 0;
}
};
}
Any idea about this?
You can't. Java doesn't allow generic types on enum constants. They are allowed on enum types, though:
public enum B implements A<String> {
A1, A2;
}
What you could do in this case is either have an enum type for each generic type, or 'fake' having an enum by just making it a class:
public class B<T> implements A<T> {
public static final B<String> A1 = new B<String>();
public static final B<Integer> A2 = new B<Integer>();
private B() {};
}
Unfortunately, they both have drawbacks.
As Java developers designing certain APIs, we come across this issue frequently. I was reconfirming my own doubts when I came across this post, but I have a verbose workaround to it:
// class name is awful for this example, but it will make more sense if you
// read further
public interface MetaDataKey<T extends Serializable> extends Serializable
{
T getValue();
}
public final class TypeSafeKeys
{
static enum StringKeys implements MetaDataKey<String>
{
A1("key1");
private final String value;
StringKeys(String value) { this.value = value; }
#Override
public String getValue() { return value; }
}
static enum IntegerKeys implements MetaDataKey<Integer>
{
A2(0);
private final Integer value;
IntegerKeys (Integer value) { this.value = value; }
#Override
public Integer getValue() { return value; }
}
public static final MetaDataKey<String> A1 = StringKeys.A1;
public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
At that point, you gain the benefit of being a truly constant enumeration value (and all of the perks that go with that), as well being an unique implementation of the interface, but you have the global accessibility desired by the enum.
Clearly, this adds verbosity, which creates the potential for copy/paste mistakes. You could make the enums public and simply add an extra layer to their access.
Designs that tend to use these features tend to suffer from brittle equals implementations because they are usually coupled with some other unique value, such as a name, which can be unwittingly duplicated across the codebase for a similar, yet different purpose. By using enums across the board, equality is a freebie that is immune to such brittle behavior.
The major drawback to such as system, beyond verbosity, is the idea of converting back and forth between the globally unique keys (e.g., marshaling to and from JSON). If they're just keys, then they can be safely reinstantiated (duplicated) at the cost of wasting memory, but using what was previously a weakness--equals--as an advantage.
There is a workaround to this that provides global implementation uniqueness by cluttering it with an anonymous type per global instance:
public abstract class BasicMetaDataKey<T extends Serializable>
implements MetaDataKey<T>
{
private final T value;
public BasicMetaDataKey(T value)
{
this.value = value;
}
#Override
public T getValue()
{
return value;
}
// #Override equals
// #Override hashCode
}
public final class TypeSafeKeys
{
public static final MetaDataKey<String> A1 =
new BasicMetaDataKey<String>("value") {};
public static final MetaDataKey<Integer> A2 =
new BasicMetaDataKey<Integer>(0) {};
}
Note that each instance uses an anonymous implementation, but nothing else is needed to implement it, so the {} are empty. This is both confusing and annoying, but it works if instance references are preferable and clutter is kept to a minimum, although it may be a bit cryptic to less experienced Java developers, thereby making it harder to maintain.
Finally, the only way to provide global uniqueness and reassignment is to be a little more creative with what is happening. The most common use for globally shared interfaces that I have seen are for MetaData buckets that tend to mix a lot of different values, with different types (the T, on a per key basis):
public interface MetaDataKey<T extends Serializable> extends Serializable
{
Class<T> getType();
String getName();
}
public final class TypeSafeKeys
{
public static enum StringKeys implements MetaDataKey<String>
{
A1;
#Override
public Class<String> getType() { return String.class; }
#Override
public String getName()
{
return getDeclaringClass().getName() + "." + name();
}
}
public static enum IntegerKeys implements MetaDataKey<Integer>
{
A2;
#Override
public Class<Integer> getType() { return Integer.class; }
#Override
public String getName()
{
return getDeclaringClass().getName() + "." + name();
}
}
public static final MetaDataKey<String> A1 = StringKeys.A1;
public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
This provides the same flexibility as the first option, and it provides a mechanism for obtaining a reference via reflection, if it becomes necessary later, therefore avoiding the need for instantiable later. It also avoids a lot of the error prone copy/paste mistakes that the first option provides because it won't compile if the first method is wrong, and the second method does not need to change. The only note is that you should ensure that the enums meant to be used in that fashion are public to avoid anyone getting access errors because they do not have access to the inner enum; if you did not want to have those MetaDataKeys going across a marshaled wire, then keeping them hidden from outside packages could be used to automatically discard them (during marshaling, reflectively check to see if the enum is accessible, and if it is not, then ignore the key/value). There is nothing gained or lost by making it public except providing two ways to access the instance, if the more obvious static references are maintained (as the enum instances are just that anyway).
I just wish that they made it so that enums could extend objects in Java. Maybe in Java 9?
The final option does not really solve your need, as you were asking for values, but I suspect that this gets toward the actual goal.
If JEP 301: Enhanced Enums gets accepted, then you will be able to use syntax like this (taken from proposal):
enum Primitive<X> {
INT<Integer>(Integer.class, 0) {
int mod(int x, int y) { return x % y; }
int add(int x, int y) { return x + y; }
},
FLOAT<Float>(Float.class, 0f) {
long add(long x, long y) { return x + y; }
}, ... ;
final Class<X> boxClass;
final X defaultValue;
Primitive(Class<X> boxClass, X defaultValue) {
this.boxClass = boxClass;
this.defaultValue = defaultValue;
}
}
By using this Java annotation processor https://github.com/cmoine/generic-enums, you can write this:
import org.cmoine.genericEnums.GenericEnum;
import org.cmoine.genericEnums.GenericEnumParam;
#GenericEnum
public enum B implements A<#GenericEnumParam Object> {
A1(String.class, "value"), A2(int.class, 0);
#GenericEnumParam
private final Object value;
B(Class<?> clazz, #GenericEnumParam Object value) {
this.value = value;
}
#GenericEnumParam
#Override
public Object getValue() {
return value;
}
}
The annotation processor will generate an enum BExt with hopefully all what you need!
if you prefer you can also use this syntax:
import org.cmoine.genericEnums.GenericEnum;
import org.cmoine.genericEnums.GenericEnumParam;
#GenericEnum
public enum B implements A<#GenericEnumParam Object> {
A1(String.class) {
#Override
public #GenericEnumParam Object getValue() {
return "value";
}
}, A2(int.class) {
#Override
public #GenericEnumParam Object getValue() {
return 0;
}
};
B(Class<?> clazz) {
}
#Override
public abstract #GenericEnumParam Object getValue();
}

Fluent API with inheritance and generics

I'm writing a fluent API to configure and instantiate a series of "message" objects. I have a hierarchy of message types.
To be able to access method of subclasses when using the fluent API, I used generics to parametrize the subclasses and make all fluent methods (that start with "with") return the generic type. Note that I omitted most of the body of the fluent method; a lot of configuration goes on in them.
public abstract class Message<T extends Message<T>> {
protected Message() {
}
public T withID(String id) {
return (T) this;
}
}
The concrete subclasses redefine the generic type similarly.
public class CommandMessage<T extends CommandMessage<T>> extends Message<CommandMessage<T>> {
protected CommandMessage() {
super();
}
public static CommandMessage newMessage() {
return new CommandMessage();
}
public T withCommand(String command) {
return (T) this;
}
}
public class CommandWithParamsMessage extends
CommandMessage<CommandWithParamsMessage> {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, paramValue);
return this;
}
}
This code works, i.e. I can instantiate any of the classes and use all fluent methods:
CommandWithParamsMessage msg = CommandWithParamsMessage.newMessage()
.withID("do")
.withCommand("doAction")
.withParameter("arg", "value");
Calling the fluent methods in any order is a major goal here.
However, the compiler warns that all return (T) this are unsafe.
Type safety: Unchecked cast from Message to T
I'm unsure how I could reorganize the hierarchy to make this code truly safe. Even though it works, the use of generics in this fashion feels really convoluted.
Especially, I'm not able to foresee situations where runtime exceptions will happen if I just ignore the warnings.
There will be new message types, so I need to keep the code extensible.
If the solution is to avoid inheritance altogether I would also like to obtain suggestion of alternatives.
There are other questions here on SO that address a similar issue. They point to a solution where all intermediate classes are abstract and declare a method like protected abstract self(). Still, in the end it's not safe.
Your code is fundamentally an unsafe use of Generics. For example, if I write a new class which extends message, say Threat, and has a new method doSomething(), and then I create a message parameterised by this new class and it creates an instance of Message, and then attempts to Cast it to its subclass. However, since it is an instance of Message, and not of Threat, an attempt to call this message will cause an Exception. Since it is not possible for Message to doSOmething().
Further, its also unnecessary to use Generics here. Plain old inheritance will work fine. Since sub types can override methods by making their return types more specific, you can have:
public abstract class Message {
protected Message() {
}
public Message withID(String id) {
return this;
}
}
And then
public class CommandMessage extends Message {
protected CommandMessage() {
super();
}
public static CommandMessage newMessage() {
return new CommandMessage();
}
public CommandMessage withCommand(String command) {
return this;
}
}
This will work fine, on the understanding that you call your arguments in the right order:
CommandWithParamsMessage.newMessage()
.withID("do")
.withCommand("doAction")
.withParameter("arg", "value");
will fail, but
CommandWithParamsMessage.newMessage().withParameter("arg", "value")
.withCommand("doAction").withID("do")
Will succeed, since it only "up types", finally returning a "message" class. If you want it not to "uptype", then simply overwrite the inherited commands, and now you can call the methods in any order, since they are all return the original type.
E.g.
public class CommandWithParamsMessage extends
CommandMessage {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, paramValue);
return this;
}
#Override
public CommandWithParamsMessage withCommand(String command){
super.withCommand(command);
return this;
}
#Override
public CommandWithParamsMessage withID(String s){
super.withID(s);
return this;
}
}
Now you will fluently return a CommandWithParamsMessage with either of the two fluent calls above.
Does this solve your problem, or have I misunderstood your intent?
I've done something like this before. It can get ugly. In fact, I've tried it more times than I've used it; usually it gets erased and I try to find a better design. That said, to help you move a little further down the road try this:
Have your abstract classes declare a method like:
protected abstract T self();
This can replace this in your return statements. The subclasses will be required to return something that matches the bound for T -- but it doesn't guarantee that they return the same object.
If you change the signatures like this you should neither get any warnings nor do you need any casts:
abstract class Message<T extends Message<T>> {
public T withID(String id) {
return self();
}
protected abstract T self();
}
abstract class CommandMessage<T extends CommandMessage<T>> extends Message<T> {
public T withCommand(String command) {
// do some work ...
return self();
}
}
class CommandWithParamsMessage extends CommandMessage<CommandWithParamsMessage> {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName, String paramValue) {
// do some work ...
return this;
}
#Override protected CommandWithParamsMessage self() {
return this;
}
}
The compiler warns you of this unsafe operation, because it cannot factually check the correctness of your code. This makes it, as a matter of fact, unsafe and there is nothing you can do to prevent this warning. Even though an unsafe operation is not compile-checked, it can still be legitimate at run time. If you circumvent the compiler check, it is however your job to validate your own code for its use of correct types which is what the #SupressWarning("unchecked") annotation is for.
To apply this to your example:
public abstract class Message<T extends Message<T>> {
// ...
#SupressWarning("unchecked")
public T withID(String id) {
return (T) this;
}
}
is fine, because you can as a matter of fact tell with certainty that this Message instance is always of the type that is represented by T. But the Java compiler cannot (yet). As with other suppression warnings, the key to using the annotation is to minimize its scope! Otherwise, you can easily retain the annotation suppression by accident after you made code changes that render your former manual check for type safety as invalid.
As you only return a this instance, you can however easily outsource the task to a specific methods as recommended in another answer. Define a protected method like
#SupressWarning("unchecked")
public T self() {
(T) this;
}
and you can always call the mutator like here:
public T withID(String id) {
return self();
}
As another option, and if it is possible for you to implement, consider an immutable builder which only exposes its API by interfaces but implements a full builder. This is how I normally build fluent interfaces these days:
interface Two<T> { T make() }
interface One { <S> Two<S> do(S value) }
class MyBuilder<T> implements One, Two<T> {
public static One newInstance() {
return new MyBuilder<Object>(null);
}
private T value; // private constructors omitted
public <S> Two<S> do(S value) {
return new MyBuilder<S>(value);
}
public T make() {
return value;
}
}
You can, of course, create smarter constructions where you avoid the unused fields. If you want to look at examples of me using this approach, look at my two projects which use fluent interfaces quite heavily:
Byte Buddy: API for defining a Java class at run time.
PDF converter: A conversion software for converting files using MS Word from Java.
This is not a solution for your original problem. It is only an attempt to capture your actual intention, and sketch an approach where where the original problem does not appear. (I like generics - but class names like CommandMessage<T extends CommandMessage<T>> extends Message<CommandMessage<T>> make me shudder...)
I know that this is structurally rather different from what you originally asked about, and you might have omitted some details in the question that narrow down the range of possible answers so that the following is no longer applicable.
But if I understood your intention correctly, you could consider letting the subtypes be handled by the fluent calls.
The idea here is that you initially can only create a simple Message:
Message m0 = Message.newMessage();
Message m1 = m0.withID("id");
On this message, you can call the withID method - that's the only method that all messages have in common. The withID method returns a Message in this case.
Until now, the message is neither a CommandMessage nor any other specialized form. However, when you call the withCommand method, you obviously want to construct a CommandMessage - so you now simply return a CommandMessage:
CommandMessage m2 = m1.withCommand("command");
Similarly, when you call the withParameter method, you receive a CommandWithParamsMessage:
CommandWithParamsMessage m3 = m2.withParameter("name", "value");
This idea is roughly (!) inspired by a blog entry, which is in German, but the code nicely shows how this concept may be used to construct type-safe "Select-From-Where" queries.
Here, the approach is sketched, roughly adapted for your use-case. Of course, there are some details where the implementation will depend on how this is actually going to be used - but I hope that the idea becomes clear.
import java.util.HashMap;
import java.util.Map;
public class FluentTest
{
public static void main(String[] args)
{
CommandWithParamsMessage msg = Message.newMessage().
withID("do").
withCommand("doAction").
withParameter("arg", "value");
Message m0 = Message.newMessage();
Message m1 = m0.withID("id");
CommandMessage m2 = m1.withCommand("command");
CommandWithParamsMessage m3 = m2.withParameter("name", "value");
CommandWithParamsMessage m4 = m3.withCommand("otherCommand");
CommandWithParamsMessage m5 = m4.withID("otherID");
}
}
class Message
{
protected String id;
protected Map<String, String> contents;
static Message newMessage()
{
return new Message();
}
private Message()
{
contents = new HashMap<>();
}
protected Message(Map<String, String> contents)
{
this.contents = contents;
}
public Message withID(String id)
{
this.id = id;
return this;
}
public CommandMessage withCommand(String command)
{
Map<String, String> newContents = new HashMap<String, String>(contents);
newContents.put("command", command);
return new CommandMessage(newContents);
}
}
class CommandMessage extends Message
{
protected CommandMessage(Map<String, String> contents)
{
super(contents);
}
#Override
public CommandMessage withID(String id)
{
this.id = id;
return this;
}
public CommandWithParamsMessage withParameter(String paramName, String paramValue)
{
Map<String, String> newContents = new HashMap<String, String>(contents);
newContents.put(paramName, paramValue);
return new CommandWithParamsMessage(newContents);
}
}
class CommandWithParamsMessage extends CommandMessage
{
protected CommandWithParamsMessage(Map<String, String> contents)
{
super(contents);
}
#Override
public CommandWithParamsMessage withID(String id)
{
this.id = id;
return this;
}
#Override
public CommandWithParamsMessage withCommand(String command)
{
this.contents.put("command", command);
return this;
}
}

NullObjectPattern and the Comparable interface

The problem I'm having has already been asked before: How to implement an interface with an enum, where the interface extends Comparable?
However, none of the solutions solve my exact problem, which is this:
I have a value object, similar to BigDecimal. Sometimes this value will not be set with a real object, because that value is not yet known. So I want to use the Null Object Pattern to represent the times this object is not defined. This is all not a problem, until I try to make my Null Object implement the Comparable interface. Here's an SSCCE to illustrate:
public class ComparableEnumHarness {
public static interface Foo extends Comparable<Foo> {
int getValue();
}
public static class VerySimpleFoo implements Foo {
private final int value;
public VerySimpleFoo(int value) {
this.value = value;
}
#Override
public int compareTo(Foo f) {
return Integer.valueOf(value).compareTo(f.getValue());
}
#Override
public int getValue() {
return value;
}
}
// Error is in the following line:
// The interface Comparable cannot be implemented more than once with different arguments:
// Comparable<ComparableEnumHarness.NullFoo> and Comparable<ComparableEnumHarness.Foo>
public static enum NullFoo implements Foo {
INSTANCE;
#Override
public int compareTo(Foo f) {
return f == this ? 0 : -1; // NullFoo is less than everything except itself
}
#Override
public int getValue() {
return Integer.MIN_VALUE;
}
}
}
Other concerns:
In the real example, there are multiple subclasses of what I'm calling Foo here.
I could probably work around this by having NullFoo not be an enum, but then I can't guarantee there is ever only exactly one instance of it, i.e. Effective Java Item 3, pg. 17-18
I don't recommend the NullObject pattern because I always find myself in one of these 2 situations:
it does not make sense to use NullObject like an object, and it should stay null
NullObject has too much meaning to be just a NullObject, and should be a true object itself (for instance, when it acts like a fully functional default value)
According to our discussion in the comments, it seems to me that your NullObject behaves very much like the 0 value of your normal objects.
What I would do is actually use 0 (or whatever default value makes more sense), and put a flag if you really need to know whether it has been initialized. This way, you will have 2 things to consider:
all uninitialized values won't share the same instance with my solution
for the very same reason, you are now able to initialize your object later without having to create a new instance
Here is the kind of code I think of:
public static class VerySimpleFoo implements Foo {
private int value;
private boolean initialized;
public VerySimpleFoo() {
this.value = 0; // whatever default value makes more sense
this.initialized = false;
}
public VerySimpleFoo(int value) {
this.value = value;
this.initialized = true;
}
#Override
public int compareTo(Foo f) {
// possibly need some distinction here, depending on your default value
// and the behavior you expect
return Integer.valueOf(value).compareTo(f.getValue());
}
#Override
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
this.initialized = true;
}
public boolean isInitialized() {
return initialized;
}
}
As you suggested, I believe one solution would be to use a class instead of an enum:
public class NullFoo implements Foo {
private NullFoo() {
}
public static final Foo INSTANCE = new NullFoo();
#Override
public int compareTo(Foo f) {
return f == this ? 0 : -1;
}
#Override
public int getValue() {
return 0;
}
}
This mimics an enum behavior, but it allows you to implement your Foo interface. The class is not instantiable because of the private constructor, so the only instance available is the one accessible via NullFoo.INSTANCE, which is thread-safe (thanks to the final modifier).
The thing is that Enum already implements Comparable natively, and since the generics are just a sugar code, and lost after compilation, effectively you want to implement the same method twice for the same interface.
I would drop enum, for NullFoo, converting it to class (like you suggested), and make final public static INSTANCE reference with private constructor, (This is not as good as using an enum, but acceptable, in most cases).

Java generics (template) specialization possible (overriding template types with specific types)

I'm wondering what are the options to specialize generic types in Java, i.e. in a templated class to have specific overrides for certain types.
In my case I was a generic class (of type T) to return null usually, but return "" (the empty string), when T is the String type, or 0 (zero) when its the Integer type, etc.
Merely providing a type-specific overload of a method produces a "method is ambiguous" error:
e.g.:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Is the only option to subclass the generic class with a specific type (see StringBar in the following example?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
Is this is the only way, it's a bit of a pain to have to create a subclass for every type I want to specialize instead of an overload of get() in the Bar class.
I'm guessing I could check the instanceof in the Bar.get() method, e.g.
T get(T t) {
if (t instanceof String) return "";
if (t instanceof Integer) return 0;
else return null;
}
However I've been taught to avoid instanceof and use polymorphism when possible.
All things considered, the concensus appears to be that the StringBar method mentioned in the question is the only way to go.
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
Generics in Java are very different from templates in C++ in this respect. It is not possible to write a specific version of a generic class to do something different for a particular case, as C++ can do. It is also not possible to determine at run time what T is - this is because that information is not passed into the byte code (object code) and so doesn't even exist at runtime. This due to something called "type erasure".
BarString and BarInt would be the obvious way of doing this, but there are improvements you can make. For example you can write a generic Bar to cover the common cases, and then write specialized BarString and BarInt to implement special cases. Ensure that the instances can only be created through a factory, which takes the class of the object to be processed:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
That probably won't compile, but I don't have the time to work out the exact syntax. It does illustrate the principle.
The compiler is actually correct, because the following code is compile-time checked (Bar<String> barString = new Bar<String>();) when compiled, from
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
to
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
and is ambiguous as you can't have 2 identical methods with the same return types and the same parameter arguments.
See an explanation by Jon Skeet's:
What is the concept of erasure of generics in java?
Java Generics - Types erasures - when and what happens?
You can subclass Bar<T> and create StringBar (note I removed the static keyword) and override get() method.
public class BarString extends Bar<String> {
#Override
public String get(String x) {
return "";
}
}
Generics in Java aren't made for specialization. They're made for generalization! If you want to specialize for certain types, you should be specializing...through a subclass.
Often you don't need to do something in a specialized manner however. Your StringBar example is kind of contrived because you could have this:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
I don't see why you need to specialize for a String here.

Categories