自定義註解與常用設計模式
- 2019 年 11 月 7 日
- 筆記
1.什麼是註解
註解分為:內置註解,自定義註解。內置註解就是JDK 自帶的,而自定義註解則是自己定義的比如許多框架(spring) 用到的
內置註解:
(1) @SuppressWarnings 再程式前面加上可以在javac編譯中去除警告–階段是SOURCE (2) @Deprecated 帶有標記的包,方法,欄位說明其過時—-階段是SOURCE (3)@Overricle 打上這個標記說明該方法是將父類的方法重寫–階段是SOURCE
自定義註解:
@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、介面、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變數、枚舉值)、方法參數和本地變數(如循環變數、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
1. CONSTRUCTOR:用於描述構造器
2. FIELD:用於描述域
3. LOCAL_VARIABLE:用於描述局部變數
4. METHOD:用於描述方法
5. PACKAGE:用於描述包
6. PARAMETER:用於描述參數
7. TYPE:用於描述類、介面(包括註解類型) 或enum聲明 2.@Retention
表示需要在什麼級別保存該注釋資訊,用於描述註解的生命周期(即:被描述的註解在什麼範圍內有效) 3.@Documented 4.@Inherited
程式碼示例:
package com.cheng.entity; import com.cheng.MavenTest.Zhujie.setPorter; import com.cheng.MavenTest.Zhujie.setTable; @setTable(value = "tree") public class Strudents { @setPorter(leng = 10, name = "name") public String name; @setPorter(leng = 10, name = "age") private Integer age; static { System.out.println("靜態塊"); } public Strudents() { System.out.println("無參構造函數"); } public Strudents(String name) { System.out.println("有參構造函數 傳入參數為:"+ name); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
package com.cheng.MavenTest; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; public class Zhujie { //自定義表欄位映射註解 @Retention(RetentionPolicy.RUNTIME) public @interface setPorter{ String name(); int leng(); } //自定表映射註解ORM @Target(value={ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface setTable{ String value(); } public static void main(String[] args) throws ClassNotFoundException { //反射獲取類 Class<?> c=Class.forName("com.cheng.entity.Strudents"); //獲取類 setTable st=c.getAnnotation(setTable.class); //獲取實體類欄位 Field[] declaredFields = c.getDeclaredFields(); StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(" select "); for(int i=0;i<declaredFields.length;i++){ Field f=declaredFields[i]; //獲取註解值 setPorter sp=f.getAnnotation(setPorter.class); stringBuffer.append(" " + sp.name()+" "); if(declaredFields.length-1==i){ stringBuffer.append(" from "); }else{ stringBuffer.append(" , "); } } stringBuffer.append(" "+st.value()); System.out.println(stringBuffer.toString()); } }
結果:

什麼是設計模式
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。使用設計模式是為了可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使程式碼編製真正工程化,設計模式是軟體工程的基石,如同大廈的一塊塊磚石一樣。項目中合理的運用設計模式可以完美的解決很多問題,每種模式在現在中都有相應的原理來與之對應,每一個模式描述了一個在我們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是它能被廣泛應用的原因。本章系Java之美[從菜鳥到高手演變]系列之設計模式,我們會以理論與實踐相結合的方式來進行本章的學習,希望廣大程式愛好者,學好設計模式,做一個優秀的軟體工程師!
設計模式分類
總體來說設計模式分為三大類:
創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
其實還有兩類:併發型模式和執行緒池模式。用一個圖片來整體描述一下:

設計模式的六大原則
1、開閉原則(Open Close Principle)
開閉原則就是說對擴展開放,對修改關閉。在程式需要進行拓展的時候,不能去修改原有的程式碼,實現一個熱插拔的效果。所以一句話概括就是:為了使程式的擴展性好,易於維護和升級。想要達到這樣的效果,我們需要使用介面和抽象類,後面的具體設計中我們會提到這點。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。 LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟體單位的功能不受到影響時,基類才能真正被複用,而衍生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對「開-閉」原則的補充。實現「開-閉」原則的關鍵步驟就是抽象化。而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。—— From Baidu 百科
3、依賴倒轉原則(Dependence Inversion Principle)
這個是開閉原則的基礎,具體內容:真對介面編程,依賴於抽象而不依賴於具體。
4、介面隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的介面,比使用單個介面要好。還是一個降低類之間的耦合度的意思,從這兒我們看出,其實設計模式就是一個軟體的設計思想,從大型軟體架構出發,為了升級和維護方便。所以上文中多次出現:降低依賴,降低耦合。
5、迪米特法則(最少知道原則)(Demeter Principle)
為什麼叫最少知道原則,就是說:一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模組相對獨立。
6、合成復用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承。
什麼是單利模式?
單例保證一個對象JVM中只能有一個實例,常見單例 懶漢式、餓漢式
什麼是懶漢式,就是需要的才會去實例化,執行緒不安全。
什麼是餓漢式,就是當class文件被載入的時候,初始化,天生執行緒安全。
懶漢式
class SingletonTest { public static void main(String[] args) { Singleton sl1 = Singleton.getSingleton(); Singleton sl2 = Singleton.getSingleton(); System.out.println(sl1 == sl2); } } public class Singleton { // 當需要的才會被實例化 private static Singleton singleton; private Singleton() { } synchronized public static Singleton getSingleton() { if (singleton == null) { singleton = new Singleton(); } return singleton; } }
餓漢式
lass SingletonTest1 { public static void main(String[] args) { Singleton1 sl1 = Singleton1.getSingleton(); Singleton1 sl2 = Singleton1.getSingleton(); System.out.println((sl1 == sl2)+"-"); } } public class Singleton1 { //當class 文件被載入初始化 private static Singleton1 singleton = new Singleton1(); private Singleton1() { } public static Singleton1 getSingleton() { return singleton; } }
工行模式?
實現創建者和調用者分離
public interface Car { public void run(); } public class AoDi implements Car { @Override public void run() { System.out.println("奧迪...."); } } public interface Car { public void run(); } public class CarFactory { static public Car createCar(String carName) { Car car = null; if (carName.equals("奧迪")) { car = new AoDi(); } else if (carName.equals("Benz")) { car = new BenChi(); } return car; } public static void main(String[] args) { Car car1 = CarFactory.createCar("奧迪"); Car car2 = CarFactory.createCar("Benz"); car1.run(); car2.run(); } }
工廠方法
public interface Car { public void run(); } public class AoDi implements Car { @Override public void run() { System.out.println("奧迪...."); } } public class BenChi implements Car { @Override public void run() { System.out.println("Benz...."); } } public class AoDiChiFactory { static public Car createCar() { return new AoDi(); } } public interface BenChiFactory { static public Car createCar() { return new BenChi(); } } public class Main { public static void main(String[] args) { Car c1 = AoDiChiFactory.createCar(); Car c2 = BenChiFactory.createCar(); c1.run(); c2.run(); } }
什麼是代理?
通過代理控制對象的訪問,可以詳細訪問某個對象的方法,在這個方法調用處理,或調用後處理。既(AOP微實現) ,AOP核心技術面向切面編程。

代理應用場景
安全代理 可以屏蔽真實角色
遠程代理 遠程調用代理類RMI
延遲載入 先載入輕量級代理類,真正需要在載入真實
代理的分類
靜態代理(靜態定義代理類)
動態代理(動態生成代理類)
Jdk自帶動態代理
Cglib 、javaassist(位元組碼操作庫)
靜態代理
靜態代理需要自己生成代理類
public class XiaoMing implements Hose { @Override public void mai() { System.out.println("我是小明,我要買房啦!!!!haha "); } } class Proxy implements Hose { private XiaoMing xiaoMing; public Proxy(XiaoMing xiaoMing) { this.xiaoMing = xiaoMing; } public void mai() { System.out.println("我是中介 看你買房開始啦!"); xiaoMing.mai(); System.out.println("我是中介 看你買房結束啦!"); } public static void main(String[] args) { Hose proxy = new Proxy(new XiaoMing()); proxy.mai(); } }
JDK動態代理(不需要生成代理類)
實現InvocationHandler 就可以了
public interface Hose { /** * * @methodDesc: 功能描述:(買房代理) * @author: 余勝軍 * @param: * @createTime:2017年8月27日 上午2:54:34 * @returnType: void * @copyright:上海每特教育科技有限公司 */ public void mai(); } public class XiaoMing implements Hose { @Override public void mai() { System.out.println("我是小明,我要買房啦!!!!haha "); } } public class JDKProxy implements InvocationHandler { private Object tarjet; public JDKProxy(Object tarjet) { this.tarjet = tarjet; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是房產中介.....開始監聽你買房啦!"); Object oj = method.invoke(tarjet, args); System.out.println("我是房產中介.....結束監聽你買房啦!"); return oj; } } class Test222 { public static void main(String[] args) { XiaoMing xiaoMing = new XiaoMing(); JDKProxy jdkProxy = new JDKProxy(xiaoMing); Hose hose=(Hose) Proxy.newProxyInstance(xiaoMing.getClass().getClassLoader(), xiaoMing.getClass().getInterfaces(), jdkProxy); hose.mai(); } }
CGLIB動態代理
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class Cglib implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("我是買房中介 , 開始監聽你買房了...."); Object invokeSuper = methodProxy.invokeSuper(o, args); System.out.println("我是買房中介 , 開結束你買房了...."); return invokeSuper; } } class Test22222 { public static void main(String[] args) { Cglib cglib = new Cglib(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(XiaoMing.class); enhancer.setCallback(cglib); Hose hose = (Hose) enhancer.create(); hose.mai(); } }
7CGLIB與JDK動態代理區別
jdk動態代理是由Java內部的反射機制來實現的,cglib動態代理底層則是藉助asm來實現的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之後的相關執行過程中比較高效(可以通過將asm生成的類進行快取,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的介面。如果沒有上述前提,jdk動態代理不能應用。
注:asm其實就是java位元組碼控制.