Java Challengers#1:JVM中的方法重载
祝大家有美好的一天。
我们已经启动了“ Java开发人员”课程的下一个线程,但是我们仍然希望与您分享一些材料。
欢迎阅读Java Challengers文章系列! 本系列文章重点介绍Java编程功能。 他们的发展是您成为高素质Java程序员的途径。
掌握本系列文章中讨论的技术需要花费一些精力,但是它们在您作为Java开发人员的日常经验中会大有帮助。 当您知道如何正确地应用基本Java编程技术时,避免错误会更容易;而当您确切了解Java代码中发生了什么时,则更容易跟踪错误。
您准备好开始掌握Java编程的基本概念了吗? 然后,让我们从第一个难题开始!

术语“方法重载”
关于过载,开发人员倾向于认为我们正在谈论重新启动系统,但事实并非如此。 在编程中, 方法重载意味着使用相同的方法名称和不同的参数。
什么是方法重载?
方法重载是一种编程技术,它允许同一类中的开发人员对具有不同参数的方法使用相同的名称。 在这种情况下,我们说该方法是重载的。
清单1显示了具有不同参数的方法,这些参数的数量,类型和顺序各不相同。
清单1.重载方法的三个选项。
方法重载和原始类型
在清单1中,您看到了原始类型int
和double
。 让我们讨论一下,回顾一下Java中的原始类型。
表1. Java中的原始类型
型式 | 射程 | 预设值 | 尺码 | 文字实例 |
---|
布尔值 | 对还是错 | 错误的 | 1位 | 真假 |
字节 | -128 ... 127 | 0 | 8位 | 1,-90,-128 |
烧焦 | Unicode字符或0到65536 | \ u0000 | 16位 | 'a','\ u0031','\ 201','\ n',4 |
短的 | -32,768 ... 32,767 | 0 | 16位 | 1,3,720,22,000 |
整型 | -2 147 483 648 ... 2 147 483 647 | 0 | 32位 | -2,-1、0、1、9 |
长 | -9,223,372,036,854,775,808至9,223,372,036,854,775,807 | 0 | 64位 | -4000L,-900L,10L,700L |
飘浮 | 3.40282347 x 1038,1.40239846 x 10-45 | 0.0 | 32位 | 1.67e200f,-1.57e-207f,.9f,10.4F |
双倍 | 1.7976931348623157 x 10308,4.9406564584124654 x 10-324 | 0.0 | 64位 | 1.e700d,-123457e,37e1d |
为什么要使用方法重载?
使用重载使您的代码更整洁,更易于阅读,还有助于避免程序错误。
与清单1相反,请想象一个程序,其中将有许多名称类似于calculate1
, calculate2
, calculate3
...的calculate()
方法,对吗? 重载calculate()
方法使您可以使用相同的名称,并且仅更改所需的参数。 查找重载的方法也很容易,因为它们在代码中分组。
什么过载都不是
请记住,更改变量名称并非重载。 以下代码无法编译:
public class Calculator { void calculate(int firstNumber, int secondNumber){} void calculate(int secondNumber, int thirdNumber){} }
您也不能通过更改方法签名中的返回值来重载该方法。 此代码也不会编译:
public class Calculator { double calculate(int number1, int number2){return 0.0;} long calculate(int number1, int number2){return 0;} }
构造函数重载
您可以采用与方法相同的方式重载构造函数:
public class Calculator { private int number1; private int number2; public Calculator(int number1) { this.number1 = number1; } public Calculator(int number1, int number2) { this.number1 = number1; this.number2 = number2; } }
解决方法重载的问题
您准备好进行第一次测试了吗? 让我们找出答案!
首先仔细检查以下代码。
清单2.方法重载的挑战
public class AdvancedOverloadingChallenge3 { static String x = ""; public static void main(String... doYourBest) { executeAction(1); executeAction(1.0); executeAction(Double.valueOf("5")); executeAction(1L); System.out.println(x); } static void executeAction(int ... var) {x += "a"; } static void executeAction(Integer var) {x += "b"; } static void executeAction(Object var) {x += "c"; } static void executeAction(short var) {x += "d"; } static void executeAction(float var) {x += "e"; } static void executeAction(double var) {x += "f"; } }
好啊 您已经研究了代码。 结论是什么?
- 贝菲
- bfce
- efce
- 交流电
文章结尾给出了正确的答案。
现在发生了什么? JVM如何编译重载方法
为了了解清单2中发生的情况,您需要了解有关JVM如何编译重载方法的一些知识。
首先,JVM是相当懒惰的:它总是会尽最小的努力来执行一个方法。 因此,当您考虑JVM如何处理重载时,请记住编译器的三个重要功能:
- 加宽
- 包装(自动装箱和拆箱)
- 可变长度参数(varargs)
如果您从未遇到过这些技术,那么一些示例应该可以帮助您理解它们。 请注意,JVM按列出的顺序运行它们。
这是一个示例扩展:
int primitiveIntNumber = 5; double primitiveDoubleNumber = primitiveIntNumber ;
这是基本类型的扩展顺序:

( 译者的注意-在JLS中,原语的扩展描述有很大的变化,例如long可以扩展为float或double。 )
自动包装示例:
int primitiveIntNumber = 7; Integer wrapperIntegerNumber = primitiveIntNumber;
注意编译代码时幕后发生的事情:
Integer wrapperIntegerNumber = Integer.valueOf(primitiveIntNumber);
这是一个拆箱示例:
Integer wrapperIntegerNumber = 7; int primitiveIntNumber= wrapperIntegerNumber;
这是编译此代码时幕后发生的事情:
int primitiveIntNumber = wrapperIntegerNumber.intValue();
这是带有可变长度参数的方法的示例。 请注意,可变长度方法始终是最后执行的方法。
execute(int... numbers){}
什么是变长参数?
可变长度参数只是由三个点(...)给出的值的数组。 我们可以将尽可能多的int
数传递给此方法。
例如:
execute(1,3,4,6,7,8,8,6,4,6,88...);
可变长度参数(varargs)非常方便,因为可以将值直接传递给方法。 如果使用数组,则必须使用值创建一个数组实例。
扩展:案例研究
当我们将数字1直接传递给executeAction()
方法时,JVM会自动将其解释为int
。 这就是为什么此数字不会传递给executeAction(short var)
方法的原因。
同样,如果传递数字1.0
JVM将自动识别为双精度。
当然,数字1.0
也可以是float
,但是此类文字的类型是预定义的。 因此,在清单2中,执行executeAction(double var)
方法。
当我们使用Double
包装器时,有两个选择:可以将数字解包为原始类型,也可以将其扩展为Object
。 (请记住,Java中的每个类都扩展了Object
类。)在这种情况下,JVM选择Object
中类型Double
的扩展,因为与解压缩相比,它需要的工作更少。
我们传递的最后一个是1L
由于我们指定了类型,所以它是long
。
常见的过载错误
到现在为止,您可能已经知道,方法重载可能会使您感到困惑,因此让我们看一下您可能会遇到的一些问题。
使用包装器自动装箱
Java是一种强类型的编程语言,当我们将自动包装与包装一起使用时,需要考虑一些事项。 首先,以下代码无法编译:
int primitiveIntNumber = 7; Double wrapperNumber = primitiveIntNumber;
自动打包仅适用于double
类型,因为在编译代码时,它等同于以下形式:
Double number = Double.valueOf(primitiveIntNumber);
此代码将编译。 第一个int
将被扩展为double
,然后打包为Double
。 但是使用自动包装时,没有类型扩展,并且Double.valueof
构造函数期望double
而不是int
。 在这种情况下,如果进行显式类型转换,则自动打包将起作用,例如:
Double wrapperNumber = (double) primitiveIntNumber;
请记住, Integer
不能为Long
和Float
,也不能为Double
。 没有继承。 这些类型( Integer
, Long
Integer
, Float
和Double
)中的每一个都是Number
和Object
。
如有疑问,请记住包装号可以扩展为Number
或Object
。 (关于包装器,还有很多可以说的,但让我们留给另一篇文章。)
代码文字
当我们不指定文字数字的类型时,JVM将为我们计算类型。 如果我们直接在代码中使用数字1
,则JVM会将其创建为int
。 如果我们尝试直接将1
传递给接受short
的方法,则它将无法编译。
例如:
class Calculator { public static void main(String... args) {
当使用数字1.0
时,将应用相同的规则。 尽管它可能是float
,但JVM会将其视为double
。
class Calculator { public static void main(String... args) {
另一个常见的错误是假设Double
或任何其他包装对于获得double
的方法更好。
事实是,JVM花费了更少的精力将Double
包装器扩展为一个Object
而不是将其解压缩为原始的double
类型。
总而言之,当直接在Java代码中使用时, 1
将为int
而1.0
将为double
。 扩展是最简单的执行方法,然后进行打包或解压缩,最后一个操作将始终是可变长度的方法。
像一个奇怪的事实。 您知道char
类型接受数字吗?
char anyChar = 127;
您需要记住的过载
对于需要相同方法名称和不同参数的情况,重载是一项非常强大的技术。 这是一种有用的技术,因为使用正确的名称可使代码更易于阅读。 您可以简单地重载它,而不必复制方法名称并为代码添加混乱。
这样可以使代码保持整洁和易于阅读,还减少了重复方法破坏系统一部分的风险。
注意事项:重载该方法时,JVM将尽力而为。
这是最懒惰的执行路径的顺序:
- 首先是扩大。
- 第二个是拳击
- 三,变长参数(varargs)
要考虑的事情:直接声明数字时会遇到困难: 1
将是int
而1.0
将是double
。
还要记住,您可以使用语法1F
或1f
来明确声明这些类型,对于float
和1D
或1d
来针对double
。
这总结了JVM在方法重载中的作用。 重要的是要了解JVM本质上是惰性的,并且将始终遵循最懒惰的路径。
答案
清单2的答案是选项3。efce。
了解有关Java中方法重载的更多信息
绝对初学者的类和对象的介绍,包括有关方法和方法重载的小部分。
了解有关Java是强类型语言的重要性的更多信息,并了解Java基本类型。
了解方法重载的局限性和劣势,以及如何使用自定义类型和参数对象解决它们。