【问题标题】:Does it matter if function returns T or object if T can not be inferred from context?如果无法从上下文中推断出 T,函数返回 T 或对象是否重要?
【发布时间】:2020-11-17 22:17:26
【问题描述】:

我在gson找到了如下源码:

public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException
{
    JsonReader jsonReader = newJsonReader(json);
    T object = (T) fromJson(jsonReader, typeOfT);
    assertFullConsumption(object, jsonReader);
    return object;
}

fromJson 函数声明返回 Object 还是返回 T 是否重要?至少据我所知,如果 T 不能通过函数参数推断出来,它就完全充当对象。 那么为什么源码使用T而不是Object呢?

【问题讨论】:

  • 这很重要。它们提供 T 以便可以推断类型。 Foo foo = gson.fromJson(reader, type); 如果是 Object,您将不得不自己投射。所以为了方便就这么写了。当然,他们的演员阵容仍然未经检查,因此该方法基本上假设调用者正在分配正确的类型。如果不是,那么他们将得到一个类转换异常。
  • @Michael,他们可以添加哪些检查?
  • 这是谷歌的代码。如果有,他们会这样做;)这是类型擦除的结果,并且就编译器而言,返回 T 和参数 Type 是不相关的事实。它们之间的唯一关系是上下文关系。没有什么可以阻止我打电话给String s = gson.fromJson(reader, TypeOfInteger),这注定会失败
  • @Michael,谢谢。或许你可以看看 xehpuk 例子,试着理解为什么 result2 赋值不会抛出异常?

标签: java object generics wildcard


【解决方案1】:

这不会返回Object,而是从上下文推断出的类型,或者——如果不可能——通过传递带有type witness的类型参数:YourClass.&lt;String&gt;fromJson()

请注意,这不会神奇地起作用。如果内部调用返回的对象在运行时与T 不兼容,则(外部返回值的)赋值将抛出ClassCastException

例子:

public class MyClass {
    public static void main(String args[]) {
        String result1 = MyClass.test(); // works as expected
        Object result2 = MyClass.<Integer>test(); // works "surprisingly"
        int result3 = MyClass.test(); // cannot be cast to java.lang.Integer
    }
    
    static <T> T test() {
        try {
            return (T) "Hello World";
        } catch (ClassCastException e) {
            throw new Error(); // never reached
        }
    }
}

【讨论】:

  • @Michael 你是绝对正确的。希望现在好多了。
  • 谢谢。三件小事: 1.当说如果内部调用返回的对象在运行时与T不兼容,T是谁?在您的示例中是谁充当结果 1、结果 2、结果 3? 2.谁能说为什么result2赋值不抛出异常? 3.return语句中是否需要强制转换(T)
  • @Eitanos30 T 是从作业的左侧推断出来的,是的。它不受参数约束,因此约束来自返回类型。所以在上面的例子中T首先是String,然后是Object,然后是Integer。 result2 不会抛出异常,因为 Object 变量可以存储任何东西——也就是说,Object 并不特殊,它只是最广泛/最不特定的类型。所以result2 有效,因为Object a = new Integer(1) 是有效的。但是Integer a = new Object()显然不是
  • “显式提供T”的东西被称为类型见证(以防万一它可以帮助您通过谷歌搜索了解更多信息)。它们在某些情况下很有用,主要是在编译器无法推断出正确类型时使用它们。在这种情况下,不,它们似乎没用。
  • 在这个例子中它完全没有影响。你必须记住的是泛型只是编译时的。它们被删除。因此,只要它可以编译,泛型就会很高兴。在这种情况下,泛型认为我们有一个整数分配给一个对象,所以他们很满意。我们人类知道有一个 String 强制转换为 - 看起来是 - 一个整数(实际上,它被强制转换为 Object,即没有发生任何事情 - 强制转换在字节码中被删除),但强制转换是我们推翻的方式编译器所以没关系。在运行时,我们只剩下一个 String 被分配给一个 Object 变量
猜你喜欢
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
  • 2017-05-20
  • 2017-03-29
  • 2019-11-29
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多