As of Java 8 you can have default or static methods implemented in Interfaces as the below
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
T fromId(ID id);
ID getId();
static String getDescriptionKey(){
return "this is a test";
}
}
I would like to declare the above with the static method having a signature that uses bounds defined by the implementing classes since the method's implementation should be the same for all,with the only thing different should be the generics declared, as such:
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
public static T fromId(ID id) {
if (id == null) {
return null;
}
for (T en : T.values()) {
if (en.getId().equals(id)) {
return en;
}
}
}
ID getId();
String getDescriptionKey();
}
...
public enum Statuses implements DbValuesEnumIface<Integer,Statuses>
which breaks because T and ID are not static and cant be referenced from a static context.
So, how should the above be modified to compile successfully and if thats not possible, how the above should be implemented to achieve the desired purpose while avoiding code duplication within implementing classes .
Since there is no relationship between static methods and the class’ type parameters, which describe how instances are parameterized, you have to make the static method generic on its own. The tricky part is to get the declarations right to describe all needed constraints. And as this answer already explained, you need to a a Class parameter, as otherwise, the implementation has no chance to get hands on the actual type arguments:
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
public static
<ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> T fromId(ID id, Class<T> type) {
if (id == null) {
return null;
}
for (T en : type.getEnumConstants()) {
if (en.getId().equals(id)) {
return en;
}
}
throw new NoSuchElementException();
}
ID getId();
String getDescriptionKey();
}
Note that the type parameters of the static method are independent from the class’ type parameter. You may consider giving them different names for clarity.
So now, given you enum Statuses implements DbValuesEnumIface<Integer,Statuses> example, you can use the method like Statuses status = DbValuesEnumIface.fromId(42, Statuses.class);
Note that for default methods, it is possible to access the actual type, as a method providing the enum type will be provided by the implementation. You only have to declare the presence of the method within the interface:
public interface DbValuesEnumIface<ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> {
public default T fromId(ID id) {
if (id == null) {
return null;
}
for (T en : getDeclaringClass().getEnumConstants()) {
if (en.getId().equals(id)) {
return en;
}
}
throw new NoSuchElementException();
}
Class<T> getDeclaringClass();//no needed to implement it, inherited by java.lang.Enum
ID getId();
String getDescriptionKey();
}
However, the obvious disadvantage is that you need a target instance to invoke the method, i.e. Statuses status = Statuses.SOME_CONSTANT.fromId(42);
There is no easy way as far as I can tell, first you need to change your method to default, you can read more here of why you can't use generics in a static context.
But even if you change it to default things are still not going to work, since you need to pass an instance or class type of the enum to that method, something like this:
public default T fromId(ID id, Class<T> t) {
if (id == null) {
return null;
}
for (T en : t.getEnumConstants()) {
// dome something
}
return null;
}
Now you are hitting another problem, inside fromId - the only thing that you know is that T extends an enum - not your enum may be, thus getId (which seems that your enums have) are simply not known by the compiler.
I don't know an easy way to make this work besides declaring an interface, like :
interface IID {
public int getId();
}
making your enum implement it:
static enum My implements IID {
A {
#Override
public int getId() {
// TODO Auto-generated method stub
return 0;
}
};
}
and change the declaration to:
public interface DbValuesEnumIface<ID, T extends Enum<My> & IID>
You can change from static to default and it will compile successfully.
default EvaluationStatuses fromId(Integer id)
Related
I'm currently trying to write a method that goes through a list of Ant-Objects and returns a list of AntScouts, that extend Ant. In general, List<Ant> can contain a lot of different Objects that inherit from Ant.
I also have an enum for the different kinds of ants:
public enum AntType {
QUEEN,WARRIOR,GATHERER,SCOUT;
public Class getClass(AntType type){
return switch (type) {
case QUEEN -> AntQueen.class;
case WARRIOR -> AntWarrior.class;
case GATHERER -> AntGatherer.class;
case SCOUT -> AntScout.class;
};
}
}
This enum causes a warning:
Raw use of parameterized class 'Class'
And this is the method that currently returns a List<Ant>.
public List<Ant> getAntsType(AntType type){
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
How can I write the method so that it get's the AntType enum as argument and returns a List<AntScout> or List<AntWarrior> corresponding to the enum? I REALLY don't want to use Class<T> clazz as argument since that would defeat the point of the enum. (I also use that enum elsewhere, so I can't get rid of it)
How can I write the method so that it get's the AntType enum as argument and returns a List or List corresponding to the enum?
Edit: This comment probably comes closest to the desired solution:
Java Method that returns different types of generic Lists
Use the Power of Polymorphism
How can I write the method so that it get's the AntType enum as argument and returns a List or List corresponding to the enum?
You're overengineering your code for no good reason.
When you're using inheritance, your classes should be designed in a way that allow to benefit from the Polymorphism.
I.e. by using super type Ant for all your objects and interacting with them through overridden behavior without a need to discriminate between the concrete implementations and operating via type casts.
Therefore, your method returning List<Ant> is quite fine.
And even if you wanted to obtain a List<AntQueen> or List<AntScout> as a result of the method execution then you would need a to use a generic type variable T, or rather T extends Ant, and that would imply that you need a mean of representing the T. And enum would not help you with this task because in Java enums can't be generic. You need to provide as a method argument either an instance of T or a Class<T>.
public <T extends Ant> List<T> getAntsByType(Class<T> tClass) {
return ants.stream().filter(tClass::isAssignableFrom).toList();
}
But I would advise sticking with the initial version returning a List of super type Ant declaring method getType() which returns an instance of enum AntType.
public List<Ant> getAntsByType(AntType type) {
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
And as I've said, Java-enums can't be generic, there's no way to obtain Class<T> through it. Hence, you can remove contrived method getClass() from AntType.
public enum AntType {
QUEEN, WARRIOR, GATHERER, SCOUT;
}
Simulated self-type
But if you're still convinced that your application logic require the ability to generate a list of concrete type like List<AntScout> from a list of super type, then you can make use of a recursive type bound.
For that, you need to define the super type as Ant<T extends Ant<T>>.
This approach is also called a simulated self-type idiom and can be observed in the declaration of the parent type of all enums java.lang.Enum<E extends Enum<E>> and in some other parts of the JDK like method Collections.sort(List<T>) where T is defined as <T extends Comparable<? super T>>.
Let's apply self-type idiom for this case.
Consider super type Ant defined as an interface, declaring a self-returning method (you can change into abstract class if you need to declare some skeletal implementations and common fields):
interface Ant<T extends Ant<T>> {
T self();
AntType getType();
}
And here's a couple of concrete classes:
public static class AntWarrior implements Ant<AntWarrior> {
#Override
public AntWarrior self() {
return this;
}
#Override
public AntType getType() {
return AntType.WARRIOR;
}
}
public static class AntScout implements Ant<AntScout> {
#Override
public AntScout self() {
return this;
}
#Override
public AntType getType() {
return AntType.SCOUT;
}
}
That how we can perform conversion using self() method:
#SuppressWarnings("unchecked")
public static <T extends Ant<T>> List<T> getAntsByType(List<Ant<?>> ants,
AntType type) {
return ants.stream()
.filter(ant -> ant.getType() == type)
.map(ant -> (T) ant.self())
.toList();
}
Usage example:
public static void main(String[] args) {
List<Ant<?>> ants = List.of(new AntWarrior(), new AntScout());
// compiles and runs without issues
List<AntWarrior> antWarriors = getAntsByType(ants, AntType.WARRIOR);
System.out.println(antWarriors);
// compiles and runs without issues
List<AntScout> antScouts = getAntsByType(ants, AntType.SCOUT);
System.out.println(antScouts);
}
Output:
[AntWarrior{}]
[AntScout{}]
A link to Online Demo
This could be possible if enums could be generic, but they can't. However, that is no big deal. Just use a final class with a bunch of public static final fields and a private constructor. A little verbose surely, but is as effective as an enum.
Also, your getClass() method should either be a static method with the switch or else be an instance method without the switch. The later is much better, so went that way. Further, calling it getClass() is not a good idea since it is unrelated with Object.getClass() method. So I called it getAntTypeClass().
And this is the result:
public class Main {
public static void main(String[] args) {
System.out.println(AntType.QUEEN.getAntTypeClass().getName());
System.out.println(AntType.SCOUT.getAntTypeClass().getName());
}
}
final class AntType<T extends Ant> {
public static final AntType<AntQueen> QUEEN = new AntType<>(AntQueen.class );
public static final AntType<AntWarrior> WARRIOR = new AntType<>(AntWarrior.class );
public static final AntType<AntGatherer> GATHERER = new AntType<>(AntGatherer.class);
public static final AntType<AntScout> SCOUT = new AntType<>(AntScout.class );
private final Class<T> antTypeClass;
private AntType(Class<T> antTypeClass) {
this.antTypeClass = antTypeClass;
}
public Class<T> getAntTypeClass() {
return antTypeClass;
}
}
interface Ant {}
class AntWarrior implements Ant {}
class AntGatherer implements Ant {}
class AntScout implements Ant {}
class AntQueen implements Ant {}
See it working on ideone.
I would change your AntType enum method so that it acts as the filter in your stream. I've had to guess at the rest of the class hierarchy but this might give you a starting point.
import java.util.List;
import static java.util.stream.Collectors.toList;
public class Demo {
private List<Ant> ants = List.of(
new AntQueen(),
new AntScout(),
new AntGatherer(),
new AntWarrior());
public static void main(String[] args) {
var demo = new Demo();
System.out.println(demo.getAntsType(AntType.QUEEN));
}
public List<Ant> getAntsType(AntType type) {
return ants.stream().filter(type::matches).collect(toList());
}
}
class Ant {}
class AntQueen extends Ant {}
class AntWarrior extends Ant {}
class AntGatherer extends Ant {}
class AntScout extends Ant {}
enum AntType {
QUEEN, WARRIOR, GATHERER, SCOUT;
public boolean matches(Ant a) {
return switch (this) {
case QUEEN -> a instanceof AntQueen;
case WARRIOR -> a instanceof AntWarrior;
case GATHERER -> a instanceof AntGatherer;
case SCOUT -> a instanceof AntScout;
};
}
}
There are a couple ways you can do this.
First, fix the method in your enum:
public enum AntType {
QUEEN,WARRIOR,GATHERER,SCOUT;
public Class<? extends Ant> getImplClass(){
return switch (this) {
case QUEEN -> AntQueen.class;
case WARRIOR -> AntWarrior.class;
case GATHERER -> AntGatherer.class;
case SCOUT -> AntScout.class;
};
}
}
Since this is a non static method, you don't need to take in the type as an argument. In your example it's not clear where the list is coming from, but if I add it as an argument, it would look like this:
public static List<Ant> getAntsType(AntType type, List<Ant> ants){
return ants.stream().filter(ant -> ant.getClass() == type.getImplClass()).toList();
}
The second way to do it would be to add a method called getType() in the Ant class which returns a type variable that is set by the constructor.
public class Ant {
private AntType type;
protected Ant(AntType type) {
this.type = type;
}
public AntType getType() {
return type;
}
}
Then you set the type in each of the subclass's constructors:
public class AntQueen extends Ant {
protected AntQueen() {
super(AntType.QUEEN);
}
}
Then the filtering code looks like this:
public static List<Ant> getAntsType(AntType type, List<Ant> ants){
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
I thought I understood Java generics pretty well, but then I came across the following in java.lang.Enum:
class Enum<E extends Enum<E>>
Could someone explain how to interpret this type parameter? Bonus points for providing other examples of where a similar type parameter could be used.
It means that the type argument for enum has to derive from an enum which itself has the same type argument. How can this happen? By making the type argument the new type itself. So if I've got an enum called StatusCode, it would be equivalent to:
public class StatusCode extends Enum<StatusCode>
Now if you check the constraints, we've got Enum<StatusCode> - so E=StatusCode. Let's check: does E extend Enum<StatusCode>? Yes! We're okay.
You may well be asking yourself what the point of this is :) Well, it means that the API for Enum can refer to itself - for instance, being able to say that Enum<E> implements Comparable<E>. The base class is able to do the comparisons (in the case of enums) but it can make sure that it only compares the right kind of enums with each other. (EDIT: Well, nearly - see the edit at the bottom.)
I've used something similar in my C# port of ProtocolBuffers. There are "messages" (immutable) and "builders" (mutable, used to build a message) - and they come as pairs of types. The interfaces involved are:
public interface IBuilder<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>
public interface IMessage<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>
This means that from a message you can get an appropriate builder (e.g. to take a copy of a message and change some bits) and from a builder you can get an appropriate message when you've finished building it. It's a good job users of the API don't need to actually care about this though - it's horrendously complicated, and took several iterations to get to where it is.
EDIT: Note that this doesn't stop you from creating odd types which use a type argument which itself is okay, but which isn't the same type. The purpose is to give benefits in the right case rather than protect you from the wrong case.
So if Enum weren't handled "specially" in Java anyway, you could (as noted in comments) create the following types:
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second would implement Comparable<First> rather than Comparable<Second>... but First itself would be fine.
The following is a modified version of the explanation from the book Java Generics and Collections:
We have an Enum declared
enum Season { WINTER, SPRING, SUMMER, FALL }
which will be expanded to a class
final class Season extends ...
where ... is to be the somehow-parameterised base class for Enums. Let's work
out what that has to be. Well, one of the requirements for Season is that it should implement Comparable<Season>. So we're going to need
Season extends ... implements Comparable<Season>
What could you use for ... that would allow this to work? Given that it has to be a parameterisation of Enum, the only choice is Enum<Season>, so that you can have:
Season extends Enum<Season>
Enum<Season> implements Comparable<Season>
So Enum is parameterised on types like Season. Abstract from Season and
you get that the parameter of Enum is any type that satisfies
E extends Enum<E>
Maurice Naftalin (co-author, Java Generics and Collections)
This can be illustrated by a simple example and a technique which can be used to implement chained method calls for sub-classes. In an example below setName returns a Node so chaining won't work for the City:
class Node {
String name;
Node setName(String name) {
this.name = name;
return this;
}
}
class City extends Node {
int square;
City setSquare(int square) {
this.square = square;
return this;
}
}
public static void main(String[] args) {
City city = new City()
.setName("LA")
.setSquare(100); // won't compile, setName() returns Node
}
So we could reference a sub-class in a generic declaration, so that the City now returns the correct type:
abstract class Node<SELF extends Node<SELF>>{
String name;
SELF setName(String name) {
this.name = name;
return self();
}
protected abstract SELF self();
}
class City extends Node<City> {
int square;
City setSquare(int square) {
this.square = square;
return self();
}
#Override
protected City self() {
return this;
}
public static void main(String[] args) {
City city = new City()
.setName("LA")
.setSquare(100); // ok!
}
}
You are not the only one wondering what that means; see Chaotic Java blog.
“If a class extends this class, it should pass a parameter E. The parameter E’s bounds are for a class which extends this class with the same parameter E”.
This post has totally clarified to me these problem of 'recursive generic types'.
I just wanted to add another case where this particular structure is necessary.
Suppose you have generic nodes in a generic graph:
public abstract class Node<T extends Node<T>>
{
public void addNeighbor(T);
public void addNeighbors(Collection<? extends T> nodes);
public Collection<T> getNeighbor();
}
Then you can have graphs of specialized types:
public class City extends Node<City>
{
public void addNeighbor(City){...}
public void addNeighbors(Collection<? extends City> nodes){...}
public Collection<City> getNeighbor(){...}
}
If you look at the Enum source code, it has the following:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
#SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
}
First thing first, what does E extends Enum<E> mean? It means the type parameter is something that extends from Enum, and isn't parametrized with a raw type (it's parametrized by itself).
This is relevant if you have an enum
public enum MyEnum {
THING1,
THING2;
}
which, if I know correctly, is translated to
public final class MyEnum extends Enum<MyEnum> {
public static final MyEnum THING1 = new MyEnum();
public static final MyEnum THING2 = new MyEnum();
}
So this means that MyEnum receives the following methods:
public final int compareTo(MyEnum o) {
Enum<?> other = (Enum<?>)o;
Enum<MyEnum> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
And even more importantly,
#SuppressWarnings("unchecked")
public final Class<MyEnum> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
}
This makes getDeclaringClass() cast to the proper Class<T> object.
A way clearer example is the one that I answered on this question where you cannot avoid this construct if you want to specify a generic bound.
According to wikipedia, this pattern is called Curiously recurring template pattern.
Basically, by using the CRTP pattern, we can easily refer to subclass type without type casting, which means by using the pattern, we can imitate virtual function.
I am refactoring some legacy code and have come across a problem which I'm sure has a elegant solution - but I can't quite get there.
Initially there were a load of classes which extended an abstract class BaseType. Each of these classes has a enum - XmlElementTag - with values specific to the class:
enum XmlElementTag {value1, value2, value3}
They each also have a method :
private XmlElementTag getTag(String s){
XmlElementTag ret = null;
try {
ret = XmlElementTag.valueOf(s);
} catch (Exception e) {
Log.e(this, s+" is not supported tag");
}
return ret;
}
Every class has this exact same getTag method, but obviously they are all referring to the XmlElementTag enum specific to the class they are in. So, I'd like to get rid of this code duplication if I can.
I thought that maybe I could use a marker interface to solve this problem, so created one as which each XmlElementTag enum now inherits and rewrote the getTag method and put it in the super class.
So I have this in each class:
private XmlElementTag implements GenericTag {value1, value2, value3};
And this in the BaseType superclass:
public interface GenericTag {}
protected GenericTag getTag(String tagName){
XmlElementTag tag = null;
try {
tag = XmlElementTag.valueOf(tagName);
} catch (Exception e) {
Log.e(this, tagName+" is not supported tag");
}
return tag;
}
But again this doesn't work as the BaseType super class doesn't know what XmlElementTag is; Java doesn't allow abstract class variables; and creating this element in the BaseType won't work, as the getTag code will always refer to this enum, rather than the one in the class which extends BaseType.
Can anyone point me in the correct direction?
I guess you could write a static generic helper method that did what getTag does. It would need to use reflection under the hood, and would most likely require you to pass the enumeration's Class object as a parameter.
But IMO, you shouldn't. The getTag() method is kind of wrong-headed. It is turning what is effectively bad input into a null. That's wrong from two perspectives:
In most contexts, "you gave me bad stuff" should not be treated as "you gave me nothing".
If you are not scrupulously careful, those null values are going to come back to bite you as NullPointerExceptions.
So really, your application code should either catch and deal with the IllegalArgumentException that arises when the conversion goes wrong, or it should allow the exception to bubble up to the top where it can be reported as (for instance) an error parsing the input stream.
(I don't think that an enum can either extend or be extended, so I don't think your enums can inherit a generic version of this class.)
You might be able to coalesce the XmlElementTag elements into a single enum and establish an EnumSet apropos to each derived type. There's an example here.
Addendum: In this scheme, getTag() would then become a single method of the combined enum. Each derived class would invoke getTag() using the Set that it considers valid. The method might have a signature such as this:
public static XmlElementTag getTag(Set valid, String s) { ... }
Unfortunately Java enums don't come with a good meta-class (Class is evil). However, all you really need here is the list (array) of the enum values.
As it's a private method, you might as well use composition.
import static java.util.Objects.requireNonNull;
/* pp */ class EnumFinder<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType {
private static final EnumFinder<XmlElementType> finder = // note, shared
new EnumFinder<>(XmlElementType.values());
...
finder.getTag(name)
...
}
(Create a Map<String,E> if you really want to. Unnecessary for reasonably sized enums.)
If you really want to use inheritance, then that is much the same. (Unfortunately as we are using an array, unless you add more boilerplate to your code, this code will create an unnecessary extra array per instance - probably not a significant issue, but may be.):
/* pp */ abstract class BaseType<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType extends BaseType<XmlElementType> {
public DerivedType() {
super(XmlElementType.values());
}
...
this.getTag(name)
...
}
You could use generics for that:
The Base is
public abstract class Base {
protected static <T extends Enum<T>> T getTag(Class<T> enumType, String s) {
T ret = null;
try {
ret = Enum.valueOf(enumType, s);
} catch (Exception e) {
System.err.println(s + " is not supported tag");
}
return ret;
}
protected abstract <T extends Enum<T>> T getTag(String s);
}
Your numerous classes have a shorter getTag() (and all the logic is in the Base)
public class ClassA extends Base {
enum XmlElementTag {
UL, LI
}
#Override
protected XmlElementTag getTag(String s) {
return Base.getTag(XmlElementTag.class, s);
}
}
(same thing for ClassB)
I think that you wanted to achieve something like this (correct me if I'm wrong):
interface GenericTag {
public GenericTag fromString(String str) throws IllegalArgumentException;
}
class BaseType {
protected GenericTag getTag(String tagName) {
GenericTag tag = null;
try {
tag = tag.fromString(tagName);
} catch (Exception e) {
Log.e(this, tagName+" tag is not supported");
}
return tag;
}
}
class ConcreteTypeA extends BaseType {
enum XmlElementTag implements GenericTag {
TAG1, TAG2;
public GenericTag fromString(String str) throws IllegalArgumentException {
return XmlElementTag.valueOf(str);
}
}
}
However, that will never work. You would need the fromString method to return an instance of appropriate class (in this case, enum) implementing the GenericTag, but the fromString method has to be performed by that concrete class, which you don't have yet, so you'll get a NullPointerException.
It's a sort of Chicken and Egg Problem! :)
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.
I have a base Entity class:
public class Entity
{
abstract int getTypeID();
}
The method int getTypeID() returns a number that is unique to that class:
public class OneEntity extends Entity
{
int getTypeID()
{
return 1; // Actually defined in a constants class
}
}
Now I want to be able to safely cast it and assign it.
I can do it this way:
public void castTheEntityAndDoSomething(Entity ent)
{
if (isType(ent, 1)) // this is the 1 from the OneEntity class
{
OneEntity oneEnt = (OneEntity)ent;
// ... and then do something
}
}
public bool isType(Entity ent, int type)
{
return ent.getTypeID() == type;
}
But what I'd like to do is combine the cast and the type check in one line.
Something like:
if (OneEntity oneEnt = entityCast(ent, 1))
{
// use a method specific to the OneEntity class
}
Is this possible? What does the method look like?
It would be even better if I could use the subclass name as an argument of the safe casting method.
EDIT:
So I've written this method to avoid the type id etc. etc.
#SuppressWarnings("unchecked")
public static <T extends Entity> T castEntity(Entity ent)
{
if (ent instanceof T)
{
return (T)ent;
}
return null;
}
But it has this error:
Cannot perform instanceof check against type parameter T. Use instead its erasure Entity since generic type information will be erased at runtime
What do I need to do to fix this compile error? Is this even going in the right direction?
In case you have defined this typeId for the sole purpose of casting, then please don't do that and use instanceof operator instead.
Then you just need to do something like this,
if (ent instanceof EntityOne) {
OneEntity oneEntity = (OneEntity) ent;
// do whatever
}
Now, taking your example here,
if (Entity oneEnt = entityCast(ent, 1))
{
// do something with oneEnt
}
Suppose this if statement of yours work and your entityCast() method return OneEntity. Don't you think you are again getting that returned value in type Entity. Hence spoiling the whole purpose.
So, please explain what are you trying to do exactly.
If you implement an interface which defines the methods you want to call on them from the "do something" blocks and implement that inteface in all your derived entiries, your have solved problem by using polymorphism.
You might want to rethink your architecture.
First of all maybe you should not have a typeID field in the class.
You should rely on the "power" of inheritance and/or interfaces instead.
// Entity.java
public interface Entity { abstract public void doSomeThing(); }
// EntityType1.java
public class OneEntity extends Entity {
#Override
public void doSomeThing() {
// do something specific for entity type 1
}
}
// EntityType2.java
public class TwoEntity extends Entity {
#Override
public void doSomeThing() {
// do something specific for entity type 2
}
}
// Main.java
public static void main(String[] args) {
Entity e1 = new EntityType1();
Entity e2 = new EntityType2();
e1.doSomeThing();
e2.doSomeThing();
}
You should encapsulate the different behavior in the implementation classes.
If you think you have good reasons to detach the behavior from the entities you would better use this same logic in a hierarchy of external processing classes (maybe with a simple factory on top) and use "instanceof" in the factory method.
I suppose that you could do this:
OneEntity oneEnt;
if (isType(ent, 1) && (oneEnt = (OneEntity) ent) != null) {
// ... and then do something
}
... or the equivalent with instanceof instead of your icky isType method ...
Or you could define a method called oneEntityOrNull as follows:
public OneEntity oneEntityOrNull(Entity ent) {
return ent instanceof OneEntity ? (OneEntity) ent : null;
}
and then
OneEntity oneEnt;
if ((oneEnt = oneEntityOrNull(ent)) != null) {
// ... and then do something
}
but IMO both of these are a BAD IDEA since the code is harder to understand than the original.