目前流行的開發技術、常見的面試問題以及問題的答案都已經寫的特別清楚了,今天我在以前的基礎上,再基於我的的經驗繼續精選一些面試題給你們閱讀參考。java
1,Java的反射程序員
Java 反射機制是在運行狀態中,對於任意一個類,都可以得到這個類的全部屬性和方法,對於任意一個對象都可以調用它的任意一個屬性和方法。這種在運行時動態的獲取信息以及動態調用對象的方法的功能稱爲Java 的反射機制。反射也就是動態加載對象,並對對象進行剖析。Class 類與java.lang.reflect 類庫一塊兒對反射的概念進行了支持,該類庫包含了Field,Method,Constructor類(每一個類都實現了Member 接口)。web
反射的做用:面試
1),在運行時判斷任意一個對象所屬的類redis
2),在運行時構造任意一個類的對象spring
3),在運行時判斷任意一個類所具備的成員變量和方法數據庫
4),在運行時調用任意一個對象的方法編程
優勢:能夠動態的建立對象和編譯,最大限度發揮了java的靈活性。設計模式
缺點:對性能有影響。使用反射基本上一種解釋操做,告訴JVM咱們要作什麼而且知足咱們的要求,這類操做老是慢於直接執行java代碼。緩存
如何使用java的反射?
a. 經過一個全限類名建立一個對象
1) Class.forName("全限類名");
2) 類名.class; 獲取Class<?> clazz 對象
3) 對象.getClass();
b. 獲取構造器對象,經過構造器new出一個對象
1) Clazz.getConstructor([String.class]);
2) Con.newInstance([參數]);
c. 經過class對象建立一個實例對象(就至關與new類名()無參構造器)
1) Clazz.newInstance();
d. 經過class對象得到一個屬性對象
1) Field c=clazz.getFields(); 得到某個類的全部的公共(public)的字段,包括父類中的字段。
2) Field c=clazz.getDeclaredFields(); 得到某個類的全部聲明的字段,即包括public、private和proteced,可是不包括父類的申明字段。
e、經過class對象得到一個方法對象
1)Clazz.getMethod("方法名",class…..parameaType);(只能獲取公共的)
2)Clazz.getDeclareMethod("方法名"); (獲取任意修飾方法,不能執行私有)
M.setAccessible(true);(讓私有的方法能夠執行)
f. 讓方法執行
Method.invoke(obj實例對象,obj可變參數);
2,Spring的源碼分析及實現
Spring是一個開源的、輕量級的Java 開發框架。Spring使用的是基本的JavaBean來完成之前只可能由EJB完成的事情。然而,Spring的用途不只僅限於服務器端的開發。從簡單性、可測試性和鬆耦合性角度而言,絕大部分Java應用均可以從Spring中受益。Spring的核心是控制反轉(IOC)和麪向切面(AOP)。
Spring Bean的建立是典型的工廠模式,這一系列的Bean工廠,也即IOC容器爲開發者管理對象間的依賴關係提供了不少便利和基礎服務,在Spring中有許多的IOC容器的實現供用戶選擇和使用,其相互關係以下:
BeanFactory做爲最頂層的一個接口類,它定義了IOC容器的基本功能規範,BeanFactory 有三個子類:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。IOC容器接口BeanFactory:
public interface BeanFactory {
在BeanFactory裏只對IOC容器的基本行爲做了定義,根本不關心你的bean是如何定義怎樣加載的。正如咱們只關心工廠裏獲得什麼的產品對象,至於工廠是怎麼生產這些對象的,這個基本的接口不關心。
而要知道工廠如何產生對象,就須要看具體的IOC容器實現,spring提供了許多IOC容器的實現。如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是針對最基本的ioc容器的實現,這個IOC容器能夠讀取XML文件定義的BeanDefinition(XML文件中對bean的描述),若是說XmlBeanFactory是容器中的屌絲,ApplicationContext應該算容器中的高富帥了。
ApplicationContext是Spring提供的一個高級的IoC容器,它除了可以提供IoC容器的基本功能外,還爲用戶提供瞭如下的附加服務。從ApplicationContext接口的實現,咱們看出其特色:
1, 支持信息源,能夠實現國際化。(實現MessageSource接口);
2, 訪問資源。(實現ResourcePatternResolver接口,這個後面要講);
3, 支持應用事件。(實現ApplicationEventPublisher接口);
AOP即面向切面編程。能夠說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入封裝、繼承、多態等概念來創建一種對象層次結構,用於模擬公共行爲的一個集合。AOP技術利用一種稱爲"橫切"的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其命名爲"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減小系統的重複代碼,下降模塊之間的耦合度,並有利於將來的可操做性和可維護性。
AOP把軟件系統分爲兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特色是,他們常常發生在覈心關注點的多處,而各處基本類似,好比權限認證、日誌、事物。AOP的做用在於分離系統中的各類關注點,將核心關注點和橫切關注點分離開來。
Spring對AOP的支持
Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。所以,AOP代理能夠直接使用容器中的其它bean實例做爲目標,這種關係可由IOC容器的依賴注入提供。Spring建立代理的規則爲:
1)、默認使用Java動態代理來建立AOP代理,這樣就能夠爲任何接口實例建立代理了;
2)、當須要代理的類不是代理接口的時候,Spring會切換爲使用CGLIB代理,也可強制使用CGLIB;
AOP編程實際上是很簡單的事情,縱觀AOP編程,程序員只須要參與三個部分:
1)、定義普通業務組件 2)、定義切入點,一個切入點可能橫切多個業務組件 3)、定義加強處理,加強處理就是AOP框架爲普通業務組件織入的處理動做
因此進行AOP編程的關鍵就是定義切入點和定義加強處理,一旦定義了合適的切入點和加強處理,AOP框架將自動生成AOP代理,即:代理對象的方法=加強處理+被代理對象的方法。
下面給出一個Spring AOP的.xml文件模板,名字叫作aop.xml,以後的內容都在aop.xml上進行擴展:
<?xml version="1.0" encoding="UTF-8"?>
3,****動態代理****(cglib 與 JDK)
JDK動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理。
一、若是目標對象實現了接口,默認狀況下會採用JDK的動態代理實現AOP;
二、若是目標對象實現了接口,能夠強制使用CGLIB實現AOP;
三、若是目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換;
如何強制使用CGLIB實現AOP?
1) 添加CGLIB庫,SPRING_HOME/cglib/*.jar
2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK動態代理和CGLIB字節碼生成的區別?
1) JDK動態代理只能對實現了接口的類生成代理,而不能針對類;2) CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法,由於是繼承,因此該類或方法最好不要聲明成final;
4,分佈式鎖的實現方案
分佈式鎖通常有三種實現方式:
1. 數據庫鎖;
2. 基於Redis的分佈式鎖;
3. 基於ZooKeeper的分佈式鎖。
基於數據庫鎖實現
方案1:
CREATE TABLE `methodLock` (
當咱們想要鎖住某個方法時,執行如下SQL:
insert into methodLock(method_name,desc) values (`method_name`,`desc`);
:想要釋放鎖的話,須要執行如下Sql:
delete from methodLock where method_name ='method_name';
方案2:
CREATE TABLE `method_lock` (
獲取鎖:
select id, method_name, state,version from method_lock where state=1 and method_name='methodName';
佔有鎖:
update t_resoure set state=2, version=2, update_time=now() where method_name='methodName' and state=1 and version=2;
缺點:
一、這把鎖強依賴數據庫的可用性,數據庫是一個單點,一旦數據庫掛掉,會致使業務系統不可用。 二、這把鎖沒有失效時間,一旦解鎖操做失敗,就會致使鎖記錄一直在數據庫中,其餘線程沒法再得到到鎖。 三、這把鎖只能是非阻塞的,由於數據的insert操做,一旦插入失敗就會直接報錯。沒有得到鎖的線程並不會進入排隊隊列,要想再次得到鎖就要再次觸發得到鎖操做。 四、這把鎖是非重入的,同一個線程在沒有釋放鎖以前沒法再次得到該鎖。由於數據中數據已經存在了。
解決方案:
一、數據庫是單點?搞兩個數據庫,數據以前雙向同步。一旦掛掉快速切換到備庫上。 二、沒有失效時間?只要作一個定時任務,每隔必定時間把數據庫中的超時數據清理一遍。 三、非阻塞的?搞一個while循環,直到insert成功再返回成功。 四、非重入的?在數據庫表中加個字段,記錄當前得到鎖的機器的主機信息和線程信息,那麼下次再獲取鎖的時候先查詢數據庫,若是當前機器的主機信息和線程信息在數據庫能夠查到的話,直接把鎖分配給他就能夠了。
實現方案:
try{
缺點:
在這種場景(主從結構)中存在明顯的競態:
客戶端A從master獲取到鎖,
在master將鎖同步到slave以前,master宕掉了。
slave節點被晉級爲master節點,
客戶端B取得了同一個資源被客戶端A已經獲取到的另一個鎖。安全失效!
基於zookeeper實現
方案:能夠直接使用zookeeper第三方庫Curator客戶端,這個客戶端中封裝了一個可重入的鎖服務。
Curator提供的InterProcessMutex是分佈式鎖的實現。acquire方法用戶獲取鎖,release方法用於釋放鎖。
缺點:
性能上可能並無緩存服務那麼高。由於每次在建立鎖和釋放鎖的過程當中,都要動態建立、銷燬瞬時節點來實現鎖功能。ZK中建立和刪除節點只能經過Leader服務器來執行,而後將數據同不到全部的Follower機器上。
三種方案的比較
上面幾種方式,哪一種方式都沒法作到完美。就像CAP同樣,在複雜性、可靠性、性能等方面沒法同時知足,因此,根據不一樣的應用場景選擇最適合本身的纔是王道。
從理解的難易程度角度(從低到高):數據庫 > 緩存 > Zookeeper
從實現的複雜性角度(從低到高):Zookeeper >= 緩存 > 數據庫
從性能角度(從高到低):緩存 > Zookeeper >= 數據庫
從可靠性角度(從高到低):Zookeeper > 緩存 > 數據庫
5,Java設計模式部分搞笑解讀
一、工廠模式,
搞笑解讀:—追MM少不了請吃飯了,麥當勞的雞翅和肯德基的雞翅都是MM愛吃的東西,雖然口味有所不一樣,但無論你帶MM去麥當勞或肯德基,只管向服務員說「來四個雞翅」就好了。麥當勞和肯德基就是生產雞翅的Factory。
工廠模式:客戶類和工廠類分開。消費者任什麼時候候須要某種產品,只需向工廠請求便可。消費者無須修改就能夠接納新產品。缺點是當產品修改時,工廠類也要作相應的修改。如:如何建立及如何向客戶端提供。
2,單例模式
搞笑解讀:俺有6個漂亮的老婆,她們的老公都是我,我就是咱們家裏的老公Sigleton,她們只要說道「老公」,都是指的同一我的,那就是我(白日好夢)。
單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例單例模式。單例模式只應在有真正的「單一實例」的需求時纔可以使用。
3,適配器模式
搞笑解讀:在一次聚會碰到了一個很漂亮的烏克蘭MM,可不會說烏克蘭語,她也不會說普通話,只好求助於會烏克蘭語的朋友,他做爲咱們之間的Adapter,讓咱們能夠相互交談了(也不知道他會不會耍我)。
適配器模式:把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口緣由不匹配而沒法一塊兒工做的兩個類可以一塊兒工做。適配類能夠根據參數返還一個合適的實例給客戶端。
4,代理模式
搞笑解讀:跟MM在網上聊天,一開頭老是「hi,你好」,「你從哪兒來呀?」「你多大了?」「身高多少呀?」這些話,真煩人,寫個程序作爲個人Proxy吧,凡是接收到這些話都設置好了自動的回答,接收到其餘的話時再通知我回答,酷吧。
代理模式:代理模式給某一個對象提供一個代理對象,並由代理對象控制對源對象的引用。代理就是一我的或一個機構表明另外一我的或者一個機構採起行動。某些 狀況下,客戶不想或者不可以直接引用一個對象,代理對象能夠在客戶和目標對象直接起到中介的做用。客戶端分辨不出代理主題對象與真實主題對象。代理模式可 以並不知道真正的被代理對象,而僅僅持有一個被代理對象的接口,這時候代理對象不可以建立被代理對象,被代理對象必須有系統的其餘角色代爲建立並傳入。