jvm7 jvm8
欢迎来到新的Java Challengers博客! 该博客致力于处理Java编程中的挑战性概念。 掌握它们,您将逐步成为一名高技能的Java程序员。
本博客中的技术需要花费一些精力来掌握,但是它们对于您作为Java开发人员的日常体验将产生巨大的影响。 当您知道如何正确应用核心Java编程技术时,避免bug会更容易;而当您确切了解Java代码中发生的事情时,跟踪bug会容易得多。
您准备好开始掌握Java编程中的核心概念了吗? 然后,让我们开始第一个Java Challenger!
术语:方法重载
由于有术语重载 ,开发人员倾向于认为此技术会使系统重载,但这不是事实。 在编程中, 方法重载意味着使用相同的方法名称和不同的参数。
什么是方法重载?
方法重载是一种编程技术,它允许开发人员在相同的类中使用相同的方法名称多次,但使用不同的参数。 在这种情况下,我们说该方法是重载的。 清单1显示了一个方法,其参数在数量,类型和顺序上有所不同。
清单1.三种类型的方法重载
Number of parameters:
public class Calculator {
void calculate(int number1, int number2) { }
void calculate(int number1, int number2, int number3) { }
}
Type of parameters:
public class Calculator {
void calculate(int number1, int number2) { }
void calculate(double number1, double number2) { }
}
Order of parameters:
public class Calculator {
void calculate(double number1, int number2) { }
void calculate(int number1, double number2) { }
}
方法重载和原始类型
在清单1中,您将看到原始类型int
和double
。 我们将进一步处理这些类型和其他类型,因此请花一点时间来回顾Java中的原始类型。
表1. Java中的原始类型
类型 | 范围 | 默认 | 尺寸 | 示例文字 |
boolean | 对或错 | 假 | 1位 | 真假 |
byte | -128 .. 127 | 0 | 8位 | 1,-90,128 |
char | Unicode字符或0到65,536 | \ u0000 | 16位 | 'a','\ u0031','\ 201','\ n',4 |
short | -32,768 .. 32,767 | 0 | 16位 | 1,3,720,22,000 |
int | -2,147,483,648 .. 2,147,483,647 | 0 | 32位 | -2,-1、0、1、9 |
long | -9,223,372,036,854,775,808至9,223,372,036,854,775,807 | 0 | 64位 | -4000L,-900L,10L,700L |
float | 3.40282347 x 1038,1.40239846 x 10-45 | 0.0 | 32位 | 1.67e200f,-1.57e-207f,.9f,10.4F |
double | 1.7976931348623157 x 10308,4.9406564584124654 x 10-324 | 0.0 | 64位 | 1.e700d,-123457e,37e1d |
为什么要使用方法重载?
重载使您的代码更整洁,更易于阅读,还可以帮助您避免程序中的错误。
与清单1相比,想象一下一个程序,其中有多个名称为calculate
1, 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;
}
}
接受方法重载挑战!
您准备好迎接第一个Java Challenger吗? 让我们找出答案!
首先仔细查看以下代码。
清单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如何处理重载时,请记住以下三种重要的编译器技术:
- 加宽
- 装箱(自动装箱和拆箱)
- 瓦拉格斯
如果您从未遇到过这三种技术,那么一些示例应该可以帮助您将它们弄清楚。 请注意,JVM 按照给定的顺序执行它们。
这是扩大范围的示例:
int primitiveIntNumber = 5;
double primitiveDoubleNumber = primitiveIntNumber ;
扩展时,这是原始类型的顺序:
这是自动装箱的示例:
int primitiveIntNumber = 7;
Integer wrapperIntegerNumber = primitiveIntNumber;
请注意在编译此代码后在后台发生的情况:
Integer wrapperIntegerNumber = Integer.valueOf(primitiveIntNumber);
这是拆箱的示例:
Integer wrapperIntegerNumber = 7;
int primitiveIntNumber= wrapperIntegerNumber;
这是编译此代码后在后台发生的事情:
int primitiveIntNumber = wrapperIntegerNumber.intValue();
这是可变参数的一个例子; 请注意, varargs
始终是最后执行的变量:
execute(int… numbers){}
什么是可变参数?
用于可变参数的varargs
基本上是由三个点(…)指定的值的数组。我们可以将想要的许多int
数传递给此方法。
例如:
execute(1,3,4,6,7,8,8,6,4,6,88...); // We could continue…
Varargs非常方便,因为可以将值直接传递给方法。 如果使用数组,则必须使用值实例化数组。
加宽:一个实际的例子
当我们将数字1直接传递给executeAction
方法时,JVM会自动将其视为int
。 这就是为什么数字不属于executeAction(short var)
方法的原因。
同样,如果我们传递数字1.0,则JVM会自动将该数字识别为double
。
当然,数字1.0也可以是float
,但是类型是预定义的。 这就是清单2中调用executeAction(double var)
方法的原因。
当我们使用Double
包装器类型时,有两种可能性:包装器编号可以拆箱为原始类型,或者可以扩展为Object
。 (请记住,Java中的每个类都扩展了Object
类。)在这种情况下,JVM选择将Double
类型扩展为Object
因为它比拆箱所需的工作量少,正如我之前解释的那样。
我们传递的最后一个数字是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
, Float
和Double--is
一个Number
和一个Object
。
如有疑问,请记住包装号可以扩展为Number
或Object
。 (关于包装器,还有很多要探索的地方,但是我将其留在另一篇文章中。)
JVM中的硬编码数字类型
当我们不为数字指定类型时,JVM会为我们完成。 如果我们直接在代码中使用数字1,则JVM会将其创建为int
。 如果您尝试将1直接传递给正在接收short
的方法,则它将无法编译。
例如:
class Calculator {
public static void main(String… args) {
// This method invocation will not compile
// Yes, 1 could be char, short, byte but the JVM creates it as an int
calculate(1);
}
void calculate(short number) {}
}
当使用数字1.0时,将应用相同的规则。 尽管可能是float
,但JVM会将这个数字视为double
float
数:
class Calculator {
public static void main(String… args) {
// This method invocation will not compile
// Yes, 1 could be float but the JVM creates it as double
calculate(1.0);
}
void calculate(float number) {}
}
另一个常见的错误是认为Double
或任何其他包装器类型将更适合于接收double
的方法。 事实上,它需要为JVM的扩大省力Double
包装到一个Object
,而不是它拆箱到的double
原始类型。
综上所述,当直接在Java代码中使用时,1将为int
而1.0将为double
。 扩展是执行最懒惰的路径,装箱或拆箱紧随其后,最后一个操作将始终是varargs
。
奇怪的是,您知道char
类型接受数字吗?
char anyChar = 127; // Yes, this is strange but it compiles
关于重载的注意事项
对于需要相同方法名称和不同参数的方案,重载是一项非常强大的技术。 这是一种有用的技术,因为在代码中使用正确的名称对可读性有很大的影响 。 您可以简单地重载它,而不是复制方法并给代码增加混乱。 这样做可以使您的代码保持整洁和易于阅读,并减少了重复方法破坏系统某些部分的风险。
注意事项 :重载方法时,JVM将尽力而为。 这是最懒惰的执行路径的顺序:
- 首先是扩大
- 第二是拳击
- 第三是瓦拉格斯
需要注意的是 :直接声明数字会产生棘手的情况:1将是int
而1.0将是double
。
还要记住,您可以使用1F或1f的float
语法或1D或1d的double
语法明确声明这些类型。
结束我们的第一个Java Challenger,介绍了JVM在方法重载中的作用。 重要的是要认识到JVM本质上是惰性的,并且将始终遵循最懒惰的执行路径。
答案键
清单2中Java Challenger的答案是:选项3. efce。
有关Java中方法重载的更多信息
- Java 101:Java中的类和对象 :真正的初学者对类和对象的介绍,包括有关方法和方法重载的简短部分。
- Java 101:基本Java语言功能 :了解有关Java是强类型语言的重要性的更多信息,并全面介绍Java中的原始类型。
- Java方法中的参数太多,第4部分 :探索方法重载的局限性和缺点,以及如何通过集成自定义类型和参数对象来补救它们。
这个故事“ JVM中的方法重载”最初是由JavaWorld发布的 。
翻译自: https://www.infoworld.com/article/3268983/java-challengers-1-method-overloading-in-the-jvm.html
jvm7 jvm8