简体   繁体   中英

Subclassing a generic type, returning instances of the subclass from a method in another class

It was such a simple, brilliant idea. Use the power of Java 5.0 enumerated types to encode details of a data dictionary (attribute name, type, range, units, etc.) and create a type-safe system for setting and reading attribute values (i,.e., attribute AAH is short, ACC is enumerated and should only accept the values ACC001, ACC002, ACC003, etc.).

The hitch is that different attributes have different types (integer, float, text, enumerated), and the behaviors for each type are different. So I create a base class with a type parameter and some abstract methods:

public abstract class GsAttributeValueBase<T extends Comparable<T>> {
  protected T m_value;
  ...
  public GsAttributeValueBase(...) {..}
  ...
  public abstract void SetValue(T value) throws IllegalArgumentException;
  public T GetValue() { return m_value; }
  // etc., etc., etc
}

I then subclass this for each type (basically, I'm trying to fake partial specialization):

public class GsAttributeValueShort extends GsAttributeValueBase<Short> {...}
public class GsAttributeValueLong  extends GsAttributeValueBase<Long> {...}
public class GsAttributeValueEncoded extends GsAttributeValueBase<GsAttributeEncodedValueEnum> {...}
...

So far so good. Now I want to basically create a factory method in the attribute enumeration type to return an instance of one of the above subtypes (since each attribute knows its type and range), something like

public GsAttributeValueBase<? extends Comparable<?>> CreateInstance()
{
  switch(m_format)
  {
  case SHORT: return new GsAttributeValueShort(...);
  case LONG: return new GsAttributeValueLong(...);
  case ENCODED: return new GsAttributeValueEncoded(...);
  ...
  }
}

and call the method as:

GsAttributeValueShort = GsAttributeEnum.AAH.CreateInstance();

This is where I hit a brick wall; I get an incompatible types error on the order of

found   : GsAttributeValueBase<capture of ? extends java.lang.Comparable<?>>
required: GsAttributeValueShort

I've tried roughly a dozen permutations on the declaration of CreateInstance() so far (it can't be static, since it relies on information specific to the enumeration instance). I'm about to tear my hair out at this point; I've wasted several days going down this rabbit hole, and need to either get this working today or punt altogether.

I really want to make this work; I think it would be valuable to not just this project but other projects going forward. But Java generics don't behave like C++ templates (something that's been driven home with a vengeance over the past week), and I know I'm missing something vital here, but I can't see what it is.

EDIT

I can't make this work the way I'm envisioning in my head and I've burned too much time on it. Thanks for the suggestions, but I'm going to go ahead and close this down.

EDIT 2

Oh. I can't close my own question. Oh well.

What about:

public <T extends Comparable<T>> GsAttributeValueBase<? super T> CreateInstance() {
    ...
}

Just use a map and my TypeSafeMap pattern .

Some thoughts on Generics: Generics are meant to make collections type safe. They aren't really intended for complex things like building type-safe classes at runtime. So be mindful and use your tools so that they don't become a burden. If a cast works and you don't understand how the generic construct works (even if you just wrote it), use the cast. Just imagine coming back to this code in half a year and having to fix it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM