Java 中的协变返回类型和原语

问题描述 投票:0回答:2

在OCP书中我读到协方差有这样的规则:

给定一个继承的返回类型 A 和一个重写的返回类型 B,您可以将 B 的实例分配给 A 的引用变量而不进行强制转换吗?如果是这样,那么它们是协变的。此规则适用于基本类型和对象类型。

如果规则适用于基本类型,并且我可以将 int 值分配给 long 变量而无需强制转换(因此它们是协变的),那么为什么代码无法编译(协变返回类型)?我觉得这句话或者我的理解有问题?

class Class1
{
    long method()
    {
        return 1L;
    }
}
class Class2 extends Class1
{
    public static void main(String[] args)
    {
        int B = 1;
        long A = B; // no cast
    }

//    @Override
//    int method() { return 1; } // does not compile // 'method()' in 'B' clashes with 'method()' in 'A'; attempting to use incompatible return type
}
java types casting covariance
2个回答
0
投票

您的问题与类型转换无关,而是与继承有关。您试图重写方法并将返回类型更改为不兼容的类型。这是不可能的,但如果是的话,那就非常危险了。方法签名(包括返回类型)是一种不允许您破坏的合同。 您的调用类取决于该协定,因此如果可以覆盖原始类型,您最终可能会遇到一个简单的问题:您的调用类不知道实际的返回类型。但通常要使用多态性,因此在编译时,您必须依赖于所使用的引用类型的约定。请参阅以下简单示例(由于最后一行而无法编译):

public class Class1 {

    long method() {
        return 3; //int, but cast before the value is returned
    }
}

class Class2 extends Class1 {
    public static void main(String[] args) {
        int B = 1;
        long A = B; // no cast
    }

    int method2() { //renamed to get this compiled
        return 3;
    }
}

class SimpleClass {
    public static void main(String[] args) {
       int i = 1;
       long j = 2;
       long l = i + j; //this compiles because int is implicitly cast to long
       //int k = i + j; // This doesn't compile because long can't be cast
       //implicitly to int
    }
}

class Class3 {

    void whatIsTheResult() {
        Class1 class1 = new Class1();
        Class1 class12 = new Class2(); //No problem due to  polymorphism, both   
        //objects have the reference type Class1,
    // but actually, class12 is of type Class2
        Class2 class2 = new Class2(); 

        long a = class1.method() + class2.method2(); //By contract, method 
        //returns a long, method2 returns an int
        int b = class1.method() + class2.method2(); // Same contract, but long 
        //can't be 'cast down' to int, so doesn't compile
    }
}

0
投票

那么这是否意味着在重写的方法中不允许使用更窄的类或原语?它可以是 int/long、Integer/Long 或任何其他类(如 Super/Sub)吗?只是简单的规则,即不允许更窄的返回类型,但要位于上面示例中的 Class1 中??

© www.soinside.com 2019 - 2024. All rights reserved.