How to preserve the original type of a type variable in Java?

I have the following example:

class bounds
{
  private StringBuilder str = new StringBuilder();

  public <Type> void add (Type value)
  {
    add_specific (value);
    str.append (String.format("%n"));
  }

  private <Type extends Number> void add_specific (Type value)
  {
    str.append (value);
  }

  public String toString () { return str.toString(); }

  public static void main (String[] args)
  {
    bounds test = new bounds();
    test.add (new Integer (42));
    System.out.print (test.toString());
  }
}

When I try to compile it I get the following error:

bounds.java:7: error: method add_specific in class bounds cannot be applied to given types;
    add_specific (value);
    ^
  required: Type#1
  found: Type#2
  reason: inferred type does not conform to declared bound(s)
    inferred: Type#2
    bound(s): Number
  where Type#1,Type#2 are type-variables:
    Type#1 extends Number declared in method add_specific(Type#1)
    Type#2 extends Object declared in method add(Type#2)
1 error

This looks to me as if the original type of the argument passed to the add method gets lost in the body of add. How can I preserve the type so that the correct add_specific method can be chosen?

Update

I have simplified my example, because I thought it would be easier to understand. But it seems to me that most people do not understand the reason why it contains a generic and a specific function. So I paste a more advanced example. Maybe this makes the reasons more obvious:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class bounds
{
  private StringBuilder str = new StringBuilder();

  public <Type> void add (Type value)
  {
    add_specific (value);
    str.append (String.format("%n"));
  }

  private <Type extends Number> void add_specific (Type value)
  {
    str.append (value);
  }

  private void add_specific (String value)
  {
    str.append ('"');
    for (int i = 0; i < value.length(); i++) {
      char ch = value.charAt(i);
      switch (ch) {
      case '\\': str.append ("\\\\"); break;
      case '"': str.append ("\\\""); break;
      default: str.append (ch);
      }
    }
    str.append ('"');
  }

  private static DateFormat iso8601
    = new SimpleDateFormat("'\"'yyyy-MM-dd'T'HH:mm:ssZ'\"'");

  private void add_specific (Date date)
  {
    str.append (iso8601.format(date));
  }

  public String toString ()
  {
    return str.toString();
  }

  public static void main (String[] args)
  {
    bounds test = new bounds();

    test.add (new Integer (42));
    test.add ("42");
    test.add (new Date());

    System.out.print (test.toString());
  }
}

I have a generic function called add. This generic function does something generic and calls a specific function to do something specific. The problem is, that the type to select the specific function gets lost in the generic function. And the question is how to fix this? How do I have to write the generic function so that it is still possible to select the right specific function in the body of the generic function?

Jon Skeet
people
quotationmark

This looks to me as if the original type of the argument passed to the add method gets lost in the body of add.

Well, type erasure means that Type won't be known at execution time, but that's not the immediate reason you're getting a compile-time error. You can call add with any type - whereas you can only call add_specific with a type which is compatible with Number. So for example, consider:

// TODO: Fix your naming to meet Java naming conventions
bounds b = new bounds();
b.<String>add("foo");

How would you expect that to call add_specific? String doesn't extend Number.

(As an aside, it's also a really bad idea to name a type parameter Type - it's too easy to confuse it with java.lang.reflect.Type.)

Options:

  • Add the extends Number bound to Type in add
  • Remove the bound from Type in add_specific

EDIT: Okay, so it sounds like you'd only given us half the picture - you're expecting overload resolution to be performed at execution time based on Type. That's not going to work, for two reasons:

  • Java always performs overload resolution at compile-time
  • Type erasure means that the information isn't present at execution time to base an overload decision on anyway. If you want that information, you'll need another parameter of type Class<Type>.

people

See more on this question at Stackoverflow