JLS。返回式可替代性。这是什么意思?

时间:2014-05-11 14:42:42

标签: java inheritance methods return jls

我正在阅读jls,我面临以下任期:

return-type-substitutable
来自jls的

片段

  

返回类型为R1的方法声明d1   return-type-substitutable为另一个返回类型为R2的方法d2   如果以下任何一种情况属实:

     

如果R1无效,则R2无效。

     

如果R1是基本类型,则R2与R1相同。

     

如果R1是引用类型,则以下之一为真:

     

- 适应d2(§8.4.4)类型参数的R1是。的子类型   R2。

     

- 可以通过未经检查的转换将R1转换为R2的子类型   (§5.1.9)。

     

- d1与d2(§8.4.2)没有相同的签名,R1 = | R2 |。

前两点很明显。

你可以澄清

吗?
  

- R1,适用于d2(§8.4.4)的类型参数,是R2的子类型。

     

- 可以通过未经检查的转换(第5.1.9节)将R1转换为R2的子类型。

     

- d1与d2(§8.4.2)没有相同的签名,R1 = | R2 |。

感谢

P.S。 为Luiggi Mendoza

interface Foo {
        List<String> foo(String arg1, String arg2);
}

class Bar implements Foo {
    @Override
    public ArrayList<String> foo(String arg1, String arg2) {
        //implementation...
        return  null;
    }

    public String foo(String arg1, String arg2, String arg3) {
        //implementation...
        return  null;
    }
}

它正在起作用。

我的问题的原因 - 我想从jls中理解以下短语:

  

如果返回类型为R1的方法声明d1覆盖或隐藏   声明另一个方法d2,返回类型为R2,则d1必须为   d2的return-type-substitutable(第8.4.5节),或编译时错误   发生

规则:

If R1 is a reference type then **one of the following** is true:
...
--d1 does not have the same signature as d2 (§8.4.2), and R1 = |R2|.
...

代码:

interface Foo {
        List<String> foo(String arg1, String arg2);
}

class Bar implements Foo {
    @Override
    public List<String> anotherName(String arg1, String arg2,Object obj) {
           return  null;
    }

这是编译错误。

R1 == R2(List<String > == List<String>

D1!= D2

我在哪里违反了规则?

2 个答案:

答案 0 :(得分:2)

我们有这个界面

interface Foo {
    List<String> foo(String arg1, String arg2);
}

实施它的课程

class Bar implements Foo {
    @Override
    public List<String> foo(String arg1, String arg2) {
        //implementation...
    }
}

我们有:

  • Bar#food1
  • List<String>在d1中将类型返回为R1。
  • Foo#food2
  • List<String>在d2中将类型返回为R2。
  

R1,适用于d2(§8.4.4)的类型参数,是R2的子类型。

这意味着R1可以是R2的子类型,这意味着R1应该通过IS-A测试。所以,我们可以做到以下几点:

class Bar implements Foo {
    @Override
    public ArrayList<String> foo(String arg1, String arg2) {
        //implementation...
    }
}
  

可以通过未经检查的转化(§5.1.9)将R1转换为R2的子类型。

这与泛型更相关。这意味着R1应该通过IS-A测试,即使它发出了未经检查的覆盖警告。所以,我们可以做到以下几点:

class Bar implements Foo {
    @Override
    public ArrayList foo(String arg1, String arg2) {
        //implementation...
    }
}
  

d1与d2(§8.4.2)没有相同的签名,而R1 = | R2 |

这意味着重载:

class Bar implements Foo {
    @Override
    public ArrayList<String> foo(String arg1, String arg2) {
        //implementation...
    }

    public ArrayList<String> foo(String arg1, String arg2, String arg3) {
        //implementation...
    }
}

答案 1 :(得分:0)

  

如果返回类型为R1的方法声明d1覆盖或隐藏了另一个返回类型为R2的方法d2的声明,那么对于d2,d1必须是return-type-substitutable(第8.4.5节),或者是编译时错误出现为d2(§8.4.2),R1 = | R2 |。

让我们分一杯羹:

首先,我们需要一个方法声明d2和一个返回类型R2

class SomeClass {
    public List<String> d2() {
        return null;
    }
}

现在,我们定义一个扩展SomeClass的类,定义d1并返回R1

class AnotherClass extends SomeClass {
    //@Override annotation means it is overriding a method in parent class
    //d2 here is d1
    //Object here is R1
    @Override
    public List<String> d2() {
    }
}

这怎么编译?因为d1d2的返回类型可替代,这意味着R1可以将R2替换为返回类型。这也称为covariant return type,并在Java Tutorials. Returning a Value from a Method中介绍。这是由另一条规则支持的:

  

返回类型为R1的方法声明d1是另一个方法d2的return-type-substitutable,如果满足以下任何条件,则返回类型为R2:如果R1是引用类型,则以下之一为真:d1不与d2(§8.4.2)具有相同的签名,R1 = | R2 |。

这意味着所有这些方法都有效覆盖SomeClass#d2

class AnotherClass extends SomeClass {
    //ArrayList implements List
    @Override
    public ArrayList<String> d2() {
        return null;
    }
}

class AnotherClass extends SomeClass {
    //raw List can be casted to `List<String>` by unchecked conversion
    //means you don't need a explicit cast to convert `List` to `List<String>`
    //due to type erasure
    @Override
    public List d2() {
        return null;
    }
}

class AnotherClass extends SomeClass {
    //combination of both examples above
    @Override
    public ArrayList d2() {
        return null;
    }
}

但这些都是无效的实现:

class AnotherClass extends SomeClass {
    //the signature is not the same
    @Override
    public List<String> d1() {
        return null;
    }
}

class AnotherClass extends SomeClass {
    //Set is not a subtype of List
    @Override
    public Set<String> d2() {
        return null;
    }
}

class AnotherClass extends SomeClass {
    //Collection is not a subtype of List
    @Override
    public Collection<String> d2() {
        return null;
    }
}