首先来看一段代码
我们把这段代码称为代码①,接下来我们再来看另外一段代码
我们把这段代码称为代码②。
在代码①当中,定义了一个方法,这个方法声明的返回值类型是double,而实际通过return关键字返回的却是一个int型的值,但并没有引起编译错误。而在代码②当中,情况正好相反,方法声明的返回值类型是int,方法内部的return关键字实际返回了一个double类型的值,在这种情况下,编译器却报出了语法错误。
对比一下这两种情况,很多初学Java的小伙伴搞不清:为什么同样是方法声明的返回值类型与实际返回值的类型不相同,但一种情况不报错,而另一种情况却无法通过编译检查呢?要讲清楚这个问题,我们必须从为什么方法要声明返回值类型说起。
在Java语言中,要求程序员在定义一个方法的时候,必须在方法名称的前面声明这个方法的返回值类型。为什么要求你这么做呢?简单来说,就是编译器强制程序员必须公开一个信息,那就是:这个方法在运行之后会返回一个什么类型的值,只有这样,调用方法的人才知道要用一个什么类型的变量接收方法的运算结果。除此之外,编译器还要求:主调方法在接收返回值的过程中,必须以声明的返回值类型作为标准,而不是看实际返回值的类型。就拿代码①来说,声明的返回值类型是double,实际返回值是int,我们在程序中用变量接收方法返回值的时候,必须用double型变量接收,即便是它实际返回的只是一个int型数据,也不能用int型变量接收返回值,否则就会出现编译错误
接下来,我们再来观察方法的定义过程。在代码①当中,方法所声明的返回值类型是double型,而实际在方法的内部返回的是一个int型的值,二者之间类型并不一致,但并没有出现语法错误,这又是怎么回事呢?这是因为,Java语言在做语法检查的时候,要求声明的返回值类型与实际返回值的类型只要达到“兼容”就可以了,并不需要完全相同。代码①当中的方法就做到了二者兼容,而代码②当中的方法没有做到,所以报错了。
举个容易理解的例子:你小的时候,你爸爸要出门,告诉你在他回来的时候会带回一个直径50厘米的大蛋糕,那么你肯定会按照他的承诺,准备一个直径50厘米的大盘子用来装这个大蛋糕。但你爸爸回来的时候,实际带回来的却是一个直径只有10厘米的小蛋糕,这时虽然你很伤心也很失望,但是,你所准备的大盘子足够能放得下你爸爸带回来的小蛋糕,不会出什么问题。代码①当中定义的方法就属于这种情况,声明返回一个占8字节的double型数据,但实际返回一个占4字节的int型数据。
但是反过来,你爸爸出门的时候告诉你他回来的时候会带回一个10厘米的小蛋糕,你也按照他的承诺准备了一个直径10厘米的小盘子,打算用来装这个小蛋糕。但当你爸爸回来的时候,带回的却是一个直径达50厘米的大蛋糕!这时,你又惊喜又激动,但是却无法解决一个问题:你所准备的小盘子根本无法盛放这么大的蛋糕!这就好比是代码②中所展现的情况,声明返回一个只占4字节的int型数据,而方法运行实际返回一个8字节的double型数据,让那些准备用int型变量接收方法返回值的人感到“措手不及”。当然,这只是一句玩笑,如果真实出现了返回值不兼容的情况,编译器根本不允许这样的代码通过编译,所以也更谈不上运行代码了。
接下来再 具体说说哪些情况下,方法声明的返回值类型与实际的返回值类型能够达到兼容。我们可以分以下几种情况讨论:
一、我们知道,Java基础数据类型有8种,其中整数类型有4中,分别是long、int、short和byte。这4种整数类型有着明显的“向下兼容”的特性,也就是说,声明返回值为较大的数据类型,实际返回较小的数据类型,是肯定没有问题。比如,声明返回long类型,但实际返回int型数据是没有问题的。同样,两种浮点数double和float也能够做到“向下兼容”。
二、我们还知道,表示字符的char类型,在实际存储数据的过程中,存储的也是一个占两个字节的”整数”,这个”整数”其实就是字符的编码值。那么char类型的数据能否与Java的4种整型相兼容呢?实际情况是:long和int能够完全兼容char,而short和byte不行。反过来,char类型不能兼容任何一种整型数据。说的直白一点,就是如果我们把方法的返回值声明为char类型,方法实际返回的是long、int、short和byte型的数据都不行。
三、浮点数能够兼容任意整型和字符型。也就是说,double和float可以兼容long、int、short、byte以及char。但反过来,整型和字符型无法兼容任意一种浮点型。这里可能有写小伙伴会有一点疑惑:4个字节的float真的能兼容8个字节的long吗?从语法的角度是没有问题的,我们把一个long类型的数据赋值给一个float类型的变量不需要做强制类型转换,编译器也不会报错。但实际存储过程中,有可能会导致数据损失精度。注意,这里所说的是“有可能”损失精度,而不是”一定”损失精度。
四、boolean类型在8种基础数据类型中是”特立独行”的,它不与任何其他基础数据类型相兼容,如果一个方法声明返回值类型为boolean,那么这个方法只能返回boolean类型的数据。
以上我们谈到的方法返回值都是基础数据类型,如果是引用数据类型,情况又如何呢?这种情况下,遵循“父兼容子”的原则。也就是说,如果返回值被声明为父类,而实际返回对象为子类对象,完全可以顺利通过编译器语法检查。同样,如果返回值类型被声明为接口,方法实际返回对象为接口的实现类对象,也没有问题。而反过来,方法声明返回值类型为子类,实际返回值为父类对象是无法通过编译检查的。
希望本文对初学Java的小伙伴理解方法的返回值有所帮助。
如想系统学习Java编程,欢迎观看我在本站的视频课程。
来源:51CTO
作者:穆哥
链接:https://blog.51cto.com/2266836/2480984