摘要:Java知識點精選之類、接口、枚舉30問,算是比較基礎的,希望大家一起學習進步。
整理了一些JAVA語言的在類、接口、枚舉等方面的知識點以及大家常遇到的問題。希望能幫助到大家。
Q: 各修飾符所代表的可見性?
public: 可被所有使用
protect: 只能被自己和子類使用,或者同一個包路徑
private: 只能自己使用,兒子都不行
不加修飾符即default權限: 包訪問權限,和他在同一包內的類都可以訪問他,包外的則都不能訪問
Q: 外部類可以用private或者protect修飾嗎?
A: 不能,只能用public或者包訪問權限。 內部類可以。
解釋以下final的作用
Q: final 成員?
A: 如果是基本類型,則指值不能被改變。 如果是對象,指對象的引用不可改變,但是引用處的內容可改變。
Q: final 參數?
A: 參數不可變,只能讀不能修改,同上
Q: final方法
A: 方法不能被子類重寫。
Q: final類
A: 該類不能被繼承。
Q:final局部變量可以作爲非final的參數傳入嗎?會編譯報錯嗎?
public static void main(String[] args){
final A a = new A();
changeA(a);
}
public void changeA(A a) {
// change A...
}
A:可以作爲非final的參數傳入,不會編譯報錯。
Q: 重載和重寫的區別?
A:重載是方法名相同,參數不同。
重寫是方法參數等都一致的情況下重寫父類的方法。
Q: 如果子類重載了父類中的方法, 那麼子類中還能調用父類中的同名方法嗎?
A: 可以(C++中不可以調用父類中的同名重載方法)。
Q: 怎樣能避免子類在重寫父類的方法,不小心弄成了重載?
(即你想重寫父類的f(int), 卻不小心寫成了f(int,int),導致調用f(int)時還是調用了父類的f ,怎麼能避免這種失誤?)
A: 加個@Override關鍵字即可,原文解釋:
Q:父類的成員變量能被重寫/覆蓋嘛?
class A{
public String name = "A";
}
class B extends A{
public String name = "B";
}
public static void main{
A a = new B();
System.out.println(a.name);
}
A:輸出A。
注意成員變量不具有多態性,因此你定義的是A,賦值的是B, 那麼輸出的依舊是A裏的成員。
如果是被重寫的方法的話,那會用B裏的方法。
Q:內部類是啥,內部類能訪問外部類的成員嗎?
A:
內部類概念:
class A {
class B{
...
}
}
B就是A的內部類,B能訪問A的所有成員
Q: A中有1個內部類C, A的子類B中也有1個內部類C, B中的C會覆蓋A中的C嗎?
A: 不會, 因爲使用時是通過B.C或者A.C去調用的,存在命名空間的關係。
Q:可以在內部類中定義靜態成員嗎?
class A {
class B{
static int b;
...
}
}
A:不可以。 除非在class B前面加static變爲靜態類
Q: 匿名類是啥, 匿名類能訪問外面的變量或者對象嗎?
A: 匿名類概念:
return new A(構造參數){
{構造器內容}
類定義
}
匿名類如果要用外面的對象, 外面的對象必須要定義爲final。
Q: 嵌套類是啥,能訪問外部類的成員嗎?
A:
class A {
static int sa;
int a;
static class B{}
}
B只能訪問A中的靜態成員sa, 而不能訪問a。
§ 接口
類是單繼承,接口可以多繼承
Q: 接口中如果要定義成員變量,那成員的默認修飾符是什麼?
A: public static final
Q: 接口中各方法的默認修飾符是什麼?
A: public abstract
Q: 接口中可以定義實現具體方法嘛?
A:java8以上版本可以。
引入了default關鍵字,在接口中用default關鍵字修飾接口,就可以在接口中去實現這個接口了。
§ 枚舉
Q: enum可以被繼承嗎?
像下面這樣:
enum A extend B{
...
}
A: 不可以。enum標識符本身被編譯器處理過,自身就繼承自Enum類,而java不支持多重繼承。但支持實現接口
Q: switch(enum)時需要加default嗎?
A: 可以不需要。
Q: Enum基類裏實現了values()方法嗎?
A: 沒有實現, values方法是編譯器加的。因此從List<Enum>裏取出的對象,是不能調用values()的。
Q:enum裏的枚舉的默認修飾符默認是?
A:static final
§ 靜態分派和動態分派
Q: 下面輸出什麼,屬於什麼分派?
void test() {
Father father = new Son(); //靜態分派
print(father);
}
void print(Father father) {
System.out.println("this is father");
}
void print(Son son) {
System.out.println("this is son");
}
A:輸出this is father。 屬於靜態分派。
靜態分派概念: 編譯器就能確定調用哪個方法。
這裏2個print屬於重載方法,通過輸入參數的定義類型即立刻確定調用哪個
靜態分派取決於靜態類型
靜態類型概念: 編譯期寫在java文件裏能馬上看到的類型
例如 A a = Factory.create(args);
那麼左邊的A就是靜態類型, 而右邊的類型取決於運行期,是不確定的。
Q: 上一題的進階:
public class Overload {
private static void sayHello(char arg){
System.out.println("hello char");
}
private static void sayHello(Object arg){
System.out.println("hello Object");
}
private static void sayHello(int arg){
System.out.println("hello int");
}
private static void sayHello(long arg){
System.out.println("hello long");
}
// 測試代碼
public static void main(String[] args) {
sayHello('a');
}
}
輸出什麼?
A:輸出 hello char
因爲‘a’是一個char類型數據(即靜態類型是char),所以會選擇參數類型爲char的重載方法。
若註釋掉sayHello(char arg)方法,那麼會輸出 hello int
因爲‘a’除了可代表字符串,還可代表數字97。因此當沒有最合適的sayHello(char arg)方式進行重載時,會選擇第二合適(第二優先級)的方法重載,即sayHello(int arg)
總結:當沒有最合適的方法進行重載時,會選優先級第二高的的方法進行重載,如此類推。
優先級順序爲:char>int>long>float>double>Character>Serializable>Object>…
其中…爲變長參數,將其視爲一個數組元素。變長參數的重載優先級最低。
因爲 char 轉型到 byte 或 short 的過程是不安全的,所以不會選擇參數類型爲byte 或 short的方法進行重載,故優先級列表裏也沒有。
Q: 下面輸出什麼,屬於什麼分派:
void test() {
Father father = new Son();
father.name();
}
class Son extends Father {
void name(){
System.out.println("son");
}
}
class Father {
void name(){
System.out.println("father");
}
}
A:輸出son,屬於動態分派。運行的時候根據所指向的具體對象才確定調用哪個方法
Q:靜態分派屬於單分派還是多分派?動態分派屬於單分派還是多分派?
A:靜態分派是多分派。動態分派是單分派。
多分派概念: 分派時即要考慮調用者的類型,也要考慮參數類型。
而單分派只考慮調用者的類型。
動態分派原理:
Q:類方法在class文件中是什麼樣的? 是符號引用還是直接引用?
A:class文件中, 所定義的方法 都只是符號引用,即只是個符號,知道方法名字, 但是不知道方法的實際指令運行地址
符號引用如下,不過我這展示的時class_info即類的符號引用, 實際上還會有method_info即方法的引用:
然後方法在class文件中時這樣存放的, 先是一個method_count數量,接着再存儲方法。
此時是不知道方法的指令地址的。 除非從符號引用轉爲直接引用。
Q:什麼時候方法的符號引用會轉爲實際方法區中的直接引用?
A:類加載的解析階段會把滿足「編譯期可知,運行期不可變」的方法的符號引用替換爲指向方法區的直接引用,不會延遲到運行時再去完成。
- 構造
- 私有
- 靜態
- final修飾
上面這4類方法在類加載時都會被識別出來,並轉成 指向方法區的直接引用(即能知道了指令地址了,而不是字節碼的符號)
Q:動態分派(即多態), 虛擬機裏是怎麼確定調用哪個方法的?
如下, 他怎麼確定調用的是Son實現的do, 還是father實現的do?
int a = 1;
Father f = new Son()
f.do(a);
A:首先,通過靜態分派, 他知道一定選用的是f(int a) 這個方法,但是他不知道選用哪個類的do(int a)方法。
而你執行f.do(a)時, 操作數棧上會存放一個對象引用
那麼執行f方法的虛擬機指令就會通過這個對象引用,找到他的實際類型的class
他會在這個實際類中查找是否有實現這個方法,具體看class文件中有沒有這個方法的定義
如果沒有找到,他就去父類找,父類的關係class文件中就可以知道
如果父類沒有,就接着往上找,直到找到實現了的。
本文分享自華爲雲社區《Java知識點問題精選之類、接口、枚舉》,原文作者:breakDraw 。