Java Challengers#1:JVM中的方法重载

Java Challengers#1:JVM中的方法重载


祝大家有美好的一天。


我们已经启动了“ Java开发人员”课程的下一个线程,但是我们仍然希望与您分享一些材料。


欢迎阅读Java Challengers文章系列! 本系列文章重点介绍Java编程功能。 他们的发展是您成为高素质Java程序员的途径。


掌握本系列文章中讨论的技术需要花费一些精力,但是它们在您作为Java开发人员的日常经验中会大有帮助。 当您知道如何正确地应用基本Java编程技术时,避免错误会更容易;而当您确切了解Java代码中发生了什么时,则更容易跟踪错误。


您准备好开始掌握Java编程的基本概念了吗? 然后,让我们从第一个难题开始!


加宽装箱变量


术语“方法重载”

关于过载,开发人员倾向于认为我们正在谈论重新启动系统,但事实并非如此。 在编程中, 方法重载意味着使用相同的方法名称和不同的参数。

什么是方法重载?


方法重载是一种编程技术,它允许同一类中的开发人员对具有不同参数的方法使用相同的名称。 在这种情况下,我们说该方法是重载的。


清单1显示了具有不同参数的方法,这些参数的数量,类型和顺序各不相同。


清单1.重载方法的三个选项。


//   public class Calculator { void calculate(int number1, int number2) { } void calculate(int number1, int number2, int number3) { } } //   public class Calculator { void calculate(int number1, int number2) { } void calculate(double number1, double number2) { } } //   public class Calculator { void calculate(double number1, int number2) { } void calculate(int number1, double number2) { } } 

方法重载和原始类型


在清单1中,您看到了原始类型intdouble 。 让我们讨论一下,回顾一下Java中的原始类型。


表1. Java中的原始类型


型式射程预设值尺码文字实例
布尔值对还是错错误的1位真假
字节-128 ... 12708位1,-90,-128
烧焦Unicode字符或0到65536\ u000016位'a','\ u0031','\ 201','\ n',4
短的-32,768 ... 32,767016位1,3,720,22,000
整型-2 147 483 648 ... 2 147 483 647032位-2,-1、0、1、9
-9,223,372,036,854,775,808至9,223,372,036,854,775,807064位-4000L,-900L,10L,700L
飘浮3.40282347 x 1038,1.40239846 x 10-450.032位1.67e200f,-1.57e-207f,.9f,10.4F
双倍1.7976931348623157 x 10308,4.9406564584124654 x 10-3240.064位1.e700d,-123457e,37e1d

为什么要使用方法重载?


使用重载使您的代码更整洁,更易于阅读,还有助于避免程序错误。


与清单1相反,请想象一个程序,其中将有许多名称类似于calculate1calculate2calculate3 ...的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"; } } 

好啊 您已经研究了代码。 结论是什么?


  1. 贝菲
  2. bfce
  3. efce
  4. 交流电

文章结尾给出了正确的答案。


现在发生了什么? JVM如何编译重载方法


为了了解清单2中发生的情况,您需要了解有关JVM如何编译重载方法的一些知识。


首先,JVM是相当懒惰的:它总是会尽最小的努力来执行一个方法。 因此,当您考虑JVM如何处理重载时,请记住编译器的三个重要功能:


  1. 加宽
  2. 包装(自动装箱和拆箱)
  3. 可变长度参数(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不能为LongFloat ,也不能为Double 。 没有继承。 这些类型( IntegerLong IntegerFloatDouble )中的每一个都是NumberObject


如有疑问,请记住包装号可以扩展为NumberObject 。 (关于包装器,还有很多可以说的,但让我们留给另一篇文章。)


代码文字


当我们不指定文字数字的类型时,JVM将为我们计算类型。 如果我们直接在代码中使用数字1 ,则JVM会将其创建为int 。 如果我们尝试直接将1传递给接受short的方法,则它将无法编译。


例如:


 class Calculator { public static void main(String... args) { //      // ,   char, short, byte,  JVM    int calculate(1); } void calculate(short number) {} } 

当使用数字1.0时,将应用相同的规则。 尽管它可能是float ,但JVM会将其视为double


 class Calculator { public static void main(String... args) { //      // ,   float,  JVM    double calculate(1.0); } void calculate(float number) {} } 

另一个常见的错误是假设Double或任何其他包装对于获得double的方法更好。


事实是,JVM花费了更少的精力将Double包装器扩展为一个Object而不是将其解压缩为原始的double类型。


总而言之,当直接在Java代码中使用时, 1将为int1.0将为double 。 扩展是最简单的执行方法,然后进行打包或解压缩,最后一个操作将始终是可变长度的方法。


像一个奇怪的事实。 您知道char类型接受数字吗?


 char anyChar = 127; // ,  ,    

您需要记住的过载


对于需要相同方法名称和不同参数的情况,重载是一项非常强大的技术。 这是一种有用的技术,因为使用正确的名称可使代码更易于阅读。 您可以简单地重载它,而不必复制方法名称并为代码添加混乱。


这样可以使代码保持整洁和易于阅读,还减少了重复方法破坏系统一部分的风险。


注意事项:重载该方法时,JVM将尽力而为。


这是最懒惰的执行路径的顺序:


  • 首先是扩大。
  • 第二个是拳击
  • 三,变长参数(varargs)

要考虑的事情:直接声明数字时会遇到困难: 1将是int1.0将是double


还要记住,您可以使用语法1F1f来明确声明这些类型,对于float1D1d来针对double


这总结了JVM在方法重载中的作用。 重要的是要了解JVM本质上是惰性的,并且将始终遵循最懒惰的路径。


答案


清单2的答案是选项3。efce。


了解有关Java中方法重载的更多信息



绝对初学者的类和对象的介绍,包括有关方法和方法重载的小部分。



了解有关Java是强类型语言的重要性的更多信息,并了解Java基本类型。



了解方法重载的局限性和劣势,以及如何使用自定义类型和参数对象解决它们。

Source: https://habr.com/ru/post/zh-CN428307/


All Articles