1. 程式人生 > 程式設計 >【JAVA】【面試】【 基礎篇】- 基本功

【JAVA】【面試】【 基礎篇】- 基本功

再快不能快基礎,再爛不能爛語言!

【基礎篇】- 基本功

  • 什麼是面向物件

    現實世界存在的任務事物都可以稱之為物件,面向物件是對現實世界建模的一種方式,將一種抽象的思想給具體例項化,物件中包含的內容特徵是它的屬性,物件的一些操作行為是它的方法。例如簡歷就是一個物件,裡面的內容是它的屬性,看、拿、放都可以稱為這個物件的方法。

  • 面向物件的特徵

    封裝:把描述一個物件的屬性和行為封裝成一個類,把具體的業務邏輯功能實現封裝成一個方法,其次封裝的意義還有效的保護屬性通過訪問修飾符私有化屬性(成員變數),公有化方法。

    繼承:實現程式碼的複用,所有的子類所共有的行為和屬性抽取為一個父類,所有的子類繼承該類可具備父類的屬性和行為,繼承具有單一性和傳遞性。

    多型:程式中定義的引用型別變數所指向的具體型別和呼叫的具體方法在程式編譯階段無法確定,而是在執行期才能確定該引用型別變數指向具體哪個物件而呼叫在哪個類中宣告的方法。

    多型的表現形式有強制型別轉換,向上造型等,多型可分為行為多型和物件多型。

    • 行為多型:同一個run( ){ }方法,不同的物件呼叫時會有不同的實現,貓呼叫時是跑,魚呼叫時是遊,鳥呼叫時是飛。

    • 物件多型:同一個物件,可以被造型為不同的型別,比如同一個人物件,可以被造型為兒子,父親,員工等。

  • 面向物件的七大設計原則

    1. 開閉原則(Open-Closed Principle,OCP)

    軟體實體應對擴充套件開放,對修改關閉。在不修改現有程式碼的基礎上去擴充套件新功能。

    2. 單一職責原則(Single Responsibility Principle)

    定義一個類,應該只有一個職責。如果一個類有一個以上的職責,多個職責耦合在一起,會導致設計的侷限性以及程式碼的複用性。

    3. 里氏替換原則(Liskov Substitution Principle)

    子型別必須能夠替換掉它們的父型別。子類可以擴充套件父類的功能,但不能改變父類原有的功能。當子類的方法過載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入引數更寬鬆。當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。

    4. 迪米特法則(Law Of Demeter)

    迪米特法則又稱為最少知道原則,即一個物件應該對其他物件保持最少的瞭解,只與直接的朋友通訊。如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。儘量減少類與類之間的耦合。軟體程式設計的總原則:低耦合高內聚。迪米特法則的初衷就是降低類之間的耦合,由於每個類都減少了不必要的依賴,因此的確可以降低耦合關係。

    5. 依賴倒置原則(Dependence Inversion Principle)

    高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。依賴倒置原則就是要我們面向介面程式設計,理解了面向介面程式設計,也就理解了依賴倒置。

    6. 介面隔離原則(Interface Segregation Principle)

    客戶端不應該依賴它不需要的介面;一個類對一個類的依賴應該建立在最小的介面上。

    7. 合成/聚合原則(Composite/Aggregate Reuse Principle,CARP)

    儘量使用合成/聚合,儘量不要使用繼承。原則:一個類中有另一個的物件。

  • 低耦合高內聚的理解

內聚:每個模組儘可能獨立完成自己功能,不依賴與模組外部的程式碼。

耦合:模組與模組之間介面的複雜程度,模組之間聯絡越複雜耦合度越高,牽一髮而動全身。

低耦合是指減少對其他類的依賴,高內聚是指呼叫的方法儘量寫在本類中,對一個專案來說,就是減少第三方依賴。
複製程式碼
  • final、finally、finalize的區別

    final:可以用來修飾類、方法和變數(成員變數或區域性變數)

    • 修飾類:當修飾類的時候,表面該類不能被繼承,注意:final類中所有的成員方法都會隱式的定義為final方法。
    • 修飾方法:把方法鎖定,防止繼承對其修改。final修飾過的方法不能被重寫。注意:若父類中final方法許可權為private,子類不能繼承,若子類重新定義相同方法名的函式,會認為是子類中的一個新方法。
    • 修飾變數:final成員變量表示常量。只能被賦值一次,賦值後其值不再改變。當final修飾一個基本資料型別時,表示該基本資料型別的值一旦初始化後便不能發生變化;如果final修飾一個引用型別時,則在對其初始化之後便不能再讓其指向其他物件了,但該引用所指向的物件的內容是可以發生變化的。final修飾成員變數,必須要初始化。

    finally:finally作為異常處理的一部分,它只能用在try/catch語句中,並且附帶一個語句塊,表示這段語句最終一定會被執行。

    以下這幾種情況是不會被執行的:

    • 呼叫了System.exit()方法
    • JVM崩潰了(異常情況導致)

    finalize:finalize()是在java.lang.Object理定義的,也就是每一個物件都有這麼一個方法。這個物件在gc啟動時,該物件被回收的時候被呼叫。其實gc可以回收大部分物件(凡是new出來的物件,gc都能搞定),所以一般不需要去實現finalize的。

  • int 和 Integer的區別

    1. Integer是int的包裝類,int是java的一種基本資料型別。
    2. Integer變數必須例項化後才能使用,int變數不需要。
    3. Integer實際是物件的引用,當new一個Integer時,實際上是對一個指標指向此物件;而int則是直接儲存資料值。
    4. Integer的預設值是null,int預設值是0.
    public static void main(String[] args) {
        Integer i = 10;
        Integer j = 10;
        System.out.println(i == j);     //true
          
        Integer a = 128;
        Integer b = 128;
        System.out.println(a == b);     //false
         
        int k = 10;
        System.out.println(k == i);     //true
        int kk = 128;
        System.out.println(kk == a);    //true
          
        Integer m = new Integer(10);
        Integer n = new Integer(10);
        System.out.println(m == n);     //false
    }
    複製程式碼
  • 過載和重寫的區別

    過載(Overloading):過載發生在本類,方法名相同,引數列表不同,與返回值無關,只和方法名、引數列表、引數的型別有關。

    • 方法名必須相同
    • 方法的引數列表一定不一樣
    • 訪問修飾符和返回型別可以相同也可以不同

    重寫(Overriding):重寫發生在父類和子類之間,一般表示父類和子類之間的關係。

    • 方法名必須相同,返回型別必須相同
    • 引數列表必須相同
    • 訪問許可權不能比父類中被重寫的方法的訪問許可權更低。例如:父類的一個方法宣告為public,那麼子類重寫後就不能宣告為protected。
  • 抽象類和介面的區別

    抽象類:抽象類用abstract來修飾,抽象類是用來捕捉子類的通用性,它不能被例項化,只能用作子類的超類,抽象類是被用來建立繼承層級裡子類的模版。

    介面:介面是抽象方法的集合,如果一個類實現了某個介面,那麼它就繼承了這個介面的抽象方法,就像契約模式,如果實現了這個介面,那麼久必須保證使用這些方法,並且實現這些方法,介面是一種形式,介面自身不能做任何事情,介面裡面的方法預設都是abstract的。

    使用場景:

    • 如果擁有一些方法,並想讓他們中的一些有預設的具體實現,請選擇抽象類。
    • 如果想實現多重繼承,那麼請使用介面,由於java不支援多繼承,子類不能繼承多個類,但一個類可以實現多個介面,因此可以使用介面來解決。
    • 如果基本功能在不斷變化,那麼久使用抽象類,如果使用介面,那麼每次變更都需要相應的去改變實現該介面的所有類。
    引數 抽象類 介面
    預設的方法實現 可以有預設的方法實現 完全抽象,根本不存在方法實現
    實現方式 子類用extends關鍵字來繼承抽象類,如果子類不是抽象類的話,

    它需要實現父類抽象類中所有抽象方法,父類中非抽象方法可重寫也可不重寫

    子類用implements去實現介面,需要實現介面中所有方法
    構造器 抽象類可以有構造器(構造器不能用abstract修飾) 介面不能有構造器
    與正常Java類區別 正常Java類可被例項化,抽象類不能被例項化 介面和正常java類是不同的型別
    訪問修飾符 抽象方法可以用public、protected、default修飾 介面預設是public、不能用別的修飾符去修飾
    main方法 抽象類可以有main方法,可以執行 介面中不能有main方法
    多繼承 抽象類可繼承一個類和實現多個介面 介面能繼承一個或多個介面
  • 說說反射的用途及實現

    反射:反射的核心是JVM在執行時才動態載入或呼叫方法/訪問屬性,它不需要事先(寫程式碼或者編譯期)知道執行物件是誰。注意:由於反射會額外消耗一定的系統資源,因此如果不需要動態地建立一個物件,那麼久不需要反射。

    反射框架提供的功能:

    • 在執行時判斷任意一個物件所屬的類;
    • 在執行時構造任意一個類的物件;
    • 在執行時判斷任意一個類所具有的成員變數和方法(通過反射甚至可以呼叫private方法);
    • 在執行時呼叫任意一個物件的方法

    反射的用途:反射最重要的用途就是開發各種通用框架。

    反射的基本實現:獲得Class物件、判斷是否為某個類的例項、建立例項、獲取方法、獲取構造器資訊、獲取類的成員變數、呼叫方法、利用反射建立陣列。

  • 說說自定義註解的場景及實現

    java中有四種元註解:

    @Retention:定義該註解的生命週期(什麼時候使用該註解)

    RetentionPolicy.RUNTIME:始終不會丟棄,執行期也保留註解,因此可以使用反射機制讀取該註解的資訊。自定義註解時通常使用這種方式。

    @Inherited:定義該註釋和子類的關係(是否允許子類繼承該註解),如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。

    @Documented:一個簡單的Annotations標記註解,表示是否將註解資訊新增在java檔案中(註解是否將包含在JavaDoc中)

    @Target:表示該註解用在什麼地方(註解用於什麼地方)

    ElementType.TYPE用於描述類、介面(包括註解型別)或enum宣告。

    
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    @Target({ElementType.FIELD,ElementType.METHOD})
    @interface MyAnno{
        public String name() default "zhangsan";
        public String email() default "[email protected]";
    }
     
    //建立使用者類
    class  User{
     
        @MyAnno(name = "zhang")
        private String name;
     
        @MyAnno(name = "[email protected]")
        private String email;
     
     
        @MyAnno(name = "sayHelloWorld")
        public String sayHello(){
            return "";
        }
    複製程式碼
  • HTTP請求的GET和POST方式的區別

    Get:一般用於獲取、查詢資源資訊

    POST:一般用於更新資源資訊

    Get請求 POST請求
    請求引數會顯示在位址列中 請求引數不會顯示在位址列中
    請求體是空 請求體是請求引數
    請求引數顯示在請求首行中(GET/name=aaa) 請求引數不顯示在請求首行中(POST/ )
    請求引數顯示位址列中【不安全】 位址列不顯示請求引數【相對安全】
    請求引數放首行,http對請求首行顯示1kb 請求引數放請求體,請求體沒有大小限制
    請求引數不能通過request.setCharacterEncoding("gbk")來設定編碼 request.setCharacterEncoding("gbk")只能設定請求體的編碼集
  • session和cookie區別

    1. session儲存在伺服器端,cookie儲存在客戶端(瀏覽器)。
    2. cookie不是很安全,別人可以分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session。
    3. session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用伺服器的效能,考慮到減輕伺服器效能方面,應當使用cookie。
    4. 單個cookie儲存的資料不能超過4k,很多瀏覽器都限制一個站點最多儲存20個cookie。
    5. 可以考慮將登陸資訊等重要資訊存放為session,其他資訊如需保留,可以放在cookie中。
  • session分散式處理

    1. 客戶端cookie加密。(一般用於內網中企業級的系統中,要求使用者瀏覽器端的cookie不能禁用,禁用的話,該方案會失效)。
    2. 叢集中,各個應用伺服器提供了session複製的功能,Tomcat和Jboss都實現了這樣的功能。特定:效能隨著伺服器增加急劇下降,容易引起廣播風暴;session資料需要序列化,影響效能。
    3. session的持久化,使用資料庫來儲存session。就算宕機了也沒有事,資料庫的session照樣存在。特點:每次請求session都要讀寫資料庫,會帶來效能開銷。使用記憶體資料庫,會提高效能,但是宕機會丟失資料(像支付寶的宕機,有同城災備,異地災備)。
    4. 使用共享儲存來儲存session。和資料庫類似,就算宕機了也沒事。其實就是專門搞一臺伺服器,全部對session落地。特定:頻繁的進行序列化和反序列化會影響效能。
    5. 使用memcached來儲存session。本質上是記憶體資料庫的解決方案。特點:存入memcached的資料需要序列化,效率極低。
  • JDBC流程

    1. 註冊驅動程式:Class.forName("com.mysql.jdbc.Driver");
    2. 使用驅動管理類來獲取資料連線物件:conn = DriverManager.getConnection(...);
    3. 獲取資料庫操作物件:Statement state = conn.createStatement();
    4. 定義操作的SQl語句
    5. 執行state.executeQuery(sql);
    6. 處理結果集:ResultSet,如果SQl前有引數值就設定引數值setXXX()
    7. 關閉物件,回收資料庫資源(關閉結果集->關閉資料庫操作物件->關閉連線)
public class JDBCTest {
    /**
     * 使用JDBC連線並操作mysql資料庫
     */
    public static void main(String[] args) {
        // 資料庫驅動類名的字串
        String driver = "com.mysql.jdbc.Driver";
        // 資料庫連線串
        String url = "jdbc:mysql://127.0.0.1:3306/jdbctest";
        // 使用者名稱
        String username = "root";
        // 密碼
        String password = "1234";
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1、載入資料庫驅動( 成功載入後,會將Driver類的例項註冊到DriverManager類中)
            Class.forName(driver);
            // 2、獲取資料庫連線
            conn = DriverManager.getConnection(url,username,password);
            // 3、獲取資料庫操作物件
            stmt = conn.createStatement();
            // 4、定義操作的SQL語句
            String sql = "select * from user where id = 100";
            // 5、執行資料庫操作
            rs = stmt.executeQuery(sql);
            // 6、獲取並操作結果集
            while (rs.next()) {
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 7、關閉物件,回收資料庫資源
            if (rs != null) { //關閉結果集物件
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt != null) { // 關閉資料庫操作物件
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) { // 關閉資料庫連線物件
                try {
                    if (!conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
複製程式碼
  • MVC設計思想

MVC是Model-View-Controller的簡稱,它是一種架構模式,它分離了表現與互動。分為三個核心部件:模型、檢視、控制器。

Model(模型),是程式的主體部分,主要包含業務資料和業務邏輯。在模型層,還會涉及到使用者釋出的服務,在服務中會根據不同的業務需求,更新業務模型中的資料。

View(檢視),是程式呈現給使用者的部分,是使用者和程式互動的介面,使用者會根據具體的業務需求,在View檢視層輸入自己特定的業務資料,並通過介面的事件互動
將對應的輸入引數提交給後臺控制器進行處理。

Controller(控制器),Controller是用來處理使用者輸入資料,以及更新業務模型的部分。控制器中接收了使用者與介面互動時傳遞過來的資料,並根據資料業務邏輯來
執行服務的呼叫和更新業務模型的資料和狀態。

MVC架構的控制流程
1.所有的終端使用者請求被髮送到控制器。
2.控制器依賴請求去選擇載入哪個模組,並把模型附加到對應的檢視。
3.附加了模型資料的最終檢視做為相應傳送給終端使用者。
複製程式碼
  • equals與==的區別

    比較基本資料型別時,只能採用==,比較的是數值

    當比較引用資料型別時,==比較的是引用地址,而equals其實也是,equals是Object定義的方法,而其預設的顯示也是比較地址。我們常用的String型別,因為重寫了equals方法,其內部比較的是內容。

更詳細的面試總結連結請戳:??
juejin.im/post/5db8d9…

【推薦篇】- 書籍內容整理筆記 連結地址
【推薦】【Java程式設計思想】【筆記】 juejin.im/post/5dbb7a…
【推薦】【Java核心技術 卷Ⅰ】【筆記】 juejin.im/post/5dbb7b…

若有錯誤或者理解不當的地方,歡迎留言指正,希望我們可以一起進步,一起加油!??