從零開始學Java-Day18
阿新 • • 發佈:2021-06-24
設計模式
設計模式是Java發展過程中總結出來的一些值得借鑑的優秀程式設計經驗
設計模式一共有23種,主要分為三大類
單例設計模式
核心思想:確保例項只有一個
好處:可以節省記憶體空間,方便控制資源
實現思路:
- 構造方法私有化--阻止外部直接呼叫本類的構造方法建立物件
- 建立本類物件且私有化--為了防止外部多次獲取本類物件
- 對外提供一個公共全域性訪問點--按照預先設定的方式來獲取物件
餓漢式:載入時事先建立好類的物件
懶漢式:不會再初始化就載入所有資源,在用的時候才載入
單例設計模式方案二:懶漢式
不會再初始化類的時候就建立本類物件,而是用的時候(呼叫get())才建立
程式碼實現思路:
- 將建立物件拆分成兩步:
- 先定義引用型別變數,預設值null
- 在get()裡判斷(之前是否建立過),如果沒建立過,建立,建立過返回建立的物件.
package cn.tedu.design; //本類用於測試單例模式實現方式一:餓漢式 public class Singleton1 { public static void main(String[] args) { MySingle single = MySingle.getSingle(); MySingle single2 = MySingle.getSingle(); System.out.println(single); System.out.println(single2); System.out.println(single == single2); } } /* *思考:在構造方法與物件被私有化後,需要呼叫公共的全域性訪問點來獲取本類物件,但是, * 我們如何呼叫這個公共方法 * 之前呼叫方法都是通過類物件進行呼叫,但單例因為構造方法私有化無法建立物件。 * 解決方案:可以將公共方法設定為靜態方法,因此可以直接通過類來呼叫。 * 因為公共方法是靜態的所以類裡建立的物件也要靜態修飾 */ class MySingle{ //構造方法私有化:防止外界隨意例項化本類物件 private MySingle() {} private static MySingle single = new MySingle(); public static MySingle getSingle(){ return single; } }
package cn.tedu.design; //單例測試模式方案二:懶漢式--面試重點 public class Singleton2 { public static void main(String[] args) { MySingle2 single1 = MySingle2.getMySingle2(); MySingle2 single2 = MySingle2.getMySingle2(); System.out.println(single2); System.out.println(single1); System.out.println(single1 == single2);//true } } class MySingle2{ private MySingle2(){} static private MySingle2 mySingle2; /* *在多執行緒下會有資料隱患 * 解決方案一:同步程式碼塊鎖 * 解決方案二:把該方法用 synchronized 修飾 */ public synchronized static MySingle2 getMySingle2() { if (mySingle2 == null) { mySingle2 = new MySingle2(); } return mySingle2; } }
註解與自定義註解
註解很厲害,它可以增強我們的Java程式碼,同時利用反射技術可以擴充實現很多功能。它們被廣泛應用於三大框架底層。
傳統我們通過xml文字檔案宣告方式(如下圖,但是XML比較繁瑣且不易檢查),而現在最主流的開發都是基於註解方式,程式碼量少,框架可以根據註解去自動生成很多程式碼,從而減少程式碼量,程式更易讀。例如最火爆的SpringBoot就完全基於註解技術實現。
分三類
-
JDK註解
- @override
-
元註解:用來定義其他註解的註解
- @Target註解用的範圍:類上、方法上、屬性上等
- @Retention註解的生命週期:原始檔中、位元組碼檔案中、執行中
- SOURCE:在原始檔中有效(即原始檔保留)
- CLASS:在class檔案中有效(即class保留)
- RUNTIME:在執行時有效(即執行時保留)
- @Inherited 允許子註解繼承
- @Documented 生成javadoc時會包含註解,不常用
- @Repeatable 註解為可重複型別註解,可以在同一個地方多次使用,不常用
-
自定義註解
- 自定義註解需要元註解來指定,語法:@interface 註解名{}
- 使用@Target註解定義自定義註解的作用位置,可以指定多個,格式:{,}
- 使用@Retention註解定義自定義註解的生命週期,只能指定一個
- 使用註解時,@符號 + 註解名直接使用
- 自定義註解可以新增屬性
- 普通屬性int age(); 賦值格式: @Test(age = 18)
- 特殊屬性int value(); 賦值格式:@Test(18)
- 一旦添加了屬性必須賦值
- 特殊屬性不限制類型,限制的是屬性的名字
- 特殊屬性和普通屬性賦予預設的格式一樣 int age() default 15;
package cn.tedu.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//本類用於測試自定義註解,熟悉註解的相關規則
public class TestAnnotation {
public static void main(String[] args) {
new MeiGeMi().skill();
}
}
/*
*0.首先注意:自定義註解的語法和Java不同,不要套用Java格式
*1.註解定義要使用@interface 註解名的方式來定義
* 1.1通過@Target註解來定義當前自定義註解使用的位置| 注意導包 | ElementType.靜態常量 | 輸入的是一個數組,可以用 , 隔開元素
* 1.2通過使用@Retention註解來定義當前自定義註解使用的生命週期| 注意導包 |RetentionPolicy.靜態常量
* 決定註解的存活時間,只能存在一個
*
*/
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
@interface Test{
/*自定義註解可以新增功能--給自定義註解新增屬性
* 注意:int age();不是方法的定義,而是自定義註解中定義age屬性的語法
* 定義屬性後,才使用自定義註解時要在註解後的括號裡定義同類型的值,如果在定義屬性時
* 賦予預設值了可以直接使用
* 註解中的新功能:定義特殊屬性value*/
int height() default 0;
String value() default "一馬當先,萬馬無光";
}
class MeiGeMi{
@Test
String name;
public void skill(){
System.out.println("Explosion!!!!!!!!!!!!!!");
}
}
反射
獲取位元組碼物件
- Class.forName("類的全路徑")
- 類名.class
- 物件.getClass();
反射是一種經典常用的技術,通常用來獲取或才做其他人的資源
反射的前提是獲取位元組碼物件 + 反射技術獲取目標類的所有構造方法
具體方法詳見API手冊
單元測試方法
package cn.tedu.reflection;
//本類用於測試反射而準備的物料類
public class Student {
String name;
private int age;
private static String skill;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void learn(){
System.out.println("學習!");
}
private void play(String gameName){
System.out.println("沖沖衝!!!" + gameName);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cn.tedu.reflection;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
//本類用來測試反射
public class TestReflect1 {
/*單元測試方法:是Java測試的最小單位,使用靈活
* 語法要求:@Test
* void + 沒有引數 + public
* 使用時需要導包*/
@Test
public void getClazz() throws ClassNotFoundException {
Class<?> stu1 = Class.forName("cn.tedu.reflection.Student");
Class<Student> stu2 = Student.class;
Class<? extends Student> stu3 = new Student().getClass();
System.out.println(stu1);//class cn.tedu.reflection.Student
System.out.println(stu1.getName());//cn.tedu.reflection.Student
System.out.println(stu2.getPackage().getName());//cn.tedu.reflection
System.out.println(stu3.getSimpleName());//Student
}
@Test
public void getConstruct() throws NoSuchMethodException {
Class<Student> stu = Student.class;
Constructor<?>[] cs = stu.getConstructors();
Method[] method = stu.getMethods();
for (Method method1 : method) {
Class[] cp = method1.getParameterTypes();
System.out.println(Arrays.toString(cp));
}
for (Constructor<?> c : cs) {
//System.out.println(c.getName());
Class[] cp = c.getParameterTypes();
System.out.println(Arrays.toString(cp));
}
}
}