0

我有以下示例:

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());
  }
}

当我尝试编译它时,我收到以下错误:

bounds.java:7:错误:类边界中的方法 add_specific 不能应用于给定类型;
    add_specific (值);
    ^
  必需:类型#1
  找到:类型#2
  原因:推断类型不符合声明的边界
    推断:类型#2
    bound(s): 数字
  其中 Type#1,Type#2 是类型变量:
    Type#1 扩展了方法 add_specific(Type#1) 中声明的 Number
    Type#2 扩展了在方法 add(Type#2) 中声明的 Object
1 个错误

在我看来,好像传递给add方法的参数的原始类型在add. 如何保留类型以便add_specific选择正确的方法?

更新

我已经简化了我的例子,因为我认为它会更容易理解。但在我看来,大多数人不明白它为什么包含通用和特定功能的原因。所以我贴了一个更高级的例子。也许这让原因更加明显:

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());
  }
}

我有一个名为add. 这个通用函数做一些通用的事情,并调用一个特定的函数来做一些特定的事情。问题是,选择特定函数的类型在泛型函数中丢失了。问题是如何解决这个问题?我如何编写泛型函数,以便仍然可以在泛型函数的主体中选择正确的特定函数?

4

4 回答 4

3

这在我看来好像传递给 add 方法的参数的原始类型在add.

好吧,类型擦除意味着Type在执行时不会知道,但这不是您收到编译时错误的直接原因。您可以add使用任何类型调用 - 而您只能add_specific使用兼容的类型调用Number。例如,考虑:

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

你会怎么指望它add_specificString不扩展Number

(顺便说一句,命名类型参数也是一个非常糟糕的主意Type- 很容易将它与 . 混淆java.lang.reflect.Type。)

选项:

  • extends Number绑定添加到Typeinadd
  • Type从in 中删除绑定add_specific

编辑:好的,所以听起来你只给了我们一半的图片 - 你期望在执行时基于Type. 这是行不通的,有两个原因:

  • Java总是在编译时执行重载决议
  • 类型擦除意味着信息在执行时不存在,无论如何都不能作为重载决策的基础。如果您想要该信息,则需要另一个 type 参数Class<Type>
于 2013-10-08T15:15:56.043 回答
1

问题是这部分:

public <Type> void add (Type value)
{
   add_specific (value);
   ...
}

add_specific requires the value to be of a type that extends Number but add doesn't require/ensure that. Hence the error.

To fix it, you'd need to change add to use <Type extends Number>, but I doubt that's what you want. It seems like a design error to me: add_specific should call the more generic looking add and not the other way round.

Btw, as John Skeet already said, please adhere to the coding conventions, which will make it easer to spot bugs and read your code.

于 2013-10-08T15:16:28.153 回答
0

去掉 add 和 add_specific 方法,只重载 add 方法。但是请注意,选择哪种方法是在编译时静态完成的,而不是在运行时动态完成的。

就像乔恩说的那样,你试图做的事情是行不通的。如果您希望所有客户端代码看起来都一样,请执行以下操作;尽管在 Effective Java 中,Bloch 建议您避免使用这种令人困惑的 API。

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

  private void appendNewline() {
       str.append (String.format("%n"));
  }
  public  void add (Number value)   {
    str.append (value);   
    appendNewline();
  }

  public void add (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 ('"');  
  appendNewline();
 }

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

  public void add (Date date)   {
    str.append (iso8601.format(date));   
    appendNewline();
  }

  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());   } 
}
于 2013-10-08T16:02:41.620 回答
0

编译器在尖叫,因为value您的add方法中的引用不一定是Number

解决这个问题:

add方法更改为:

public <Type extends Number> void add (Type value)
{

}

或添加:

public <Type> void add (Type value)
  {
    if (value instanceof Number){
        add_specific ((Number)value);
        str.append (String.format("%n"));
    }
  }
于 2013-10-08T15:19:11.457 回答