1. Java面向對象的知識結構
-
1.1 Java語法以及關鍵字、如接口與類、內部類,final/finally/finalize, throw/throws,域訪問符權限等;
-
1.2 Java面向對象思想以及體系,例如設計思想。
2. 經典面試題
2.1 Java 有沒有 goto? 如果有,一般用在什么地方?如果沒有,如何跳出當前的多重嵌套循環?
goto是Java中的保留字,在目前Java版本中沒有使用。
在Java中跳出多重循環的的方法有三種:
1. break + 標簽,在外層循環前加上一個標簽lable,
然后在最里層循環使用 break lable.
public static void main(String[] args) {
label: //標記
for (int i = 0 ; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if(j == 5) { //滿中一定條件跳到某個標記
break label;
}
}
}
}
2. 通過異常捕獲
public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if (j == 5) {// 滿足一定條件拋異常
throw new RuntimeException("test exception for j = 5");
}
}
}
} catch (RuntimeException e) { //循環外層捕獲異常
e.printStackTrace();
}
}
3. 通過標置變量
public static void main(String[] args) {
boolean flag = false; //初始化標置變量
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if (j == 5) { //滿足一定條件進行設置標置變量
flag = true;
}
if (flag) { //內層循環判斷標置變量
break;
}
}
if (flag) {//外層循環判斷標置變量
break;
}
}
}
2.2 抽象類(abstract class)和接口(interface)有什么異同?
-
相同點
1. 不能直接實例化。如果要實例化,抽象變量必須實現所有抽象方法,接口變量必須實現接口未實現的方法。 2. 都可以有實現方法(Java1.8之前不能有實現方法) 3. 都可以不需要實現類或者繼承者去實現所有方法(Java8 以前的接口,Java8 及以后的接口中可以包括默認方法,不需要實現者實現)。
-
不同點
1. 抽象類和接口所反映的設計理念不同,抽象類表示的是對象/類的抽象,接口表示的是行為的抽象。 2. 抽象類不可以多重繼承,接口可以多重繼承。即一個類只能繼續一個抽象類,卻可以繼承多個接口。 3. 抽象類中的方法可以用 public protected 和 default abstract 修飾符,不能用 private、static、synchronize、native 修飾;變量可以在子類中重新定義,也可以重新賦值; 接口的方法默認修飾符是 public abstract, Java8 開始出現靜態方法,多加 static 關鍵字;變量默認是 public static final 型,且必須給其初值,在實現類中也不能重新定義,也不能改變其值。 4. 抽象類可以有構造器,接口沒有構造器。
2.3 Java 創建對象的方式有哪些?
1. 使用 new關鍵字
2. 反射創建,使用java.lang.Class 類的newInstance 方法
這種方式會調用無參的構造函數來創建對象,有兩種實現方式。
//方式一,使用全路徑包名
User user = (User)Class.forName("com.imooc.interview.demo.User").newInstance();
//方法二,使用class類
User user = User.class.newInstance();
反射,使用 java.lang.reflect.Constructor 類的 newInstance 方法。
Constructor<User> constructor = User.class.getConstructor();
User user = constructor.newInstance();
使用 clone 方法。
public class User implements Cloneable {
/** 構造方法 */
public User(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
private Integer age;
// 重寫(Overriding)Object的clone方法
@Override
protected User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
public static void main(String[] args) throws Exception {
User person = new User(new Integer(200));
User clone = person.clone();
System.out.println("person == clone, result = " + (person == clone)); // false,拷貝都是生成新對象
System.out.println("person.age == clone.age, result = " + (person.getAge() == clone.getAge())); // true,淺拷貝的成員變量引用仍然指向原對象的變量引用
}
}
淺拷貝和深拷貝
-
淺拷貝:被復制對象的所有變量都含有與原來的對象相同的值,對拷貝后對象的引用仍然指向原來的對象。
-
深拷貝:不僅要復制對象的所有非引用成員變量值,還要為引用類型的成員變量創建新的實例,並且初始化為形式參數實例值。
3. 使用反序列化。 為了序列化 / 反序列化一個對象,需要該類實現空接口 Serializable 序列化時首先創建一個輸出流對象 oos, 使用 oos 的 writeObject () 方法將 p 對象寫入 oos 對象中去。使用反序列化創建對象時,首先創建一個輸入流對象 ois,使用輸入流對象 ois 的 readObject () 方法將序列化存入的對象讀出,重新創建一個對象。 序列化是深拷貝。