当前位置: 首页 > 知识库问答 >
问题:

基于返回类型的Java泛型转换?

羊舌庆
2023-03-14

下面的代码来自一个名为ButterKnife的Android库。我正在弄清楚它是怎么工作的。

@SuppressWarnings("unchecked") // That's the point.
  public <T> T castParam(Object value, String from, int fromPosition, String to, int toPosition) {
    try {
      return (T) value;
    } catch (ClassCastException e) {
      throw new IllegalStateException("Parameter #"
          + (fromPosition + 1)
          + " of method '"
          + from
          + "' was of the wrong type for parameter #"
          + (toPosition + 1)
          + " of method '"
          + to
          + "'. See cause for more info.", e);
    }
  }

我试图重新创建此函数的行为:

  @SuppressWarnings("unchecked")
    public static <T> T cast(Object o){
        try {
            return (T) o;
        } catch (ClassCastException e){
            throw new AssertionError("Error");
        }
    }

和用法:

Object o = new String("test");
Double d = cast(o);

但是异常并非永远不会被捕获,而是在调用方法时在行中抛出。为什么?

还有,这到底是如何工作的?该方法如何知道要转换到什么?

共有2个答案

孟浩慨
2023-03-14

正如SJuan67所解释的,您不能像Java编译器那样对泛型类型使用强制转换

如果类型参数是无界的,则用其边界或对象替换泛型类型中的所有类型参数。因此,生成的字节码仅包含普通类、接口和方法。

这里有更多关于所有泛型限制的信息。

所以ButterKnife代码看起来像这样:

  public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2)
  {
    return paramObject;
  }

因此,对于您的问题:

问:但是异常并不是永远不会被捕获,它会在调用方法时被抛出。为什么?

答:嗯,它甚至不在字节码中。

问:还有,这到底是怎么工作的?方法如何知道要转换成什么?

A: 没有。至少不像你想的那样。在实践中,它将抛出ClassCastException而不是您观察到的非法状态异常或断言错误。您甚至可以使用ButterKnife示例应用程序尝试,并将已知的TextView绑定到复选框:

@Bind(R.id.title) CheckBox title;

问:那么图书馆是如何工作的呢?

答:好吧,IllegalStateException只是从未调用过,而且您有ClassCastException。为什么会这样,我不太确定。但是,当ButterKnife生成代码时,这可能是为了防止编译错误。

例如:

public interface Some {
}

public static void weWantSome(Some d) {
}

public static void test() {
    String o = "test";
    weWantSome((Some)o); //<-- compile error
    weWantSome(Main.<Some>cast(o)); //<-- runtime error
} 

这就是为什么在前面的示例中,代码会编译但不会运行。

太叔航
2023-03-14

由于类型擦除,泛型类型仅在编译时检查。这样做是因为在Java5中没有办法在运行时引入泛型,而不会破坏向后兼容性并强制重新编译所有已经存在的库。

长历史短,当您定义“泛型”类或方法时,实际代码将编译为<code>对象</code>而不是绑定方法的类型。所有类型检查都在编译时完成。

因此,您的方法代码实际上并没有在<code>return)分配给<code>对象

 类似资料:
  • 我在我的Java程序中写了这个函数: 这就是我所说的: 它是有效的,但我觉得我应该能够省略第一个参数,并从返回类型(结果被分配到的类型)推断出它。这可能吗?如果是,语法是什么?

  • 问题内容: 背景 我曾经写过这种方法: 应该这样称呼它: 这很好用(尽管我在研究当前容易出错的问题时在这里的答案中已经看到)。 目前的情况 无论如何,现在我正在编写以下代码(在扩展javax.servlet.jsp.tagext.TagSupport的类中): 目的是可以这样称呼: 我的评估方法中的代码显然不起作用。的第二个参数应该是Class对象。这导致我: 我的问题 如何获得通用(返回)类型的

  • 我试图创建一个Java方法,它接受一个对象类型和它应该转换成的数据类型。 例如,如果我应该能够返回一个值1作为Int或双根据需要。我使用类传递数据类型作为参数。 问题:如何使方法泛型以接受基于输入参数的返回类型? 下面的代码只是一个示例,它可能在语法上不正确,用于解释我的问题。

  • 我想让一个函数返回一个保证实现两个接口的对象。编译时不一定知道确切的对象。我的代码看起来像: 在尝试编译时,我遇到以下错误: 你好世界java:13:错误:不兼容的类型:C无法转换为T 返回新的C() ^ 其中T是一个类型变量: T扩展了方法f(布尔值) HelloWorld中声明的a,B。java:14:错误:不兼容的类型:D无法转换为T 返回新的D() ^ 其中T是一个类型变量: T扩展了方法

  • 对于一堆带有泛型的包装类,我的继承结构遇到了一些麻烦。这基本上是结构: 这将与当前代码一起编译和工作,但是,这似乎很危险。如果调用方像这样使用这个方法:,它将很好地编译,但是如果findMiddle尝试返回SubBWrapper,则在运行时会有一个ClassCastException。我以为行得通却行不通的是: 所以我的问题基本上是,有没有正确的方法来编写编译、运行并遵循最佳实践的方法findMi

  • Java中是否有一种方法可以通过一个方法的声明返回不同的类型? 我希望此方法返回一个对象,并在函数调用时将其转换为正确的类型。这就是我的想法,但它不是这样工作的。我是否需要某种通用返回类型来执行此操作?解决这个问题的最佳方法是什么?