Java面試複習之Java深入解析四
- main方法:main方法是程式執行的入口。可以被過載,但必須要有虛擬機器能自動呼叫的main方法才能編譯通過。main方法也可以被其他方法呼叫。main同樣也可以被繼承和隱藏。
- 方法的過載:過載是根據引數列表的不同來區分的。引數列表的不同可以區分為個數、型別、順序等。不能根據返回值型別和方法的異常列表來區分。 void m(List ist){} void m(List<String> list){} 以上兩個方法也不能構成過載,因為引數化型別在經過編譯後會被擦除。這兩個方法擦除後的引數列表時相同的,都是List型別,會出現方法重定義。 在呼叫過載方法的時候,會最先呼叫最“明確”的方法。如實參為byte型別時的呼叫,形參中沒有byte型別的時候,會依次找short、int、long、float、double。實參為char型別時的呼叫,會依次找char、int、long、float、double。找到為止。引數為引用型別時也一樣。先找形參為該類的引用的方法。如果沒有,再找可以賦值的父類的引用的方法。 自動拆裝箱和可變引數型別的過載:優先選可變引數型別
public class Maintest { public static void main(String[] args) { Maintest maintest=new Maintest(); int i=10; maintest.m(i); } public void m(Integer integer) { System.out.println("Integer\t\t"+integer.intValue()); } public void m(long l) { System.out.println("long\t\t"+l); } }
執行結果為:
long 10
當呼叫方法有有兩個或兩個以上的引數,且多個方法都符合呼叫條件,但是無法從中選擇出一個最明確的方法來呼叫時。就會產生編譯錯誤。
public class Maintest { public static void main(String[] args) { char ch='a'; int i=1; long l=2; float f=3; //m(ch,l); } public static void m(char ch,float f) { System.out.println("char-----float 方法"); } public static void m(int i,long l) { System.out.println("int------long 方法"); } }
這樣的方法呼叫產生了編譯錯誤。因為兩個方法都不是最明確的,但都可以呼叫。因此不明確該呼叫哪一個。註釋兩個方法中的任意一個,編譯即可通過。 過載方法的呼叫是根據引用的靜態型別來決定的(識別符號左邊的型別),這一點與對方法重寫的呼叫不同(多型,執行時決定)。
public class Maintest {
public static void main(String[] args) {
Object o=new String();
m(o);
}
public static void m(String s)
{
System.out.println("String");
}
public static void m(Object o)
{
System.out.println("Object");
}
}
執行結果為Object。是根據引用的靜態型別來決定的。 3.方法的重寫: 重寫條件:
- 都要是例項方法,不能是靜態。
- 子類方法的返回值型別是父類方法的返回值型別的可替換型別。
- 不能比父類丟擲更多的異常。
- 子類方法的訪問許可權不能低於父類方法的訪問許可權。
可以在子類中使用非泛型化的方法重寫父類中泛型化的方法,但是不能再子類中使用泛型化的方法重寫父類中非泛型化的方法。父類定義為void m(List<String> list)時,子類可以重寫為void m(List list)。但是反過來不行。要重寫父類的方法,在子類中首先要可以訪問到。父類中私有的方法不能重寫,可以在子類中定義與父類中私有方法同名同參的方法,但這不是重寫,是重新定義了一個方法。 4.隱藏: 方法的隱藏:條件和方法的重寫條件一樣,只不過兩個方法都是靜態的。 成員變數的隱藏:從父類中繼承來了(不是private修飾的)且變數名稱相同就是隱藏。 對於隱藏的變數和方法來說,要呼叫時通過類名點變數名來呼叫。 父類:
public class Super {
public String s="Super 的成員變數";
public void m(){
System.out.println("Super 的m方法");
}
public static void method(){
System.out.println("Super的靜態方法");
}
}
子類:
public class Maintest extends Super{
public String s="Maintest 的成員變數";
@Override public void m() {
System.out.println("Maintest 的方法");
}
public static void method()
{
System.out.println("Maintese的靜態方法");
}
public static void main(String[] args) {
Super s=new Maintest();
System.out.println(s.s);
s.m();
s.method();
}
}
執行結果:
Super 的成員變數
Maintest 的方法
Super的靜態方法
對於隱藏,是根據引用的靜態型別來決定呼叫相關類的成員。
5.構造器:構造器在建立物件之後呼叫,對物件進行初始化工作。所以不是構造器建立物件,而是new關鍵字建立了物件。構造器可以顯示呼叫,用this(呼叫當前類的構造)或者super(呼叫父類構造)。但是this或super必須出現在構造器中的第一行。所以this和super不能同時出現在一個構造方法中。如果類內沒有構造方法時,系通或生成無參構造。這個無參構造會呼叫父類的構造,一直遞迴,直到呼叫到Object類。 父類:
public class Super {
public Super()
{
System.out.println("This is Super's constructor");
}
}
子類,沒有寫構造方法。系統自動生成無參構造。但是如果有有參構造,系統不會自動生成無參構造。所以如果寫了有參構造,最好順便新增上無參構造。
public class Maintest extends Super{
public static void main(String[] args) {
Maintest maintest=new Maintest();
}
}
執行結果:
This is Super's constructor
6.成員變數的初始值: 基本資料型別:數字型別的均為0,char為空字元,boolean為false。 引用資料型別:陣列和物件的引用均為null。 在方法中宣告的區域性變數沒有預設值,使用前一定要賦初始值。但是陣列有值,值為0。 例項變數初始化方式:
- 在宣告處初始化。
- 在例項化塊中初始化。
- 在構造方法中初始化。
靜態變數的初始化方式:
- 在宣告處初始化。
- 在靜態初始化塊中初始化
五種初始化的先後順序:先靜態,後例項,最後剩下構造器。靜態和例項中方法和變數的順序是以定義順序為初始化順序。
public class Maintest {
public static int i=Super.init2();
public Maintest()
{
System.out.println("構造器初始化");
}
static {
System.out.println("靜態塊的初始化");
}
{
System.out.println("例項塊初始化");
}
public int j=Super.init1();
public static void main(String[] args) {
Maintest maintest=new Maintest();
}
}
不管怎樣調整調整以上五段初始化程式碼的順序,構造器都是在最後,靜態都是在例項之前。JVM虛擬機器試圖呼叫該類的main方法,發現類沒有被載入。因此會先載入類,為類的靜態變數分配空間,並設定預設值,隨後初始化執行。靜態初始化部分只會在載入類的時候進行執行。例項初始化部分會在建立物件的時候執行。 執行結果:
靜態變數初始化
靜態塊的初始化
例項塊初始化
例項變數初始化
構造器初始化
當存在繼承關係時,先呼叫父類的靜態,後呼叫子類。當存在引用時。 向前引用:在定義變數之前就引用了該變數。變數的值為預設值。訪問時要加this。 在構造器中呼叫了例項方法,該例項方法用到了例項成員變數。由於構造器是對例項變數的初始化,因此這種情況也被視為向前引用。
public class Maintest {
private int area=this.side*4;
private int side=5;
public static void main(String[] args) {
Maintest maintest=new Maintest();
System.out.println("side:"+maintest.side+"\tside:"+ maintest.area);
}
}
由於是在同一個類,公有可以訪問私有。成員變數數字基本型別中數字型別的預設值為0。
side:5 side:0
如果有final修飾的變量出現,則該變數即為常量。在編譯成位元組碼的時候值就已經定了,且不可更改。所以在程式執行的時候,根本看不見final修飾的變數的預設值。就算是向前引用也看不到。