[金三銀四面試季]Java面向對象高頻面試題

      網友投稿 745 2022-05-30

      金三銀四正是跳槽漲薪的好時節,波哥給大家整理了很多面試高頻的問題,助力大家找到更好的工作哦,點點關注,感謝支持。

      面向對象面試題

      1.談談你對面向對象思想的理解?

      面向過程編程(POP):是一種以過程為中心的編程思想

      面向對象編程(OOP):相對于面向過程來講的,面向對象方法,把相關的數據和方法組織為一個整體來看待,從更高的層次來進行系統建模,更貼近事物的自然運行模式

      2. 談談你對面向對象的特征的理解

      封裝

      即把對象的屬性和方法包裹起來, 只能通過約定好的接口實現訪問

      封裝是一種信息隱藏技術,在java中通過關鍵字private實現封裝。

      package com.bobo.interview0001.domain; /** * 屬性+方法 */ public class User { // 將age設置為私有屬性 private int age; public String name; /** * 提供給外界設置age屬性的方法 * @param age */ public void setAge(int age){ if(age < 0 || age > 120){ System.out.println("age的設置不合法!!!"); age = 0; } this.age = age; } /** * 提供給外界獲取age屬性的方法 * @return */ public int getAge(){ return age; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      封裝的好處:可以將私有數據和公共數據分離,保護私有數據,提高了程序的安全性!!!

      繼承

      繼承是面向對象的最顯著的一個特征。繼承是從已有的類中派生出新的類,新的類能吸收已有類的數據屬性和行為,并能擴展新的能力。

      為什么要繼承呢:

      反映現實的真實關系

      減少代碼冗余

      對父類的屬性和方法進行擴展和重寫

      繼承中,子類不可以選擇性的繼承父類的東西,而是全部繼承父類的屬性和方法。其中父類又叫超類或基類,子類又叫派生類。父類是子類的一般化,子類是父類的特化(具體化)。java中不支持多繼承,一個類最多只能有一個父類。而在java中多繼承是通過接口實現的。

      public class Person { private String userName; private int age; private String sex; private String address; private String idCard; public void show(){ System.out.println("父類中的方法"); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      public class Doctor extends Person{ @Override public void show() { System.out.println("Doctor ... show"); } }

      1

      2

      3

      4

      5

      6

      public class Student extends Person{ private String ClassNum; private String stuNo; // .... public void learn(){ } @Override public void show() { System.out.println("Student ... show"); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      多態

      Java對象的多種狀態,多態主要是基于繼承和重寫,最終可以實現相同的類型調用相同的方法,結果不相同

      public static void main(String[] args) { // 多態的體現 Person p1 = new Student(); p1.show(); Person p2 = new Doctor(); p2.show(); }

      1

      2

      3

      4

      5

      6

      7

      3.介紹下訪問權限修飾符

      重點注意protected和default,protected相比較default多了一個不同包下面的子類可見

      4. String是基本數據類型嗎?

      Java中的8個基本數據類型:

      byte

      short

      int

      long

      float

      double

      char

      boolean

      String類型顯然不在8個基本數據類型之中,String類型是我們講的引用類型

      5. float f=6.6這樣寫是否正確?

      不正確的,6.6默認是雙精度類型,將double類型賦值給float類型,屬性向下轉型,會造成精度丟失

      public class Demo01 { public static void main(String[] args) { // 小數 默認的是 double類型 雙精度類型 向下轉型 精度丟失 float f2 = 1.1; float f = 6.6F; float f1 = 7.7F; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      6 程序題1

      short s1 = 1; s1 = s1 + 1; // 此處需要強制類型轉換

      1

      2

      有錯嗎? – 有錯

      short s1 = 1; s1 += 1; // s1 = (short) ( s1 + 1 )

      1

      2

      有錯嗎?-- 沒有錯

      7. 程序題2

      以下程序的輸出結果是:

      public static void main(String[] args) { Integer f1=100,f2=100,f3=150,f4=150; System.out.println(f1==f2); System.out.println(f3==f4); }

      1

      2

      3

      4

      5

      輸出結果:true,false

      原因解釋:

      IntegerCache中的定義

      private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; // 創建了一個緩存的數組 長度256 cache = new Integer[(high - low) + 1]; int j = low; // 循環256次 for(int k = 0; k < cache.length; k++) // 一次創建 -128 到 127 對應的Integer對象,并保存到數組中 cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      valueOf(int)中的源碼

      public static Integer valueOf(int i) { // 如果 i 在 -128 到 127之間 if (i >= IntegerCache.low && i <= IntegerCache.high) // 就從緩存的數組中返回之前創建的 Integer對象 return IntegerCache.cache[i + (-IntegerCache.low)]; // 否則創建一個新的Integer對象 return new Integer(i); }

      1

      2

      3

      4

      5

      6

      7

      8

      提醒:越是貌似簡單的面試題,其中的玄機就越多,要求面試者需要相對深厚的功力。

      8. &和&&的區別

      &:按位與

      int a = 5; // 101 int b = 3; // 011 int c = a & b;// 001

      1

      2

      3

      邏輯與:都為true結果才為true,左邊如果為false,右邊表達式還是會運行

      &&:短路與:都為true結果才為true,左邊如果為false,右邊表達式不會運行

      public static void main(String[] args) { int a = 5; // 101 int b = 3; // 011 int c = a & b;// 001 System.out.println("c = " + c); // 邏輯與 & 左右兩邊都為true 那么結果才為true // 左邊為false,結果為false,但是右邊的表達式還是會進行運算 if(a == 0 & a ++ > 0){ System.out.println("------"); } System.out.println("a = " + a); // && 短路與 左邊如果為false,那么整體的結果也為false,而且右邊的表達式不會運算 if(a == 0 && a ++ > 0){ System.out.println("------"); } System.out.println("a = " + a); String name = null; // 短路與在實際使用的時候還是很有使用場景的 if(name != null & !name.equals("")){ } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      9. switch可以使用的數據類型

      JDK5之前:byte,short,int,char

      JDK5之后:Java中引入了枚舉類型,枚舉類型也可以

      JDK7之后:可以使用String,但是long類型一直是不可以的

      10. 用最有效的方法計算2乘以8?

      2 << 3(左移3位,相當于乘以2的3次方)

      11. 構造器是否可以被重寫?

      構造器不能被繼承,因此是不能被重寫的,但是我們可以重載構造器

      12. 是否可以繼承String類?

      String類是final類型,所以不可以被繼承。

      13. 重載和重寫的區別

      方法的重載和重寫都是實現多態的方式, 區別在于前者實現的是編譯時的多態性, 而后者實現的是運行時的多態性。

      重載:在同一個類中,同名的方法如果有不同的參數列表(參數類型,參數個數,順序)視為重載

      package com.bobo.interview0006; public class Demo01 { public static void main(String[] args) { A a = new A(); a.show1(); a.show1(18); a.show1("a",18); a.show1(18,"aaa"); } } class A{ /** * 方法的重載:在同一個類中 方法名稱相同 參數列表不同 */ public void show1(){ } public void show1(String name){ } public void show1(int a){ } public void show1(String name,int a){ } public void show1(int a,String name){ } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      重寫:發生在父子關系類中,子類重寫父類的方法,有相同的返回類型或子類

      class B extends A{ /** * 重寫,子類重寫父類中的方法 */ @Override public void show1() { // super.show1(); System.out.println("show1 --- B"); } /** * 重寫的返回類型必須相同或者是父類返回類型的子類 * @param n * @return */ @Override public Integer fun1(Number n) { return 666; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      14. 抽象類和接口的區別

      接口和抽象類都不能實例化

      抽象類相比于普通類多的限制是可以添加抽象方法

      接口中只能聲明常量和抽象方法且訪問修飾符必須都為public,在JDK8之后可以定義default方法和static方法

      package com.bobo.interview0007; public class Demo01 { public static void main(String[] args) { } } /** * 抽象類 * 不能被實例化 * 可以聲明普通的屬性和方法 * 還可以定義抽象方法 */ abstract class A{ private int a; public int b; public void fun1(){ } public abstract void fun2(); } /** * 接口 * 不能被實例化 * 屬性只能是常量 * 方法只能是抽象方法 * JDK1.8之后可以有 default和static方法 */ interface B{ public final int a = 9; // public abstract 方法默認的類型 可以不添加 public abstract void show1(); /** * default方法 */ public default void fun1(){ } /** * 靜態方法 */ public static void fun2(){ } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      15. 靜態內部類和內部類的區別

      靜態內部類是被聲明為static的內部類,它可以不依賴外部類的實例被實例化,而通常我們的內部類是需要通過外部類的實例才能實例化。

      public class OutterClass { /** * 普通內部類 */ class InnerClass{ public void show(){ System.out.println("InnerClass ..."); } } /** * 靜態內部類 */ static class StaticInnerClass{ public void show(){ System.out.println("StaticInnerClass ..."); } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      測試代碼

      public static void main(String[] args) { // 獲取普通內部類對象 OutterClass.InnerClass innerClass = new OutterClass().new InnerClass(); innerClass.show(); // 獲取靜態內部類對象 OutterClass.StaticInnerClass staticInnerClass = new OutterClass.StaticInnerClass(); staticInnerClass.show(); }

      1

      2

      3

      4

      5

      6

      7

      8

      16. 抽象方法是否可以同時是靜態的本地方法及被synchronized修飾?

      抽象方法所在的類肯定是抽象類,

      不能被static修飾,因為靜態不能被重寫,而抽象方法必須要被子類重寫,所以矛盾。

      不能被native修飾,本地方法是由C代碼實現的,而抽象方法沒有實現,也是矛盾的

      不能被synchronized修飾,同步是和方法的實現的細節有關系的,而抽象方法沒有具體的實現,也是相互矛盾的

      17. 靜態變量和實例變量的區別

      靜態變量:是被static所修飾的變量,也稱為類變量,它是屬性類對象的,不屬于類的任何一個對象。靜態變量是對象間共享的

      實例變量:數據具體的某個對象,必須要先創建對象,然后通過該對象來訪問實例變量,

      18.靜態方法中是否可以訪問普通方法

      肯定不可以,靜態方法是在類加載階段就創建的,而普通方法是屬性對象的,在類加載階段還沒有對象,所以是矛盾的,靜態方法只能訪問靜態成員,普通方法必須要先創建對象,然后通過對象來調用普通方法。

      public class Person { static void show(){ // 靜態方法中不可以調用 普通方法 // speak(); } void speak(){ // 普通方法可以調用靜態方法 show(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      19.如何實現克隆

      package com.dpb.prototype; import java.io.Serializable; import java.util.Date; /** * 原型類:被克隆的類型 * @author dengp * */ public class User implements Cloneable,Serializable{ private String name; private Date birth; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } /** * 實現克隆的方法 */ public Object clone() throws CloneNotSupportedException{ return super.clone(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      深度克隆

      package com.dpb.prototype; import java.io.Serializable; import java.util.Date; /** * 原型類:被克隆的類型 * 深度克隆測試 * @author dengp * */ public class User2 implements Cloneable,Serializable{ private String name; private Date birth; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } /** * 實現克隆的方法 * 深度克隆(deep clone) */ public Object clone() throws CloneNotSupportedException{ Object object = super.clone(); // 實現深度克隆(deep clone) User2 user = (User2)object; user.birth = (Date) this.birth.clone(); return object; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      [金三銀四面試季]Java面向對象高頻面試題

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      序列化和反序列化

      public static void main(String[] args) throws CloneNotSupportedException, Exception { Date date = new Date(1231231231231l); User user = new User(); user.setName("波波烤鴨"); user.setAge(18); user.setBirth(date); System.out.println("-----原型對象的屬性------"); System.out.println(user); System.out.println(user.getName()); System.out.println(user.getBirth()); //使用序列化和反序列化實現深復制 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(user); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); //克隆好的對象! User user1 = (User) ois.readObject(); // 修改原型對象的值 date.setTime(221321321321321l); System.out.println(user.getBirth()); System.out.println("------克隆對象的屬性-------"); System.out.println(user1); System.out.println(user1.getName()); System.out.println(user1.getBirth()); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      20.介紹下final關鍵字

      21.程序運行題

      以下程序的輸出結果是:

      public class Hello { /** * Class 對象 * Object 普通對象 * Java的類加載機制要比較清楚 * @param args */ public static void main(String[] args) { A ab = new B(); // 普通對象是根據 Class對象來創建的 1a2b ab = new B(); // 因為 B的類對象已經被加載了,這時靜態變量初始化就不會執行了 2b // 1a2b2b } } class A { static { System.out.print("1"); } public A() { System.out.print("2"); } } class B extends A{ static { System.out.print("a"); } public B() { super(); System.out.print("b"); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      輸出結果為:

      1a2b2b

      1

      程序執行的順序:

      創建對象時構造器的調用順序是:先初始化靜態成員,然后調用父類構造器,再初始化非靜態成員,最后調用自身構造器。

      22.數據類型之間的轉換

      字符串–》基本數據類型

      基本數據類型–》字符串

      public static void main(String[] args) { String s1 = "99"; // 轉換為int類型 // 1.通過int對應的包裝類 Integer 中提供的 parseXXX(String) 方法 int i = Integer.parseInt(s1); // 2.通過int 對應的包裝來 Integer 中的 valueOf(String) 方法 Integer i2 = Integer.valueOf(s1); // 將一個基本數據類型轉換為 String類型 int age = 18; String s2 = age + ""; String s3 = String.valueOf(age); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      23.return和finally的執行順序問題

      分析如下的代碼程序,給出輸出結果,并給出原因

      public class Demo02 { public static void main(String[] args) { Demo02 demo02 = new Demo02(); System.out.println(demo02.getName("bobo")); } public String getName(String name){ String res = ""; try { res = name; return res; }finally { res = "波波烤鴨"; } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      輸出的結果是:bobo

      原因:通過指令分析我們可以發現在 return 代碼執行的時候會將局部變量保存在 棧幀的頂部,然后在finally中修改的還是原來的棧幀位置的局部變量,最終返回的信息還是棧幀頂部的變量,所以finally代碼塊在return關鍵字之后會執行,但是不會改變棧幀頂部的信息。

      還有一種情況需要注意,如果finally和try塊中都有return關鍵字會怎么樣呢?

      public class Demo02 { public static void main(String[] args) { Demo02 demo02 = new Demo02(); System.out.println(demo02.getName("bobo")); } public String getName(String name){ String res = ""; try { res = name; return res; }finally { res = "波波烤鴨"; return res; // 指令中返回的就不是棧幀頂部的數據了 而是 res 對應的棧幀位置 } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      通過指令我們可以看到在finally中的return關鍵字的指令返回的就是finally中的局部變量的信息,可以理解為finally中的return會覆蓋掉try塊中的return邏輯。

      Java 面向對象編程

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel實用操作技巧有哪些(excel中比較實用的技巧)
      下一篇:【前端領域高頻筆試面試】—— JavaScript高級相關(前端高頻面試題)
      相關文章
      亚洲乱码国产乱码精品精| 在线观看国产一区亚洲bd| 亚洲综合国产成人丁香五月激情| 亚洲国产精品VA在线看黑人| 亚洲视频在线一区二区| 亚洲国产精品一区二区第四页| 亚洲色大成网站www永久网站 | 亚洲人成毛片线播放| 久久久亚洲裙底偷窥综合| 精品日韩亚洲AV无码| 久久亚洲美女精品国产精品 | 久久久无码精品亚洲日韩按摩| 国产精一品亚洲二区在线播放| 亚洲精品午夜无码电影网| 亚洲欧洲国产精品香蕉网| 亚洲国产精品无码专区影院| 亚洲gv白嫩小受在线观看| 亚洲国产成人久久精品动漫| 久久亚洲国产成人精品性色| 亚洲狠狠狠一区二区三区| 亚洲一区中文字幕在线观看| 亚洲国产日韩综合久久精品| 亚洲一区二区三区高清在线观看 | 亚洲国产综合无码一区| 久久精品国产亚洲av麻| 久久久久亚洲精品日久生情 | 亚洲AV成人片无码网站| 国产亚洲精彩视频| 国产精品亚洲玖玖玖在线观看 | 7777久久亚洲中文字幕| 亚洲人成未满十八禁网站| 国产精品亚洲一区二区三区在线观看| 亚洲AV综合永久无码精品天堂| 国产成人亚洲午夜电影| 久久精品国产亚洲AV久| 亚洲爆乳少妇无码激情| 激情小说亚洲图片| 亚洲色婷婷综合久久| 日韩亚洲Av人人夜夜澡人人爽| 亚洲伊人久久大香线蕉| 亚洲Av无码国产一区二区|