[轉載] Java Challengers#1:JVM中的方法過載
歡迎來到新的Java Challengers部落格!本部落格致力於挑戰Java程式設計中的概念。掌握它們,你將成為一名技術嫻熟的Java程式設計師。
本部落格中的技術需要付出一些努力才能掌握,但它們會對你作為Java開發人員的日常體驗產生重大影響。當你知道如何正確應用核心Java程式設計技術時,避免錯誤會更容易,並且當你確切知道Java程式碼中發生的情況時,跟蹤錯誤會更容易。
你準備好開始掌握Java程式設計中的核心概念了嗎?然後讓我們開始我們的第一個Java挑戰!
術語:方法過載
由於過載,開發人員傾向於認為這種技術會使系統過載,但事實並非如此。在程式設計中,方法過載意味著使用相同的方法名和不同的引數。
什麼是方法過載?
方法過載是一種程式設計技術,允許開發人員在同一個類中多次使用相同的方法名,但具有不同的引數。在這種情況下,我們說該方法是過載的。清單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中的原始型別
TypeRangeDefaultSizeExample literals boolean true or false false 1 bit true, false byte -128 .. 127 0 8 bits 1, -90, 128 char Unicode character or 0 to 65,536 \u0000 16 bits 'a', '\u0031', '\201', '\n', 4 short -32,768 .. 32,767 0 16 bits 1, 3, 720, 22,000 int -2,147,483,648 .. 2,147,483,647 0 32 bits -2, -1, 0, 1, 9 long -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 0 64 bits -4000L, -900L, 10L, 700L float 3.40282347 x 1038, 1.40239846 x 10-45 0.0 32 bits 1.67e200f, -1.57e-207f, .9f, 10.4F double 1.7976931348623157 x 10308, 4.9406564584124654 x 10-324 0.0 64 bits 1.e700d, -123457e, 37e1d
**為什麼我們要使用方法過載?** 過載使你的程式碼更清晰,更易於閱讀,它還可以幫助你避免程式中的錯誤。 與清單1相比,想象一個程式,其中有多個calculate()方法,其名稱為calculate1 calculate2, calculate3. 。。不好,對嗎?過載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挑戰嗎?我們來看看吧! 首先仔細檢視以下程式碼。 清單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.befe 2.bfce 3.efce 4.aecf
剛剛發生了什麼?JVM如何編譯過載方法
為了理解清單2中發生的事情,你需要了解有關JVM如何編譯過載方法的一些資訊。 首先,JVM是智慧懶惰的:它總是儘可能少地執行一個方法。因此,當你考慮JVM如何處理過載時,請記住三種重要的編譯器技術:
1.寬化型別轉換 2.box(自動裝箱和拆箱) 3.可變引數
如果你從未遇到過這三種技術,那麼一些示例應該有助於使它們清晰明瞭。請注意,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();
這是一個可變引數的例子; 請注意,可變引數它始終是最後執行的:
execute(int… numbers){}
什麼是可變引數?
用於可變數量引數,可變引數基本上是由三個點指定的值陣列(…)我們可以傳遞許多int我們想要給這個方法的數字。 例如:
execute(1,3,4,6,7,8,8,6,4,6,88...); // We could continue…
可變引數非常方便,因為值可以直接傳遞給方法。如果我們使用陣列,我們必須使用值例項化陣列。
寬化:一個實際的例子
當我們將數字1直接傳遞給executeAction方法時,JVM會自動將其視為一個int。這就是為什麼這個數字不適用於該executeAction(short var)方法。 同樣,如果我們傳遞數字1.0,JVM會自動將該數字識別為double。 當然,數字1.0也可以是 float,但型別是預先定義的。這就是executeAction(double var)清單2中呼叫該方法的原因。 當我們使用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-- 是一個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:
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。寬化是最懶的執行路徑,接下來是裝箱或拆箱,最後的操作將始終是可變引數。 作為一個奇怪的事實,你知道這個char型別接受數字嗎?
char anyChar = 127; // Yes, this is strange but it compiles
關於過載要記住什麼
對於需要使用不同引數的相同方法名稱的情況,過載是一種非常強大的技術。這是一種有用的技術,因為在程式碼中使用正確的名稱會對可讀性產生重大影響。你可以簡單地過載它,而不是複製方法併為你的程式碼新增混亂。這樣做可以使程式碼保持清潔,易於閱讀,並降低了重複方法破壞系統某些部分的風險。 需要記住的是:當過載方法時,JVM將盡可能少地工作; 這是最懶惰的執行路徑的順序:
l 首先是寬化 l 第二是裝箱 l 第三是可變引數
需要注意的是:直接宣告一個數字會產生棘手的情況:1將是int,而1.0將是 double。 還要記住,你可以使用語法顯式宣告這些型別,1F或1f用於float或者1D或1d用於 double。 這就是我們的第一個Java挑戰,介紹了JVM在方法過載中的作用。重要的是要意識到JVM本質上是懶惰的,並且總是遵循最懶的執行路徑。
答案
清單2中的Java Challenger的答案是:選項3. efce。
有關Java中方法過載的更多資訊
· Java 101: Classes and objects in Java: A true beginner’s introduction to classes and objects, including short sections on methods and method overloading. · Java 101: Elementary Java language features: Learn more about why it matters that Java is a strongly typed language and get a full introduction to primitive types in Java. · Too many parameters in Java methods, Part 4: Explore the limitations and disadvantages of method overloading, and how they may be remedied by integrating custom types and parameter objects. 點選英文原文連結 更多文章歡迎訪問: http://www.apexyun.com 公眾號:銀河系1號 聯絡郵箱:public@space-explore.com (未經同意,請勿轉載)
相關文章
- 【Java】方法的過載Java
- java -方法- 過載Java
- java方法過載Java
- Java方法03:方法的過載Java
- Java - 14 方法過載Java
- Java 方法過載概念Java
- 常用的Java類方法【轉載】Java
- 方法的過載
- Java中方法重寫與方法過載Java
- [轉載] Java中如何在方法中return返回多個值Java
- Java中的過載和重寫Java
- JVM類載入過程JVM
- java程式設計——從jvm角度看懂類初始化、方法重寫、過載Java程式設計JVM
- 《java程式設計基礎》方法的過載Java程式設計
- 轉載方法
- Java jvm 類載入 反射JavaJVM反射
- [轉載] .NET 中可以有類似 JVM 的幻像引用嗎?JVM
- 從jvm角度看懂類初始化、方法過載、重寫。JVM
- 從jvm角度看懂類初始化、方法重寫、過載。JVM
- JAVA-大白話探索JVM-類載入過程(二)JavaJVM
- Java-JVM-類載入器JavaJVM
- [轉載] Java7中增加的新特性Java
- Python 方法過載Python
- 方法過載原理
- PHP中的過載PHP
- python中的過載Python
- Java 底層機制(JVM/堆/棧/方法區/GC/類載入)JavaJVMGC
- Mybatis的Mapper中的方法為什麼不能過載?MyBatisAPP
- Java入門第12天 (方法過載 ,方法的引數傳遞)Java
- 基本方法的呼叫與過載
- JVM(六):探究類載入過程-下JVM
- java類的載入過程Java
- Java基礎03 構造器與方法過載Java
- JVM核心之JVM執行和類載入全過程JVM
- Java中的過載和覆蓋的細微差別 - rajivprabJava
- JVM中的類載入器子系統JVM
- 過載運算子的常見方法
- 【JVM進階之路】十三:類載入過程JVM