某東Java面試題

Java類(lèi)集

1、Collection 是存放一組單值得最大接口,所謂的單值是指集合中的每個(gè)元素都是一個(gè)對(duì)象,一般會(huì)很少直接使用此接口直接操作。
2、List 是Collection接口的子接口,也是最常用的接口,此接口對(duì)Collection接口進(jìn)行了大量的擴(kuò)充。里面的內(nèi)容是允許重復(fù)的。
3、Set 是Collection接口的子類(lèi),沒(méi)有對(duì)Collection進(jìn)行擴(kuò)充,里面不允許存放重復(fù)的內(nèi)容。
4、Map Map是存放一對(duì)值的最大接口,即,接口中每個(gè)元素都是一對(duì),以key—>value的形式保存。
5、Iterator 集合的輸出接口,用于輸出集合中的內(nèi)容只能進(jìn)行從前到后的單向輸出。
6、ListIterator 是Iterator的子接口,可以進(jìn)行雙向輸出。
7、Enumeration 是最早的輸出接口,用于輸出指定集合中的內(nèi)容。
8、SortedSet 單值的排序接口,凡是實(shí)現(xiàn)此接口的集合類(lèi),里面的內(nèi)容是可以排序的,使用比較器排序。
9、SortedMap 存放一對(duì)值的排序接口,實(shí)現(xiàn)此接口的集合類(lèi),里面的內(nèi)容按照key排序,使用比較器排序。
10、Queue 隊(duì)列接口,此接口的子類(lèi)可以實(shí)現(xiàn)隊(duì)列操作。
11、Map.Entry Map.Entry的內(nèi)部接口,每個(gè)Map.Entry對(duì)象都保存著一對(duì)key—>value的內(nèi)容,每個(gè)Map接口中都保存著多個(gè)Map.Entry接口實(shí)例。
以上的接口必須全部掌握。并且掌握各個(gè)接口的主要特點(diǎn)。
接口的繼承關(guān)系

Collection接口:
image

Map接口:
image

String和equals()、hashCode()

Object中的“==”,equal,hashCode()

Object中的==

  • 對(duì)于基本數(shù)據(jù)類(lèi)型,“==”比較值是否相同。
  • 對(duì)于引用數(shù)據(jù)類(lèi)型, “==”比較內(nèi)存中的存放地址是否相同。

Object中的equals()

public boolean equals(Object o) {
    return this == o;
}

Object的equals()方法默認(rèn)還是根據(jù)“==”比較,所以比較的還是內(nèi)存地址。

Object的equals()方法默認(rèn)還是根據(jù)“==”比較,所以比較的還是內(nèi)存地址。

public int hashCode() {
    int lockWord = shadow$_monitor_;
    final int lockWordStateMask = 0xC0000000;  // Top 2 bits.
    final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).
    final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.
    if ((lockWord & lockWordStateMask) == lockWordStateHash) {
        return lockWord & lockWordHashMask;
    }
    return System.identityHashCode(this);
}

Object中的hashCode()

public int hashCode() {
    int lockWord = shadow$_monitor_;
    final int lockWordStateMask = 0xC0000000;  // Top 2 bits.
    final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).
    final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.
    if ((lockWord & lockWordStateMask) == lockWordStateHash) {
        return lockWord & lockWordHashMask;
    }
    return System.identityHashCode(this);
}

Object中的hashCode()返回值是在JVM中的32位地址。

String類(lèi)的“==”,equal,hashCode()

String類(lèi)中對(duì)hashCode()和equals()都進(jìn)行了重寫(xiě),所以調(diào)用String的equals()和hashCode()可能會(huì)和沒(méi)重寫(xiě)這兩個(gè)方法的類(lèi)產(chǎn)生不同的結(jié)果。

String的equals()

@Override
public boolean equals(Object other) {
    if (other == this) {
      return true;
    }
    if (other instanceof String) {
        String s = (String)other;
        int count = this.count;
        if (s.count != count) {
            return false;
        }
        // TODO: we want to avoid many boundchecks in the loop below
        // for long Strings until we have array equality intrinsic.
        // Bad benchmarks just push .equals without first getting a
        // hashCode hit (unlike real world use in a Hashtable). Filter
        // out these long strings here. When we get the array equality
        // intrinsic then remove this use of hashCode.
        if (hashCode() != s.hashCode()) {
            return false;
        }
        for (int i = 0; i < count; ++i) {
            if (charAt(i) != s.charAt(i)) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}

同樣是如果內(nèi)存地址相同肯定內(nèi)容也相同,返回true。
存儲(chǔ)地址不同,要滿(mǎn)足長(zhǎng)度、hash碼、對(duì)應(yīng)的字符都相同才能返回true。

String的hashCode()

@Override public int hashCode() {
    int hash = hashCode;
    if (hash == 0) {
        if (count == 0) {
            return 0;
        }
        for (int i = 0; i < count; ++i) {
            hash = 31 * hash + charAt(i);
        }
        hashCode = hash;
    }
    return hash;
}

根據(jù)String的成員變量hashCode和字符串的內(nèi)容生成hashcode。

Spring工作原理

內(nèi)部最核心的就是IoC了,動(dòng)態(tài)注入(DI),讓一個(gè)對(duì)象的創(chuàng)建不用new了,可以自動(dòng)的生產(chǎn),這其實(shí)就是利用Java里的反射。反射其實(shí)就是在運(yùn)行時(shí)動(dòng)態(tài)的去創(chuàng)建、調(diào)用對(duì)象,Spring就是在運(yùn)行時(shí),跟xml Spring的配置
文件來(lái)動(dòng)態(tài)的創(chuàng)建對(duì)象,和調(diào)用對(duì)象里的方法的 。
Spring還有一個(gè)核心就是AOP這個(gè)就是面向切面編程,可以為某一類(lèi)對(duì)象 進(jìn)行監(jiān)督和控制(也就是在調(diào)用這類(lèi)對(duì)象的具體方法的前后去調(diào)用你指定的模塊)從而達(dá)到對(duì)一個(gè)模塊擴(kuò)充的功能。這些都是通過(guò)
配置類(lèi)達(dá)到的。
Spring目的:就是讓對(duì)象與對(duì)象(模塊與模塊)之間的關(guān)系沒(méi)有通過(guò)代碼來(lái)關(guān)聯(lián),都是通過(guò)配置類(lèi)說(shuō)明管理的(Spring根據(jù)這些配置 內(nèi)部通過(guò)反射去動(dòng)態(tài)的組裝對(duì)象)
要記?。篠pring是一個(gè)容器,凡是在容器里的對(duì)象才會(huì)有Spring所提供的這些服務(wù)和功能。
Spring里用的最經(jīng)典的一個(gè)設(shè)計(jì)模式就是:模板方法模式。

Spring AOP與IOC
一、 IoC(Inversion of control): 控制反轉(zhuǎn)
1、IoC:
概念:控制權(quán)由對(duì)象本身轉(zhuǎn)向容器;由容器根據(jù)配置文件去創(chuàng)建實(shí)例并創(chuàng)建各個(gè)實(shí)例之間的依賴(lài)關(guān)系
核心:bean工廠;在Spring中,bean工廠創(chuàng)建的各個(gè)實(shí)例稱(chēng)作bean
二、AOP(Aspect-Oriented Programming): 面向方面編程
1、 代理的兩種方式:
靜態(tài)代理:

  • 針對(duì)每個(gè)具體類(lèi)分別編寫(xiě)代理類(lèi);
  • 針對(duì)一個(gè)接口編寫(xiě)一個(gè)代理類(lèi);
    動(dòng)態(tài)代理:
    針對(duì)一個(gè)方面編寫(xiě)一個(gè)InvocationHandler,然后借用JDK反射包中的Proxy類(lèi)為各種接口動(dòng)態(tài)生成相應(yīng)的代理類(lèi)

JDK動(dòng)態(tài)代理的實(shí)現(xiàn)原理

首先來(lái)看一下如何使用JDK動(dòng)態(tài)代理。JDK提供了java.lang.reflect.Proxy類(lèi)來(lái)實(shí)現(xiàn)動(dòng)態(tài)代理的,可通過(guò)它的newProxyInstance來(lái)獲得代理實(shí)現(xiàn)類(lèi)。同時(shí)對(duì)于代理的接口的實(shí)際處理,是一個(gè)java.lang.reflect.InvocationHandler,它提供了一個(gè)invoke方法供實(shí)現(xiàn)者提供相應(yīng)的代理邏輯的實(shí)現(xiàn)??梢詫?duì)實(shí)際的實(shí)現(xiàn)進(jìn)行一些特殊的處理,像Spring AOP中的各種advice。下面來(lái)看看如何使用。
被代理的接口:

package com.mikan.proxy;  

public interface HelloWorld {  
  
    void sayHello(String name);  
  
}  

接口的實(shí)現(xiàn)類(lèi):

package com.mikan.proxy;  
  
public class HelloWorldImpl implements HelloWorld {  
    @Override  
    public void sayHello(String name) {  
        System.out.println("Hello " + name);  
    }  
}  

實(shí)現(xiàn)一個(gè)java.lang.reflect.InvocationHandler:

package com.mikan.proxy;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  

public class CustomInvocationHandler implements InvocationHandler {  
    private Object target;  
  
    public CustomInvocationHandler(Object target) {  
        this.target = target;  
    }  
  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("Before invocation");  
        Object retVal = method.invoke(target, args);  
        System.out.println("After invocation");  
        return retVal;  
    }  
}  

使用代理:

package com.mikan.proxy;  
  
import java.lang.reflect.Proxy;  
  
public class ProxyTest {  
  
    public static void main(String[] args) throws Exception {  
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
  
        CustomInvocationHandler handler = new CustomInvocationHandler(new HelloWorldImpl());  
        HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(  
                ProxyTest.class.getClassLoader(),  
                new Class[]{HelloWorld.class},  
                handler);  
        proxy.sayHello("Mikan");  
    }  
}  

可以看到,動(dòng)態(tài)生成的代理類(lèi)有如下特性:

  • 繼承了Proxy類(lèi),實(shí)現(xiàn)了代理的接口,由于java不能多繼承,這里已經(jīng)繼承了Proxy類(lèi)了,不能再繼承其他的類(lèi),所以JDK的動(dòng)態(tài)代理不支持對(duì)實(shí)現(xiàn)類(lèi)的代理,只支持接口的代理。
  • 提供了一個(gè)使用InvocationHandler作為參數(shù)的構(gòu)造方法。
  • 生成靜態(tài)代碼塊來(lái)初始化接口中方法的Method對(duì)象,以及Object類(lèi)的equals、hashCode、toString方法。
  • 重寫(xiě)了Object類(lèi)的equals、hashCode、toString,它們都只是簡(jiǎn)單的調(diào)用了InvocationHandler的invoke方法,即可以對(duì)其進(jìn)行特殊的操作,也就是說(shuō)JDK的動(dòng)態(tài)代理還可以代理上述三個(gè)方法。
  • 代理類(lèi)實(shí)現(xiàn)代理接口的sayHello方法中,只是簡(jiǎn)單的調(diào)用了InvocationHandler的invoke方法,我們可以在invoke方法中進(jìn)行一些特殊操作,甚至不調(diào)用實(shí)現(xiàn)的方法,直接返回。

Java設(shè)計(jì)模式

image

事務(wù)隔離級(jí)別

隔離級(jí)別是指若干個(gè)并發(fā)的事務(wù)之間的隔離程度。TransactionDefinition 接口中定義了五個(gè)表示隔離級(jí)別的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:這是默認(rèn)值,表示使用底層數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別。對(duì)大部分?jǐn)?shù)據(jù)庫(kù)而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)修改但還沒(méi)有提交的數(shù)據(jù)。該級(jí)別不能防止臟讀和不可重復(fù)讀,因此很少使用該隔離級(jí)別。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)只能讀取另一個(gè)事務(wù)已經(jīng)提交的數(shù)據(jù)。該級(jí)別可以防止臟讀,這也是大多數(shù)情況下的推薦值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級(jí)別表示一個(gè)事務(wù)在整個(gè)過(guò)程中可以多次重復(fù)執(zhí)行某個(gè)查詢(xún),并且每次返回的記錄都相同。即使在多次查詢(xún)之間有新增的數(shù)據(jù)滿(mǎn)足該查詢(xún),這些新增的記錄也會(huì)被忽略。該級(jí)別可以防止臟讀和不可重復(fù)讀。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說(shuō),該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴(yán)重影響程序的性能。通常情況下也不會(huì)用到該級(jí)別。

事務(wù)傳播行為

所謂事務(wù)的傳播行為是指,如果在開(kāi)始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為。在TransactionDefinition定義中包括了如下幾個(gè)表示傳播行為的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED。
    這里需要指出的是,前面的六種事務(wù)傳播行為是 Spring 從 EJB 中引入的,他們共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 啟動(dòng)的事務(wù)內(nèi)嵌于外部事務(wù)中(如果存在外部事務(wù)的話(huà)),此時(shí),內(nèi)嵌事務(wù)并不是一個(gè)獨(dú)立的事務(wù),它依賴(lài)于外部事務(wù)的存在,只有通過(guò)外部的事務(wù)提交,才能引起內(nèi)部事務(wù)的提交,嵌套的子事務(wù)不能單獨(dú)提交。如果熟悉 JDBC 中的保存點(diǎn)(SavePoint)的概念,那嵌套事務(wù)就很容易理解了,其實(shí)嵌套的子事務(wù)就是保存點(diǎn)的一個(gè)應(yīng)用,一個(gè)事務(wù)中可以包括多個(gè)保存點(diǎn),每一個(gè)嵌套子事務(wù)。另外,外部事務(wù)的回滾也會(huì)導(dǎo)致嵌套子事務(wù)的回滾。

JVM內(nèi)存管理

堆內(nèi)存、棧內(nèi)存溢出

中間件

HashMap原理

是基于Map接口的實(shí)現(xiàn),存儲(chǔ)鍵值對(duì)時(shí),它可以接收null的鍵值,是非同步的,HashMap存儲(chǔ)著Entry(hash, key, value, next)對(duì)象。
通過(guò)hash的方法,通過(guò)put和get存儲(chǔ)和獲取對(duì)象。存儲(chǔ)對(duì)象時(shí),我們將K/V傳給put方法時(shí),它調(diào)用hashCode計(jì)算hash從而得到bucket位置,進(jìn)一步存儲(chǔ),HashMap會(huì)根據(jù)當(dāng)前bucket的占用情況自動(dòng)調(diào)整容量(超過(guò)Load Facotr則resize為原來(lái)的2倍)。獲取對(duì)象時(shí),我們將K傳給get,它調(diào)用hashCode計(jì)算hash從而得到bucket位置,并進(jìn)一步調(diào)用equals()方法確定鍵值對(duì)。如果發(fā)生碰撞的時(shí)候,Hashmap通過(guò)鏈表將產(chǎn)生碰撞沖突的元素組織起來(lái),在Java 8中,如果一個(gè)bucket中碰撞沖突的元素超過(guò)某個(gè)限制(默認(rèn)是8),則使用紅黑樹(shù)來(lái)替換鏈表,從而提高速度。

二叉樹(shù)的遍歷

快速排序

堆排,如果從若干數(shù)中找最大N個(gè)數(shù)用最大堆還是最小堆?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 包含的重點(diǎn)內(nèi)容:JAVA基礎(chǔ)JVM 知識(shí)開(kāi)源框架知識(shí)操作系統(tǒng)多線程TCP 與 HTTP架構(gòu)設(shè)計(jì)與分布式算法數(shù)據(jù)庫(kù)知...
    消失er閱讀 4,552評(píng)論 1 10
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,562評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,697評(píng)論 18 399
  • 下雨的一天。遠(yuǎn)面接到的單子變得有點(diǎn)多樣,系統(tǒng)升級(jí)了,也感受到一種快速學(xué)習(xí)和理解的能力。 余老師調(diào)崗,不需遠(yuǎn)面了。原...
    馨晴的能量小站閱讀 168評(píng)論 0 0
  • 王成打卡 領(lǐng)導(dǎo)者的資質(zhì)#8期#關(guān)愛(ài)組 皓庭(北京)科技有限公司 一、【知~勤學(xué)】《以?shī)^斗者為本》 二、【行~實(shí)踐】...
    王成皓庭新風(fēng)閱讀 175評(píng)論 0 0

友情鏈接更多精彩內(nèi)容