第1章
- java寶典
- 律子大大
- 4464字
- 2019-03-18 15:32:45
141、Hibernate 中 DetachedCriteria 類是做什么的?
答:DetachedCriteria 和 Criteria 的用法基本上是一致的,但 Criteria 是由 Session 的createCriteria()方法創(chuàng)建的,也就意味著離開創(chuàng)建它的 Session,Criteria 就無法使用了。 DetachedCriteria 不需要 Session 就可以創(chuàng)建(使用 DetachedCriteria.forClass()方法創(chuàng)建),所以通常也稱其為離線的 Criteria,在需要進行查詢操作的時候再和 Session 綁定(調(diào)用其 getExecutableCriteria(Session)方法),這也就意味著一個 DetachedCriteria 可以在需要的時候和不同的 Session 進行綁定。
142、@OneToMany 注解的 mappedBy 屬性有什么作用?
答:@OneToMany 用來配置一對多關聯(lián)映射,但通常情況下,一對多關聯(lián)映射都由多的一方來維護關聯(lián)關系,例如學生和班級,應該在學生類中添加班級屬性來維持學生和班級的關聯(lián)關系(在數(shù)據(jù)庫中是由學生表中的外鍵班級編號來維護學生表和班級表的多對一關系),如果要使用雙向關聯(lián),在班級類中添加一個容器屬性來存放學生,并使用@OneToMany 注解進行映射,此時 mappedBy 屬性就非常重要。如果使用 XML 進行配置,可以用<set>標簽的inverse=“true“設置來達到同樣的效果。
143、MyBatis 中使用#和$書寫占位符有什么區(qū)別?
答:#將傳入的數(shù)據(jù)都當成一個字符串,會對傳入的數(shù)據(jù)自動加上引號;$將傳入的數(shù)據(jù)直接顯示生成在 SQL 中。注意:使用$占位符可能會導致 SQL 注射攻擊,能用#的地方就不要使用$,寫 order by 子句的時候應該用$而不是#。
144、解釋一下 MyBatis 中命名空間(namespace)的作用。
答:在大型項目中,可能存在大量的 SQL 語句,這時候為每個 SQL 語句起一個唯一的標識(ID)就變得并不容易了。為了解決這個問題,在 MyBatis 中,可以為每個映射文件起一個唯一的命名空間,這樣定義在這個映射文件中的每個 SQL 語句就成了定義在這個命名空間中的一個ID。只要我們能夠保證每個命名空間中這個 ID 是唯一的,即使在不同映射文件中的語句 ID 相同,也不會再產(chǎn)生沖突了。
145、MyBatis 中的動態(tài) SQL 是什么意思?
答:對于一些復雜的查詢,我們可能會指定多個查詢條件,但是這些條件可能存在也可能不存在,例如在 58 同城上面找房子,我們可能會指定面積、樓層和所在位置來查找房源,也可能會指定面積、價格、戶型和所在位置來查找房源,此時就需要根據(jù)用戶指定的條件動態(tài)生成 SQL 語句。如果不使用持久層框架我們可能需要自己拼裝 SQL 語句,還好 MyBatis 提供了動態(tài) SQL 的功能來解決這個問題。MyBatis 中用于實現(xiàn)動態(tài) SQL 的元素主要有:- if
- choose / when / otherwise
- trim
- where
- set
- foreach
下面是映射文件的片段。
<select id=“foo“ parameterType=“Blog“ resultType=“Blog“> select * from t_blog where 1 = 1
<if test=“title != null“>
and title =#{title}
</if>
<if test=“content != null“>
and content =#{content}
</if>
<if test=“owner != null“>
and owner =#{owner}
</if>
</select>
當然也可以像下面這些書寫。
<select id=“foo“ parameterType=“Blog“ resultType=“Blog“> select * from t_blog where 1 = 1
<choose>
<when test=“title != null“>
and title =#{title}
</when>
<when test=“content != null“>
and content =#{content}
</when>
<otherwise>
and owner =“owner1“
</otherwise>
</choose>
</select>
再看看下面這個例子。
<select id=“bar“ resultType=“Blog“> select * from t_blog where id in <foreach collection=“array“ index=“index“
item=“item“ open=“(“ separator=“,“ close=“)“>#{item}
</foreach>
</select>
146、什么是 IoC 和 DI?DI 是如何實現(xiàn)的?
答:IoC 叫控制反轉,是 Inversion of Control 的縮寫,DI(Dependency Injection)叫依賴注入,是對 IoC 更簡單的詮釋。控制反轉是把傳統(tǒng)上由程序代碼直接操控的對象的調(diào)用權交給容器,通過容器來實現(xiàn)對象組件的裝配和管理。所謂的“控制反轉“就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器,由容器來創(chuàng)建對象并管理對象之間的依賴關系。IoC 體現(xiàn)了好萊塢原則-“Don’t call me, we will call you“。依賴注入的基本原則是應用組件不應該負責查找資源或者其他依賴的協(xié)作對象。配置對象的工作應該由容器負責,查找資源的邏輯應該從應用組件的代碼中抽取出來,交給容器來完成。DI 是對 IoC 更準確的描述,即組件之間的依賴關系由容器在運行期決定,形象的來說,即由容器動態(tài)的將某種依賴關系注入到組件之中。
舉個例子:一個類 A 需要用到接口 B 中的方法,那么就需要為類 A 和接口 B 建立關聯(lián)或依賴關系,最原始的方法是在類 A 中創(chuàng)建一個接口 B 的實現(xiàn)類 C 的實例,但這種方法需要開發(fā)人員自行維護二者的依賴關系,也就是說當依賴關系發(fā)生變動的時候需要修改代碼并重新構建整個系統(tǒng)。如果通過一個容器來管理這些對象以及對象的依賴關系,則只需要在類 A 中定義好用于關聯(lián)接口 B 的方法(構造器或 setter 方法),將類 A 和接口 B 的實現(xiàn)類 C 放入容器中,通過對容器的配置來實現(xiàn)二者的關聯(lián)。
依賴注入可以通過 setter 方法注入(設值注入)、構造器注入和接口注入三種方式來實現(xiàn), Spring 支持 setter 注入和構造器注入,通常使用構造器注入來注入必須的依賴關系,對于可選的依賴關系,則 setter 注入是更好的選擇,setter 注入需要類提供無參構造器或者無參的靜態(tài)工廠方法來創(chuàng)建對象。
147、Spring 中 Bean 的作用域有哪些?
答:在 Spring 的早期版本中,僅有兩個作用域:singleton 和 prototype,前者表示 Bean 以單例的方式存在;后者表示每次從容器中調(diào)用 Bean 時,都會返回一個新的實例,prototype通常翻譯為原型。
補充:設計模式中的創(chuàng)建型模式中也有一個原型模式,原型模式也是一個常用的模式,例如做一個室內(nèi)設計軟件,所有的素材都在工具箱中,而每次從工具箱中取出的都是素材對象的一個原型,可以通過對象克隆來實現(xiàn)原型模式。
Spring 2.x 中針對 WebApplicationContext 新增了 3 個作用域,分別是:request(每次 HTTP 請求都會創(chuàng)建一個新的 Bean)、session(同一個 HttpSession 共享同一個 Bean,不同的 HttpSession 使用不同的 Bean)和 globalSession(同一個全局 Session 共享一個 Bean)。說明:單例模式和原型模式都是重要的設計模式。一般情況下,無狀態(tài)或狀態(tài)不可變的類適合使用單例模式。在傳統(tǒng)開發(fā)中,由于 DAO 持有 Connection 這個非線程安全對象因而沒有使用單例模式;但在 Spring 環(huán)境下,所有 DAO 類對可以采用單例模式,因為 Spring 利用 AOP 和 Java API 中的 ThreadLocal 對非線程安全的對象進行了特殊處理。
ThreadLocal 為解決多線程程序的并發(fā)問題提供了一種新的思路。ThreadLocal,顧名思義是線程的一個本地化對象,當工作于多線程中的對象使用 ThreadLocal 維護變量時, ThreadLocal 為每個使用該變量的線程分配一個獨立的變量副本,所以每一個線程都可以獨立的改變自己的副本,而不影響其他線程所對應的副本。從線程的角度看,這個變量就像是線程的本地變量。
ThreadLocal 類非常簡單好用,只有四個方法,能用上的也就是下面三個方法:
- void set(T value):設置當前線程的線程局部變量的值。
- T get():獲得當前線程所對應的線程局部變量的值。
- void remove():刪除當前線程中線程局部變量的值。
ThreadLocal 是如何做到為每一個線程維護一份獨立的變量副本的呢?在 ThreadLocal 類中有一個 Map ,鍵為線程對象,值是其線程對應的變量的副本,自己要模擬實現(xiàn)一個 ThreadLocal 類其實并不困難,代碼如下所示: import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MyThreadLocal<T>{
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());
public void set(T newValue){ map.put(Thread.currentThread(), ewValue);
}
public T get(){
return map.get(Thread.currentThread());
}
public void remove(){
map.remove(Thread.currentThread());
}
}
148、解釋一下什么叫 AOP(面向切面編程)?
答:AOP(Aspect-Oriented Programming)指一種程序設計范型,該范型以一種稱為切面(aspect)的語言構造為基礎,切面是一種新的模塊化機制,用來描述分散在對象、類或方法中的橫切關注點(crosscutting concern)。
149、你是如何理解“橫切關注“這個概念的?
答:“橫切關注“是會影響到整個應用程序的關注功能,它跟正常的業(yè)務邏輯是正交的,沒有必然的聯(lián)系,但是幾乎所有的業(yè)務邏輯都會涉及到這些關注功能。通常,事務、日志、安全性等關注就是應用中的橫切關注功能。
150、你如何理解 AOP 中的連接點(Joinpoint)、切點(Pointcut)、增強(Advice)、引介(Introduction)、織入(Weaving)、切面(Aspect)這些概念?
答:
連接點(Joinpoint):程序執(zhí)行的某個特定位置(如:某個方法調(diào)用前、調(diào)用后,方法拋出異常后)。一個類或一段程序代碼擁有一些具有邊界性質(zhì)的特定點,這些代碼中的特定點就是連接點。Spring 僅支持方法的連接點。
切點(Pointcut):如果連接點相當于數(shù)據(jù)中的記錄,那么切點相當于查詢條件,一個切點可以匹配多個連接點。Spring AOP 的規(guī)則解析引擎負責解析切點所設定的查詢條件,找到對應的連接點。
增強(Advice):增強是織入到目標類連接點上的一段程序代碼。Spring 提供的增強接口都是帶方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等。很多資料上將增強譯為“通知”,這明顯是個詞不達意的翻譯,讓很多程序員困惑了許久。
說明: Advice 在國內(nèi)的很多書面資料中都被翻譯成“通知“,但是很顯然這個翻譯無法表達其本質(zhì),有少量的讀物上將這個詞翻譯為“增強“,這個翻譯是對 Advice 較為準確的詮釋,我們通過 AOP 將橫切關注功能加到原有的業(yè)務邏輯上,這就是對原有業(yè)務邏輯的一種增強,這種增強可以是前置增強、后置增強、返回后增強、拋異常時增強和包圍型增強。
引介(Introduction):引介是一種特殊的增強,它為類添加一些屬性和方法。這樣,即使一個業(yè)務類原本沒有實現(xiàn)某個接口,通過引介功能,可以動態(tài)的未該業(yè)務類添加接口的實現(xiàn)邏輯,讓業(yè)務類成為這個接口的實現(xiàn)類。
織入(Weaving):織入是將增強添加到目標類具體連接點上的過程,AOP 有三種織入方式:①編譯期織入:需要特殊的 Java 編譯期(例如 AspectJ 的 ajc);②裝載期織入:要求使用特殊的類加載器,在裝載類的時候對類進行增強;③運行時織入:在運行時為目標類生成代理實現(xiàn)增強。Spring 采用了動態(tài)代理的方式實現(xiàn)了運行時織入,而 AspectJ 采用了編譯期織入和裝載期織入的方式。
切面(Aspect):切面是由切點和增強(引介)組成的,它包括了對橫切關注功能的定義,也包括了對連接點的定義。
補充:代理模式是 GoF 提出的 23 種設計模式中最為經(jīng)典的模式之一,代理模式是對象的結構模式,它給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用。簡單的說,代理對象可以完成比原對象更多的職責,當需要為原對象添加橫切關注功能時,就可以使用原對象的代理對象。我們在打開 Office 系列的 Word 文檔時,如果文檔中有插圖,當文檔剛加載時,文檔中的插圖都只是一個虛框占位符,等用戶真正翻到某頁要查看該圖片時,才會真正加載這張圖,這其實就是對代理模式的使用,代替真正圖片的虛框就是一個虛擬代理; Hibernate 的 load 方法也是返回一個虛擬代理對象,等用戶真正需要訪問對象的屬性時,才向數(shù)據(jù)庫發(fā)出 SQL 語句獲得真實對象。
下面用一個找槍手代考的例子演示代理模式的使用:
/**
*參考人員接口
*/
public interface Candidate {
/**
答題
*/
public void answerTheQuestions();
}
/**
*懶學生
*@author 駱昊
*
*/
public class LazyStudent implements Candidate {
private String name;//姓名
public LazyStudent(String name){
this.name = name;
}
@Override
public void answerTheQuestions(){
//懶學生只能寫出自己的名字不會答題
System.out.println(“姓名:“+ name);
}
}
/**
槍手
@author 駱昊
*/
public class Gunman implements Candidate { private Candidate target;//被代理對象
public Gunman(Candidate target){
this.target = target;
}
@Override
public void answerTheQuestions(){
//槍手要寫上代考的學生的姓名
target.answerTheQuestions();
//槍手要幫助懶學生答題并交卷
System.out.println(“奮筆疾書正確答案“);
System.out.println(“交卷“);
}
}
public class ProxyTest1 {
public static void main(String[] args){
Candidate c = new Gunman(new LazyStudent(“王小二“)); c.answerTheQuestions();
}
}
說明:從 JDK 1.3 開始,Java 提供了動態(tài)代理技術,允許開發(fā)者在運行時創(chuàng)建接口的代理實例,主要包括 Proxy 類和 InvocationHandler 接口。下面的例子使用動態(tài)代理為 ArrayList 編寫一個代理,在添加和刪除元素時,在控制臺打印添加或刪除的元素以及 ArrayList 的大小:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List;
public class ListProxy<T> implements InvocationHandler { private List<T> target;
public ListProxy(List<T> target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object retVal = null;
System.out.println(“[“+ method.getName()+“:“+ args[0]+“]“); retVal = method.invoke(target, args); System.out.println(“[size=“+ target.size()+“]“); return retVal;
}
}
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class ProxyTest2 {
@SuppressWarnings(“unchecked“)
public static void main(String[] args){ List<String> list = new ArrayList<String>(); Class<?> clazz = list.getClass();
ListProxy<String> myProxy = new ListProxy<String>(list); List<String> newList =(List<String>)
Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), myProxy);
newList.add(“apple“);
newList.add(“banana“);
newList.add(“orange“);
newList.remove(“banana“);
}
}
說明:使用 Java 的動態(tài)代理有一個局限性就是代理的類必須要實現(xiàn)接口,雖然面向接口編程是每個優(yōu)秀的 Java 程序都知道的規(guī)則,但現(xiàn)實往往不盡如人意,對于沒有實現(xiàn)接口的類如何為其生成代理呢?繼承!繼承是最經(jīng)典的擴展已有代碼能力的手段,雖然繼承常常被初學者濫用,但繼承也常常被進階的程序員忽視。CGLib 采用非常底層的字節(jié)碼生成技術,通過為一個類創(chuàng)建子類來生成代理,它彌補了 Java 動態(tài)代理的不足,因此 Spring 中動態(tài)代理和 CGLib 都是創(chuàng)建代理的重要手段,對于實現(xiàn)了接口的類就用動態(tài)代理為其生成代理類,而沒有實現(xiàn)接口的類就用 CGLib 通過繼承的方式為其創(chuàng)建代理。
斗羅:核平使者?這是絕世殺神!
【不魔改+殺伐果斷+虐三踩剛!】我有一刀,名往生,可破世間萬法,可斬諸天神魔。我有核爆,名核平,核爆面前,眾生平等,一切核平!身為武道奇才的王霄,為突破人體極限,意外穿越斗羅。先天雙武魂,器武魂--黑刀往輪回,特殊武魂--核爆量子。加入武魂殿,成為武魂殿圣子,和其下圣女比比東,稱之為武魂雙圣!多年后,唐三帶著小舞和史萊克眾人攻打武魂殿,王霄笑了。對王霄來言,這世界本就是弱肉強食,人殺魂獸取魂環(huán),魂獸吃人增修為,本就如此。他不理解,為何人能與魂獸相通,即便是化形,那也終究是畜生罷了。人,就是人,獸,就是獸,永遠都改變不了。非吾族類,其心必異。什么昊天宗,什么天斗帝國,不服?那就打!老子王霄,王字當頭,當萬古凌霄。既然不服,那就都去死吧。
人在小竹峰,系統(tǒng)說我是孫悟空!
【系統(tǒng)】+【多女主】+【陸雪琪】+【孫悟空】+【天才】穿越后。秦川成了草廟村遺孤之一。并且被小竹峰首座水月大師收為弟子。不但開局拿團寵副本,成為小竹峰的唯一小師弟。更是在拜師當天遇見個離譜系統(tǒng)。我明明在小竹峰,系統(tǒng)偏偏說我是孫悟空?秦川拜師水月大師。系統(tǒng)說他拜師了菩提祖師?簡直離譜。可系統(tǒng)卻又實實在在的獎勵給他了筋斗云與孫悟空的逆天悟性。所有功法一看就會,觸類旁通。一年時間突破玉清四重。系統(tǒng)再次下達任務。【請宿主前往東海龍宮尋找定海神針。】秦川:???東海龍宮?定海神針?系統(tǒng)你真讓我做孫悟空啊?……
撈尸人
人知鬼恐怖,鬼曉人心毒。這是一本傳統(tǒng)靈異小說。
雙穿大唐世界:小兕子叫我哥哥
【晉陽公主小兕子日常?雙穿?萌娃】大唐最寵愛的小公主來到了現(xiàn)代。葉逍遙:這么可愛的小孩子,我可以偷走嗎?李世民:小郎君,兕子我送你,你再給我點軍火如何?長孫皇后:小郎君,那個薄如蟬翼的黑色褲襪還有嗎?李麗質(zhì):小郎君,我愿以身相許!兕子:窩噠!都是窩噠!
重生:開局逮到高冷校花超市偷竊
重生校園時代,陸遠秋照看自家開的超市,卻在監(jiān)控下發(fā)現(xiàn)一位容貌清麗的少女正在偷拿貨架上的商品。拍攝證據(jù)后,陸遠秋將其帶到倉庫內(nèi)。“拿了多少?”少女背靠墻壁,沉默寡言:“沒有了,就這些。”陸遠秋認識她。少女名叫白清夏,跟他一個學校。高冷,生人勿近,冷面校花,通通是她的代名詞。只是別人眼中那不可褻瀆的白月光,今天竟以這種方式被自己逼到了墻角里。陸遠秋默默告訴自己,今天無論如何也不能放她走。前一世,白清夏在超市里做了同樣的事情,但陸遠秋顧及對方面子,選擇了視而不見。結果白清夏出門后就遭遇了一場車禍。這件事成了陸遠秋心中的釘子,倘若那天,他狠心攔下白清夏,后面的慘劇就不會發(fā)生。所以這次,他要拖延時間,要對校花進行嚴厲的批評教育!看著角落里屈辱到眼眶發(fā)紅的校花,陸遠秋繼續(xù)質(zhì)問:“你確定就這些?”“校服里面鼓鼓囊囊的,是不是還藏著東西?!”