Is there a better "workaround" than this? I want to avoid the use of a PREFIX (local var) when accessing the methods on TableMap.
public class TableMap extends TreeMap<String, String> {
public String field1, field2, field3;
public TableMap(Tables table){}
public void method(){}
public void method2(){}
public void method3(){}
...
}
workaround!
public enum Tables {
table1, table2, table3;
public final TableMap MAP=new TableMap(this);
private Tables(){}
}
needed!
public enum Tables extends TableMap {
table1, table2, table3;
public Tables(){
super(table);
}
}
Example throughout the code:
// workaround!
Tables.table1.MAP.method();
Tables.table2.MAP.method();
Tables.table3.MAP.method();
...
// needed!
Tables.table1.method();
Tables.table2.method();
Tables.table3.method();
...
In Java, enum types must extend java.lang.Enum. Since Java types can every only extend a single type, you might think that public class TableMap extends Enum might work, but no, the compiler won't allow this.
In my own code, I use enums often as mere keys because they are so hostile. I have them implement a common interface and then use a factory to look up specific implementations of "worker" instances that I can then use.
One way to get closer to the syntax that you want is to use the delegate pattern:
public enum Tables {
...
public void method() {
MAP.method();
}
}
I think you may be trying to put too much intelligence into the enum.
I have found this approach very useful. It avoids many of the issues arising from the fact that you cannot extend enums (well actually you can but not in a very useful way).
Essentially, make the enum a sub-class and pass its characteristics up to your super class as an EnumSet. This way you still get all the benefits of enums including type safety.
public static class MappedEnum<E extends Enum<E>> extends TreeMap<String, String> {
public MappedEnum(EnumSet<E> e) {
// Whatever you like with the set.
}
public void method(E e) {
}
}
public static class Foo extends MappedEnum<Foo.Tables> {
public enum Tables {
table1, table2, table3;
}
public Foo() {
super(EnumSet.allOf(Tables.class));
}
#Override
public void method(Foo.Tables e) {
}
}
You could probably even use an EnumMap instead of your TreeMap for better efficiency.
Related
I'm trying to define and then implement an abstract setter which takes a List of Objects as a parameter. Here's the gist of this simple idea:
public abstract class MyClass {
public abstract void setThings(List<?> things);
}
public class Bar extends MyClass {
private List<String> things;
#Override
public void setThings(List<String> things) {
this.things = things;
}
}
That doesn't work. I get Method does not override method from its superclass and both methods have the same erasure, but neither overrides the other. I understand the latter error relating to erasures, but even so I can't figure out the correct way to do this. I've tried some others like:
public abstract <T> void setThings(List<T> things);
...as well as a few others. And I've found other questions/answers on SO that come close to addressing this, but none that have provided a solid answer (at least not that was clear to me). I've read through the tutorials as well to no avail. What am I missing?
So Java is quite correctly telling you that you haven't implemented the abstract method setThings which takes a List<?> not a List<T> or List<String>. All of these are different things. See this question for a detailed explanation.
The simplest solution is to introduce a generic for your abstract class as well:
public abstract class MyClass<T> {
public abstract void setThings(List<T> things);
}
public class SubClass extends MyClass<String> {
private List<String> things;
public void setThings(List<String> things) {
this.things = things;
}
}
List<?> things is a list of unknown type.
List<T> things is a list of type T.
These two things aren't the same, which is why you're getting that compilation error.
There are a couple of sensible ways to eradicate the error:
Generify both classes
abstract class MyClass<T> {
public abstract void setThings(List<T> things);
}
class Bar<T> extends MyClass<T> {
private List<T> things;
#Override
public void setThings(List<T> things) {
this.things = things;
}
}
Make Bar accept a list of unknown type as well
abstract class MyClass {
public abstract void setThings(List<?> things);
}
class Bar extends MyClass {
private List<?> things;
#Override
public void setThings(List<?> things) {
this.things = things;
}
}
Forgive me if there are syntax problems. The goal of this is not to get the code perfect but to get the design.
I have an interface ITable<T>
public interface ITable<T> {
public Collection<T> getEntries();
public void add(CustomObj value);
public Collection<CustomObj> getCustomObjects();
}
that is used by two classes:
TableOne<CustomObj> and TableTwo<Pair<CustomObj, CustomObj>>
Then I have an interface that applies these tables using a function
public interface ITableFunction<T> {
public abstract Collection<ITable<?>> execute(Collection<ITable<T>> tables);
}
My dilemma occurs when I try to create a generic Abstract class
public abstract class AbstractTableFunctionCombined<T> implements ITableFunction<T>{
private boolean someBool;
public AbstractTableFunctionCombined(boolean someBool){
this.someBool = someBool;
}
#Override
public Collection<ITable<?>> execute(Collection<ITable<T>> tables){
// What i would like to do, but can't right now:
ITable<T> combinedTable;
if (someBool){
combinedTable = new TableOne();
} else {
combinedTable = new TableTwo();
}
for(ITable<T> table : tables){
combinedTable.addAll(table.getCustomObjects());
}
for(T entry : table.getEntries()){
execute(entry);
}
}
public abstract void execute(T entry);
}
The issue is that I can't guarantee that the type T is the same as the table that I'm trying to instantiate. I thought I had to create some kind of relationship from the Pair<CustomObj, CustomObj> and the regular CustomObj. I tried creating a Entry interface that these both would use, and having ITable<T> be ITable<T extends Entry> but again this runs into the same problem.
I also thought that maybe I can make the TableOne and TableTwo classes use the same Generic i.e. TableTwo<T> implements ITable<T>, but TableTwo has a hard restriction of using Pair<CustomObj, CustomObj>.
Would I have to create two separate classes: AbstractTableFunctionOne<CustomObj> and AbstractTableFunctionTwo<Pair<CustomObj, CustomObj>> ? I would like to avoid this as it would be a lot of duplicated code.
Or am I over forcing this Object oriented design? Should TableOne and TableTwo not even implement the same interface?
This Interface has some issus:
public interface ITableFunction {
public abstract execute(Collection<ITable<T>> tables);
}
You need a return type and a Generic:
public interface ITableFunction<T> {
public abstract void execute(Collection<ITable<T>> tables);
}
and return type of Method
public Collection<ITable<T>> execute(Collection<ITable<T>> tables){
..
should be Collection OR void in declaration AND implementation.
Suppose I have class:
public interface ObjectWithId<T> {
T getId();
void setId(T id);
}
public class BaseDBObject<T> implements ObjectWithId<T> {
// Common fields:
private T id;
private String createdBy;
...
}
And one concrete:
public class ConstituentEntity extends BaseDBObject<Integer> {
...
}
Then I create some service, which say also take generic parameter one of ? extends BaseDBObject and in some method should operate with id of appropriate type.
Now it implemented with double generics:
abstract public class BaseService<IdT,T extends BaseDBObject<IdT>> {
public T getById(IdT id){
return getDao().getById(id);
}
}
public class ConstituentEntityService extends BaseService<Integer, ConstituentEntity>{
...
}
But look at last definition again. I known what ConstituentEntity already have Integer as their key holder, so it is seems ugly for me again provide that type for service.
I look some possibility to write next construction:
abstract public class BaseService<T extends BaseDBObject> {
public T getById(??T.T?? id){
return getDao().getById(id);
}
}
In C++ we have typename and typedef for such cases with their complex but powerful metaprogramming possibilities.
Is something similar possible in Java?
I guess, it's not possible. If you have many services which use Integer as T, then you may define intermediate class:
public abstract class IntegerService<S extends BaseDBObject<Integer>>
extends BaseService<Integer, S>{
...
}
And use public class ConstituentEntityService extends IntegerService<ConstituentEntity>. But you will have to do this for every T type which might be inappropriate if there are many different types used as T.
public class MyClass<T> {
private Map<Class<?>, Object> member;
public <E> void putEnumSet(Class<E> enumSetType, E enumSet) {
this.member.put(enumSetType, enumSetType.cast(enumSet));
}
public <E> E getEnumSet(Class<E> enumType) {
return enumType.cast(this.member.get(enumType));
}
};
public enum Category {
// ...
};
The member in MyClass is used to store several kinds of EnumSet with different Enum type. While implementing relative methods, I meet some problems: when I try to call the method like this:
public static void main(String[] args) {
EnumSet<Category> set = EnumSet.noneOf(Category.class);
MyClass<Word> newClass = new MyClass<Word>();
newClass.putEnumSet(set.getClass(), set);
}
Here comes the error:
The method putEnumSet(Class<E>, E) in the type MyClass<Word> is not applicable for the arguments (Class<capture#1-of ? extends EnumSet>, EnumSet<Category>)
How to deal with this problem? I think it may come from raw type or type erasure, but I do not know the main reason. Thanks.
How to deal with this problem?
E extends EnumSet<E>
This is very confusing as it says you have to have a element E which must extend EnumSet<E> i.e. you need an element type which is itself an EnumSet of E
You have a problem that all EnumSet classes are the same at runtime. I.e. there is only one EnumSet.class. You are better off recording the class of elements.
public class MyClass {
private Map<Class, Set> member;
public <E> void putEnumSet(Class<E> elementType, Set<E> enumSet) {
this.member.put(elementType, enumSet);
}
public <E> Set<E> getEnumSet(Class<E> elementType) {
return (Set<E>) this.member.get(elementType));
}
};
Class objects can be difficult to use. As you have noticed, they're not easy to use with generic types because due to type erasure EnumSet<Category>.class is not legal code. It would be impossible to use your approach to store EnumSets for different Enums because there is only one Class object for all EnumSets, namely EnumSet.class.
One solution I have found to this is to replace Class<?> with my own key object. Here is a complete program demonstrating this approach.
public class Main {
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Here you would instantiate all the keys you will need.
public static final ClassKey<String> STRING_KEY = new ClassKey<String>();
public static final ClassKey<EnumSet<Shape>> SHAPE_SET_KEY = new ClassKey<EnumSet<Shape>>();
public static final class ClassKey<T> { private ClassKey() {} }
private Map<ClassKey<?>, Object> member = new HashMap<ClassKey<?>, Object>();
public <E extends Enum<E>> void putEnumSet(ClassKey<EnumSet<E>> enumSetType, EnumSet<E> enumSet) {
this.member.put(enumSetType, enumSet);
}
public <E extends Enum<E>> EnumSet<E> getEnumSet(ClassKey<EnumSet<E>> enumType) {
return (EnumSet<E>) member.get(enumType);
}
public static void main(String[] args) {
Main main = new Main();
EnumSet<Shape> enumSet = EnumSet.allOf(Shape.class);
main.putEnumSet(SHAPE_SET_KEY, enumSet);
EnumSet<Shape> shapes = main.getEnumSet(SHAPE_SET_KEY);
System.out.println(shapes);
}
}
One major drawback to this approach is that you have to have a fixed bank of ClassKey objects. It would not work to create these objects on the fly because if you usednew ClassKey<EnumSet<Shape>> to put an EnumSet into member and then tried to use new ClassKey<EnumSet<Shape>> to retrieve the EnumSet, you would find it would't work because the keys would not be equal. There is no way to write an equals() method for ClassKey that works because, due to type erasure, it would be impossible to tell a ClassKey<EnumSet<Shape>> from a ClassKey<EnumSet<Category>>.
I have an abstract class (or an interface). In this class I want to define an enum, in order to force classes that extend this abstract class (or implement this interface) to declare an enum with the same name.
abstract class Operator {
public abstract enum Symbol;
public Symbol value;
}
class Binary extends Operator {
public enum Symbol {
pls,
min,
mul,
div,
//...
}
}
class Unary extends Operator {
public enum Symbol {
sin,
cos,
tan,
cot,
//...
}
}
Assume I can't know the values of sub classes enums. I want that every extending class had an enum with that name and its values. I want to use enums (especially because it's easy to switch enums)
There's no way to do this thing and moreover, even if it were, how would you call the subclass' implementation? I mean, only method calls can be virtual, ie dispatched at runtime. Types can not, so without cheating with reflection (which throws away any type safety anyhow, so that you don't even need to subclass), you would not be able to call the overridden type (in fact, types can't be overridden).
Maybe you can still achive your objectives by using composition:
public abstract class Operator<T extends Enum<T>> {
public final Class<T> symbol;
public Operator(Class<T> symbol) { this.symbol = symbol; }
}
public enum BinarySymbol { PLS, MIN, MUL, DIV }
public class Binary extends Operator<BinarySymbol> {
public Binary(Object operand1, Object operand2, BinarySymbol symbol) {
super(symbol);
}
}
Your base class Operator can dynamically read the enumerated values through reflection, via Class.getEnumConstants()
You can't enforce it at compile time. One way would be to use reflection at runtime to see if the class has been implemented correctly. I don't suggest this, but it's possible.
What you can do is have enums that implement a common interface, and then utilize those interfaces:
public interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {
//methods that your enum should be implementing
}
The extension for the interface generic declaration is there to guarantee it is only called by enums that implement your interface
And then any enum you have to specify can implement it like so:
public enum MyEnum implements YourEnumInterface<MyEnum> {
// enum constants
TEST_VALUE;
// implementation of interface methods
}
From there, you would simply work with the YourEnumInterface as an object, and you can pass enum values for them:
public void doSomething(YourEnumInterface enm) {
//work with enm
}
//Elsewheres...
doSomething(MyEnum.TEST_VALUE);
It should be noted, that once you lower your enum down to the interface itself, you won't be able to change the constant you are working with (without casting, which can potentially be unsafe). This should really be used more or less for passing things to a destination that just works with the values (like a config enum, or internalization of strings, etc)
So in relevance to forcing a subclass to implement it:
public class YourSuperClass {
public abstract YourEnumInterface symbol;
}
A runnable example
public class EnumMagic {
public static void main(String[] args) {
YourSubClass clazz = new YourSubClass();
//prints the default value
System.out.println(clazz.getEnum().getValue());
//gets the value of a specified enum constant
System.out.println(clazz.getEnum().SECOND_TEST.getValue());
}
}
abstract class YourSuperClass {
protected YourEnumInterface symbol;
public abstract YourEnumInterface getEnum();
}
interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {
public int getValue();
}
class YourSubClass extends YourSuperClass {
public enum MyEnum implements YourEnumInterface<MyEnum> {
TEST_VALUE(1),
SECOND_TEST(2);
private final int val;
private MyEnum(int example) {
this.val = example;
}
public int getValue() {
return this.val;
}
}
public YourSubClass() {
this.symbol = MyEnum.TEST_VALUE;
}
public MyEnum getEnum() {
return MyEnum.TEST_VALUE;
}
}
The output of this progam is:
1
2
And you can simply get the class' specified enum constant via getEnum, which they will return their own internal enum.
However, once downcasted to the super type, e.g. YourSuperClass intc = clazz;, then you will lose this ability to specify the enum itself. Depending on how you store your instances will determine whether or not this requires changes.