Java 反射機(jī)制

反射機(jī)制

Java反射機(jī)制就是在運(yùn)行狀態(tài)中整慎,對于任意一個(gè)類(class文件)声诸,都能夠知道這個(gè)類的所有屬性和方法酱讶;
對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性双絮;
對于這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對象的方法和功能稱為Java語言的反射機(jī)制浴麻。

簡述:動(dòng)態(tài)獲取類中的信息,就是Java反射

反射機(jī)制實(shí)現(xiàn)

要想對字節(jié)碼文件進(jìn)行解剖囤攀,必須要有字節(jié)碼文件對象

  1. 獲取字節(jié)碼對象的方式一:

    • Object類中的getClass方法:

      \color{blue}{必須明確類名软免,并創(chuàng)建對象}

    • Person p = new Person(); Class clazz = p.getClass()

  2. 獲取字節(jié)碼對象的方式二:

    • 任何數(shù)據(jù)類型都具備一個(gè)靜態(tài)的屬性.class來獲取Class對象:

      \color{blue}{必須明確類名}

    • Class clazz = Person.class
  3. 獲取字節(jié)碼對象的方式三:

    • 通過forName()方法實(shí)現(xiàn):

      \color{blue}{必須明確類名}

    • String className = "com.zimo.Person"; Class clazz =Class.forName(className)

public static void main(String args[]){
    // 無參構(gòu)造
    // 原方法--
    com.zimo.Person p = new com.zimo.Person();
    // 反射--
    String className = "com.zimo.Person"; 
    Class clazz =Class.forName(className);
    clazz.newInstance();
    --------------------------------------------------------------------------------------------
    // 有參構(gòu)造
    // 原方法--
    com.zimo.Person p = new com.zimo.Person("zimo", 18);
    // 反射--
    String className = "com.zimo.Person"; 
    Class clazz =Class.forName(className);
    // 先獲取構(gòu)造函數(shù)列表
    Constructor c = clazz.getConstructor(String.class, int.class);
    // 通過構(gòu)造器的newInstance方法進(jìn)行對象的初始化
    Object obj = c.newInstance("zimo", 18);
    --------------------------------------------------------------------------------------------
    // 獲取字節(jié)碼文件中的字段
    Class clazz =Class.forName("com.zimo.Person");
    Filed filed = clazz.getFiled("age");    // 只能獲取公共,私有的無法獲取
    filed = clazz.getDeclaredFiled("age");  // 只能獲取本類焚挠,但包含私有
    
    // 對私有字段的訪問取消權(quán)限檢查:暴力訪問
    filed.setAccessible(true);
    
    Object o = clazz.newInstance();
    filed.set(o, 86);
    Object obj = filed.get(o);
    --------------------------------------------------------------------------------------------
    // 獲取字節(jié)碼文件中的公共方法
    Class clazz =Class.forName("com.zimo.Person");
    Method[] me = clazz.getMethods();           // 獲取的都是共有的方法
    Method[] me1 = clazz.getDeclaredMethods();   // 獲取本類中私有方法
    Method me2 = clazz.getMethod("show", null);  // 獲取person類中的show方法膏萧,空參數(shù)列表
    Method me3 = clazz.getMethod("show1", String.class, int.class);  // 獲取person類中的show方法,有參函數(shù)
    
    // 運(yùn)行show方法
    Object obj = clazz.newInstance();
    me2.invoke(obj, null);
    me3.invoke(obj, "zimo", 18);
}

反射練習(xí)

  • 電腦運(yùn)行
package com.zimo.ComputerRun;
// 主板
public class MainBoard{
    public void run(){
        System.out.println("MainBoard Run ...........");
    }
    public void usePCI(PCI p){
        if(p != null){
            p.open();
            p.close();           
        }
    }
}
package com.zimo.ComputerRun;
/**
 *  電腦運(yùn)行
 */
public class ReflectTest{
    public static void main(String args[]){
        MainBoard mb = new MainBoard();
        mb.run();
        // mb.usePCI(null);
        // mb.usePCI(new SourceCard());     // 每次添加一個(gè)設(shè)備蝌衔,就需要修改代碼傳遞一個(gè)新創(chuàng)建的對象
        // 不用new對象榛泛,只獲取其class文件,內(nèi)部創(chuàng)建對象:使用配置文件讀取
        File configFile = new File("pci.properties");
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream(configFile);
        
        prop.load(fis);
        for(int i= 0;i < prop.size(); i++){
            String pciName = prop.getProperty("pci" + (i + 1));
            Class clazz = Class.forName(pciName);   // 用Class去加載這個(gè)pci子類
            PCI p = (PCI)clazz.newInstance();
            mb.usePCI(p);
        }
    }
}
package com.zimo.ComputerRun;
public interface PCI{
    public void open();
    public void close();
}
#pci.properties
# 配置聲卡
pci1=com.zimo.Computer.SoundCard
# 配置網(wǎng)卡
pci2=com.zimo.Computer.NetCard
package com.zimo.ComputerRun;
// 聲卡
public class SourceCard implements PCI{
    public void open(){
        System.out.println("sound open...");
    }
    public void close(){
        System.out.println("sound close...");
    }
}
package com.zimo.ComputerRun;
// 網(wǎng)卡
public class NetCard {
    public void open(){
        System.out.println("NetCard open...");
    }
    public void close(){
        System.out.println("NetCard close...");
    }
}
  • 模擬MyBatis存儲(chǔ)任何對象數(shù)據(jù)
public class Mybatis{
    // 提供一個(gè)方法:可以保存任何對象數(shù)據(jù)的字段和具體值
    public static void save(Object obj) throws Exception{
        PrintStream ps = new PrintStream(new FileOutputStream("./data.txt", true));
        // 解析對象的字段和每個(gè)字段的值存儲(chǔ)起來   obj = Student/Pig/Teacher....
        // 1.先得到對象的Class文件對象
        Class c = obj.getClass();
        // 2.定位它的全部成員變量
        Field[] fields = c.getDeclaredFields();
        // 3.遍歷這些字段并取值
        for(Field field : fields){
            // 取字段名
            String name = field.getName();
            // 取字段值
            field.setAccessible(true);      // 暴力反射 取消訪問權(quán)限
            String value = field.get(obj) + "";
            ps.println(name + "=" + value);
        }
        ps.close();
    }
}
public static void main(String args[]){
    Student s = new Student(1, "zimo", "18", "秋名山", "10086");
    Mybatis.save(s);
    Pig p = new Pig("佩奇", 500.0, "粉色", "小紅", "母豬");
    Mybatis.save(p);
}

反射適合做通用技術(shù)框架的底層實(shí)現(xiàn)噩斟,在框架底層源碼我們經(jīng)巢芟牵可以看到反射的影子

正則表達(dá)式

本身也是一個(gè)對象,java.util.regex包中(Pattern類)剃允,主要用于操作字符串沛简,通過特定的符號來體現(xiàn)的。

特點(diǎn):\color{red}{簡化了代碼斥废,降低了閱讀性}

  • 傳統(tǒng)QQ號檢測方法:
// 需求:定義一個(gè)功能對QQ號進(jìn)行校驗(yàn)
// 要求:長度5-15椒楣,只能是數(shù)字,0不能開頭
public static void checkQQ(String qq){
    int len = qq,length();
    
    if(len >=5 && len <= 15){
        if(!qq.startsWith("0")){
            try{
                long l = Long.parseLong(qq);
                System.out.println(l + ":正確");
            }catch(NumberFormatException e){
                System.out.println(qq + ":含有非法字符");
            }
        }else{
            System.out.println(qq + ":開頭不能為0");
        }
    }else{
        System.out.println(qq + ":長度錯(cuò)誤");
    }
}
  • 使用正則表達(dá)式檢測QQ方法:
public static boolean checkQQByRegex(String qq){
    
    String regex = "[1-9][0-9]{4,14}";
    boolean b = qq.matches(regex);
    System.out.println(b);
    return b;
}
public static void main(String args[]){
    String QQ = "123456";
    checkQQ(QQ);
    checkQQByRegex(QQ);
}

正則表達(dá)式對字符串常見操作

  1. 匹配:
    • 其實(shí)使用的就是String類中的matches()方法
  2. 切割:
    • 其實(shí)使用的就是String類中的split()方法
  3. 替換:
    • 其實(shí)使用的就是String類中的replaceAll()方法
  4. 獲饶等狻:
    • 其實(shí)使用的就是String類中的get()方法
/**
 *  演示匹配
 */
public static void matchesRegex(){
    // 匹配手機(jī)號碼是否正確
    String tel = "15800001111";
    String regex = "1[3578][0-9]{9}";   // 等價(jià)于:"1[3578]\\d{9}"
    boolean b = tel.matches(regex);
    System.out.println(tel + ":" + b);
}
/**
 *  演示切割
 */
public static void sqlitRegex(){
    // 切割疊詞姓名
    String names = "zimo---zhangsan@@@@lisi######wangwu";
    // String[] names = str.split(" ");     // 只能切割單個(gè)空格
    String[] names = names.split("(.)\\1+");    // (.)\\1 封裝成第一組
    System.out.println(tel + ":" + b);
}
/**
 *  演示替換
 */
public static void replaceAllRegex(){
    String str = "";
    str = str.replaceAll("(.)\\1+","$1");   // 用$引用前一個(gè)組中的數(shù)據(jù) zimo-zhangsan@lisi#wangwu
    System.out.println(tel + ":" + b);
    // 隱藏手機(jī)號158****1111
    String tel = "15800001111";
    tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); // 158****1111
}
/**
 *  演示獲取
 *  正則封裝成對象捧灰,創(chuàng)建一個(gè)匹配器對象,按照表達(dá)式匹配字符序列统锤,將結(jié)果留在匹配器中
 */
public static void sqlitRegex(){
    String str = "da jia hao, ming tian bu fang jia!";
    String regex = "\\b[a-z]{3}\\b";
    // 將正則規(guī)則進(jìn)行封裝
    Pattern p = Pattern.compile(regex);
    // 通過正則對象的matcher方法字符串相關(guān)聯(lián)毛俏。獲取要對字符串操作的匹配器對象Matcher
    Matcher m = p.matcher(p);
    // 通過Matcher匹配器的對象方法對字符串進(jìn)行操作
    while(m.find()){
        System.out.println(m.group());  // 獲取匹配的子序列
        System.out.println(m.start() + ":" + m.end());  // 獲取匹配的子序列腳標(biāo)
    }
}
  • 練習(xí):
// 治療口吃:我我...我我要..要要要要...要要學(xué)學(xué)學(xué)..學(xué)學(xué)學(xué)學(xué)編編編編...編編程程程程....程程程程程程程程
// ip地址排序
// 對郵件地址校驗(yàn)
public static void main(String args[]){
    fun1();
}

// 治療口吃
public static void fun1(){
    String str = "我我...我我要..要要要要...要要學(xué)學(xué)學(xué)..學(xué)學(xué)學(xué)學(xué)編編編編...編編程程程程....程程程程程程程程";
    // 將字符串中點(diǎn)去掉,替換
    str = str.replaceAll("\\.+", "");   // 我我我我要要要要要要要學(xué)學(xué)學(xué)學(xué)學(xué)學(xué)學(xué)編編編編編編程程程程程程程程程程程程
    // 替換疊詞
    str = str.replaceAll("(.)\\1+", "$1");  // 我要學(xué)編程
}

// ip地址排序 192.168.1.82  127.0.0.1  3.3.3.3  105.70.11.55
public static void fun2(){
    String ip_str = "192.168.1.82     127.0.0.1  3.3.3.3  105.70.11.55";
    // 為了讓ip可以按字符串比較饲窿,只要讓ip每段的數(shù)位相同煌寇,補(bǔ)兩個(gè)0操作
    ip_str = ip_str.replaceAll("(\\d+)","00$1");
    // 每一段保留三位
    ip_str = ip_str.replaceAll("0*(\\d{3})","$1");
    // 將ip地址切出
    String[] ips = ip_str.split(" +");
    // 排序
    TreeSet<String> ts = new TreeSet<String>();
    for(String ip : ips){
        ts.add(ip);
    }
    for(String ip : ts){
        System.out.println(ip.replaceAll("0*(\\d+)", "$1"));
    }
}

// 對郵件地址校驗(yàn)
public static void fun3(){
    String mail = "abc1@sina.com";
    String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]{1,3}){1,3}";
    regex = "\\w+@\\w+(\\.\\w+)+";  // 可以匹配 1@1.1
    boolean b = mail.matches(regex);
    System.out.println(mail + ":" + b);
}

網(wǎng)頁爬蟲

用于在互聯(lián)網(wǎng)中獲取符合指定規(guī)則的數(shù)據(jù)

// 爬取郵箱地址
public static void main(String args[]){
    List<String> list = getMails();
    for(String l : list){
        System.out.println(l);
    }
}
// 爬取本地?cái)?shù)據(jù)
public static List<String> getMails(){
    // 讀取源文件
    BufferedReader bufr = new BufferedReader(new FileReader("D:\\mail.html"));
    // 對讀取的數(shù)據(jù)進(jìn)行規(guī)則的匹配,從中獲取符合規(guī)則的數(shù)據(jù)
    String mail_regex = "\\w+@\\w+(\\.\\w+)+";
    List<String> list = new ArrayList<String>();
    Pattern p = Pattern.compile(mail_regex);
    String line = null;
    while((line = bufr.readLine())!=null){
        Matcher m = p.matcher(line);
        while(m.find()){
            // 將符合規(guī)則的數(shù)據(jù)存儲(chǔ)到集合中
            list.add(m.group());
        }
    }
    return list;
}
// 爬取本地?cái)?shù)據(jù)
public static List<String> getMailsByWeb(){
    // 讀取源文件
    // BufferedReader bufr = new BufferedReader(new FileReader("D:\\mail.html"));
    URL url = new URL("http://192.168.1.82:8080/myweb/mail.html");
    BufferedReader bufr = new BufferedReader(new InputStreamReader(url.openStream()));
    // 對讀取的數(shù)據(jù)進(jìn)行規(guī)則的匹配免绿,從中獲取符合規(guī)則的數(shù)據(jù)
    String mail_regex = "\\w+@\\w+(\\.\\w+)+";
    List<String> list = new ArrayList<String>();
    Pattern p = Pattern.compile(mail_regex);
    String line = null;
    while((line = bufr.readLine())!=null){
        Matcher m = p.matcher(line);
        while(m.find()){
            // 將符合規(guī)則的數(shù)據(jù)存儲(chǔ)到集合中
            list.add(m.group());
        }
    }
    return list;
}

單元測試框架

org.junit測試框架的使用

package SectionTestDemo;
import org.junit.Assert;
import org.junit.Test;
public class UserServiceTest {
    /**
     *  測試方法的要求:
     *  1. public 修飾
     *  2. 沒有返回值沒有參數(shù)
     *  3. 必須使用@Test修飾
     */
    @Test
    public void testLogin(){
        UserService userService = new UserService();
        String rs = userService.login("admin", "123456");
        // 預(yù)期斷言結(jié)果正確性
        Assert.assertEquals("err", "success", rs);
    }
}
/**
 *  org.junit.ComparisonFailure: err 
 *  期望:success
 *  實(shí)際:error
 *  紅色:err   綠色:ok
 */
package SectionTestDemo;
public class UserService {
    public String login(String name, String pass){
        if ("admin".equals(name) && "1234567".equals(pass)){
            return "success";
        }else {
            return "error";
        }
    }
}

注解說明:

  • @Test:測試方法
  • @Before:測試實(shí)例方法之前 Junit 5:使用的是BeforeEach
  • @After:測試實(shí)例方法之后 Junit 5:使用的是AfterEach
  • @BeforeClass:測試靜態(tài)方法之前 Junit 5:使用的是BeforeAll
  • @AfterClass:測試靜態(tài)方法之后 Junit 5:使用的是AfterAll

注解

  • 用在類上唧席,方法上,成員變量,構(gòu)造器淌哟,.... 上對成分進(jìn)行編譯約束迹卢,標(biāo)記等操作的。
  • 注解是JDK1.5的新特性徒仓。
  • 注解相當(dāng)一種標(biāo)記腐碱,是類的組成部分,可以給類攜帶一些額外的信息掉弛。
  • 注解是給編譯器或JVM看的症见,編譯器或JVM可以根據(jù)注解來完成對應(yīng)的功能。

注解作用

  1. 標(biāo)記殃饿。
  2. 方法重寫約束@Override
  3. 函數(shù)式接口約束谋作。@FunctionalInterface.
  4. 現(xiàn)今最牛逼的框架技術(shù)多半都是在使用注解和反射。都是屬于框架的基礎(chǔ)技術(shù)乎芳。

自定義注解

  • 自定義注解格式:

    修飾符 @interface 注解名{

     注解屬性
    

    }

  • 小結(jié):

    • 自定義注解使用@interface關(guān)鍵字
    • 注解默認(rèn)可以標(biāo)記很多地方
package com.zimo._01selfNote;
@interface Book{
}

@interface MyTest{
}
@Book
public class MyBook {
    @Book
    @MyTest
    public static void main(@MyTest String[] args) {

        @MyTest
        int age = 12;
    }
}
  • 注解屬性格式:

    • 格式1:數(shù)據(jù)類型 屬性名()
    • 格式2:數(shù)據(jù)類型 屬性名() default 默認(rèn)值
  • 屬性使用的數(shù)據(jù)類型:

    八種基礎(chǔ)數(shù)據(jù)類型(int遵蚜,short,long奈惑,double吭净,byte,char肴甸,boolean寂殉,float)

    String,Class

    以上類型都支持

  • 小結(jié):

    • 注解可以有屬性原在,屬性名必須帶()
    • 在用注解的時(shí)候友扰,屬性必須賦值,除非這個(gè)屬性有默認(rèn)值N钫丁焕檬!
package com.zimo._01selfNote;
@interface Book{
    // 不寫默認(rèn)public
    String name();
    String[] authors();
    double price();
    String address() default "中國-北京";
}
@Book(name = "《精通Java基礎(chǔ)》",authors = {"zimo","mike"}, price = 59.9)
public class MyBook {
    @Book(name = "《SQL從入門到放棄》",authors = {"小白","遞歸"}, price = 9.99, address = "中國-上海")
    public static void main(String[] args) {

    }
}
  • 注解的特殊屬性名稱:value
    • value屬性姆坚,如果只有一個(gè)value屬性的情況下澳泵,使用value屬性的時(shí)候可以省略value名稱不寫!兼呵!
    • 如果有多個(gè)屬性兔辅,且多個(gè)屬性沒有默認(rèn)值,那么value是不能省略的
package com.zimo._02zhujie;
@interface Book{
    String value();
}
@interface Book1{
    String value();
    int age();
}
@interface Book2{
    String value();
    int age() default 18;
}

//@Book(value = "delete.action")
@Book("delete.action") // 可省略value不寫
public class MyBook {

}

@Book1(value = "delete.action", age = 12)   // 有多個(gè)必須全寫
@Book2("delete.action") // 若多個(gè)值都有默認(rèn)值
class MyBook1 {

}

元注解

元注解是sun公司提供的击喂,是用在自定義注解上的注解维苔,是用來注解自定義注解的

  • 元注解有兩個(gè):

    1. @Target:約束自定義注解只能在那些地方使用

      但是默認(rèn)的注解可以在類,方法懂昂,構(gòu)造器介时,成員變量,......使用

      ElementType:

      1. TYPE // 類、接口沸柔、枚舉類
      2. FIELD // 成員變量(包括:枚舉常量)
      3. METHOD // 成員方法
      4. PARAMETER // 方法參數(shù)
      5. CONSTRUCTOR // 構(gòu)造方法
      6. LOCAL_VARIABLE // 局部變量
      7. ANNOTATION_TYPE // 注解類
      8. PACKAGE // 可用于修飾:包
      9. TYPE_PARAMETER // 類型參數(shù)循衰,JDK 1.8 新增
      10. TYPE_USE // 使用類型的任何地方,JDK 1.8 新增
    2. @Retention:聲明注解的生命周期

      聲明注解的作用范圍:編譯時(shí)褐澎,運(yùn)行時(shí)

      RetentionPolicy:

      1. SOURCE // 源文件保留
      2. CLASS // 編譯期保留会钝,默認(rèn)值
      3. RUNTIME // 運(yùn)行期保留,可通過反射去獲取注解信息工三,開發(fā)常用

注解的解析

package com.zimo._04_ReNote;
import org.junit.Test;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Arrays;

@Target({ElementType.TYPE,ElementType.METHOD})  // 類和方法使用
@Retention(RetentionPolicy.RUNTIME) // 永久存活
@interface Book{
    String value();
    double price() default 100;
    String[] author();
}
@Book(value = "《Java基礎(chǔ)》",price = 99.9, author = {"zimo","mike"})
class BookStore{
    @Book(value = "《MyBatis持久層框架》",price = 199.9, author = {"zimo","jack"})
    public void run(){

    }
}
public class ReNote {
    @Test
    public void parseClass(){
        // 解析注解
        // 1.定位Class類對象
        Class c = BookStore.class;
        // 2.判斷類上是否使用了某個(gè)注解
        if (c.isAnnotationPresent(Book.class)){
            // 3.獲取注解對象
            Book book = (Book) c.getDeclaredAnnotation(Book.class);
            System.out.println(book.value() + book.price() + Arrays.toString(book.author()));   // java基礎(chǔ)
        }

        // 1.1 定位方法對象
        Method run = c.getDeclaredMethod("run");
        // 1.2
        if (run.isAnnotationPresent(Book.class)){
            // 1.3 獲取注解對象
            Book book = (Book) c.getDeclaredAnnotation(Book.class);
            System.out.println(book.value() + book.price() + Arrays.toString(book.author()));   // mybatis
        }
    }
}

模擬Junt.Test方法

package com.zimo._05_MyTest;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

@Target(ElementType.METHOD) // 方法使用
@Retention(RetentionPolicy.RUNTIME)
@interface MyTest{

}

public class MyTestDemo {
    @MyTest
    public void test01(){
        System.out.println("1111");
    }
    public void test02(){
        System.out.println("2222");
    }
    @MyTest
    public void test03(){
        System.out.println("3333");
    }

    public static void main(String[] args) throws Exception{
        // 模擬測試類啟動(dòng)按鈕
        MyTestDemo myTestDemo = new MyTestDemo();
        // 1.得到類對象
        Class c = MyTestDemo.class;
        // 2.獲取類全部方法對象
        Method[] methods = c.getDeclaredMethods();
        // 3.遍歷全部方法
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyTest.class)){
                // 運(yùn)行此方法
                method.invoke(myTestDemo);
            }
        }
    }
}

動(dòng)態(tài)代理

動(dòng)態(tài)代理設(shè)計(jì)模式(讓別人替我們?nèi)プ瞿承┦拢?/p>

動(dòng)態(tài)代理只能為實(shí)現(xiàn)接口的實(shí)現(xiàn)類對象做代理(也可以只為接口做代理對象)

  • 開發(fā)步驟:
    1. 必須有接口
    2. 實(shí)現(xiàn)類要實(shí)現(xiàn)接口迁酸,定義自己的業(yè)務(wù)功能代碼
    3. 為業(yè)務(wù)功能做代理對象(動(dòng)態(tài)代理)
  • 小結(jié):
    • 動(dòng)態(tài)代理非常靈活,可以被任意的接口實(shí)現(xiàn)類對象做代理
    • 動(dòng)態(tài)代理可以為被代理對象的所有接口的所有方法做代理俭正,動(dòng)態(tài)代理可以在不改變方法源碼的情況下奸鬓,實(shí)現(xiàn)對方法功能的增強(qiáng)
    • 動(dòng)態(tài)代理類的字節(jié)碼(代理對象)在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無需程序員手工編寫它的源代碼
    • 動(dòng)態(tài)代理不僅簡化了編程工作掸读,而且提高了軟件系統(tǒng)的可擴(kuò)展性全蝶,因?yàn)镴ava反射機(jī)制可以生成任意類型的動(dòng)態(tài)代理類
    • 動(dòng)態(tài)代理同時(shí)也提高了開發(fā)效率
    • 缺點(diǎn):只針對接口或者接口的實(shí)現(xiàn)類對象做代理對象,普通類是不能做代理對象的
代理模式.png
package com.zimo._06_ActiveDemo;
/**
 * 業(yè)務(wù)接口
 */
public interface UserService {
    String login(String admin, String s);
    void deleteAll();
}
package com.zimo._06_ActiveDemo;
/**
 * 業(yè)務(wù)實(shí)現(xiàn)類
 */
public class UserServiceImpl implements UserService {

    @Override
    public String login(String admin, String s) {
        if ("admin".equals(admin) && "123456".equals(s))return "success";
        return "error";
    }

    @Override
    public void deleteAll() {
        System.out.println("del success");
    }
}
package com.zimo._06_ActiveDemo;

public class TestDemo {
    public static void main(String[] args) {
        // 1.創(chuàng)建一個(gè)業(yè)務(wù)對象
        //UserService userService = new UserServiceImpl();
        // 代理模式
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        String res = userService.login("admin", "123456");  // 走代理寺枉,不走原來的UserServiceImpl
        System.out.println(res);

        userService.deleteAll();    // 走代理
    }
}
package com.zimo._06_ActiveDemo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  代理對象:幫助我們做一個(gè)被代理的業(yè)務(wù)對象返回
 *  java.lang.reflect.Proxy:這是Java動(dòng)態(tài)代理機(jī)制的主類
 *  它提供了一個(gè)靜態(tài)方法來為一組接口的實(shí)現(xiàn)類動(dòng)態(tài)地生成代理類及其對象(newProxyInstance)
 *  參數(shù)一:類加載器:負(fù)責(zé)加載到時(shí)候做好的業(yè)務(wù)代理對象
 *  參數(shù)二:被代理業(yè)務(wù)對象的全部實(shí)現(xiàn)的接口,以便代理對象可以知道哪些方法做代理
 *  參數(shù)三:代理正真的執(zhí)行方法,也就是代理的處理邏輯
 */
public class ProxyUtil {
    /**
     * 做一個(gè)被代理的業(yè)務(wù)對象返回
     * @param userService
     * @return
     */
    public static UserService getProxy(UserServiceImpl userService){
        return (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            // 類加載器抑淫,類實(shí)現(xiàn)的接口,具體實(shí)現(xiàn)方法邏輯
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                // o:業(yè)務(wù)代理對象本身姥闪,一般用不到  method:當(dāng)前正在被代理執(zhí)行的方法  objects:執(zhí)行方法的參數(shù)

                // 添加時(shí)間性能分析,不用在每個(gè)方法中使用
                long startTime = System.currentTimeMillis();

                // 真正觸發(fā)方法執(zhí)行
                Object re = method.invoke(o, objects);

                long endTime = System.currentTimeMillis();
                System.out.println(endTime - startTime);

                return re;
            }
        });
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末始苇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子筐喳,更是在濱河造成了極大的恐慌催式,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件避归,死亡現(xiàn)場離奇詭異荣月,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)梳毙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門哺窄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人账锹,你說我怎么就攤上這事萌业。” “怎么了奸柬?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵生年,是天一觀的道長。 經(jīng)常有香客問我廓奕,道長抱婉,這世上最難降的妖魔是什么档叔? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蒸绩,結(jié)果婚禮上蹲蒲,老公的妹妹穿的比我還像新娘。我一直安慰自己侵贵,他們只是感情好届搁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窍育,像睡著了一般卡睦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漱抓,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天表锻,我揣著相機(jī)與錄音,去河邊找鬼乞娄。 笑死瞬逊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仪或。 我是一名探鬼主播确镊,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼范删!你這毒婦竟也來了蕾域?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤到旦,失蹤者是張志新(化名)和其女友劉穎旨巷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體添忘,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡采呐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搁骑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斧吐。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖靶病,靈堂內(nèi)的尸體忽然破棺而出会通,到底是詐尸還是另有隱情口予,我是刑警寧澤娄周,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站沪停,受9級特大地震影響煤辨,放射性物質(zhì)發(fā)生泄漏裳涛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一众辨、第九天 我趴在偏房一處隱蔽的房頂上張望端三。 院中可真熱鬧,春花似錦鹃彻、人聲如沸郊闯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽团赁。三九已至,卻和暖如春谨履,著一層夾襖步出監(jiān)牢的瞬間欢摄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工笋粟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怀挠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓害捕,卻偏偏與公主長得像绿淋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子尝盼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一躬它、概述 1、Java反射機(jī)制(Java-Reflect): 在運(yùn)行狀態(tài)中东涡,對于任意一個(gè)類冯吓,都能夠知道這個(gè)類中的所...
    年少懵懂丶流年夢閱讀 4,406評論 0 5
  • 1. Java反射機(jī)制概述 1.1 動(dòng)態(tài)語言與反射 動(dòng)態(tài)語言 是一類在運(yùn)行時(shí)可以改變其結(jié)構(gòu)的語言:例如新的函數(shù)、對...
    爾玉RGX閱讀 342評論 0 2
  • 一疮跑、概述 Java反射機(jī)制定義 Java反射機(jī)制是在運(yùn)行狀態(tài)中组贺,對于任意一個(gè)類,都能夠知道這個(gè)類中的所有屬性和方法...
    CoderZS閱讀 1,634評論 0 26
  • 一祖娘、Java 反射機(jī)制概述 1. 反射概述 Reflection (反射)是被視為 動(dòng)態(tài)語言 (動(dòng)態(tài)性是核心失尖,底...
    與樂為樂閱讀 137評論 0 0
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)渐苏、注意力掀潮、語言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析琼富,社會(huì)...
    Jenaral閱讀 5,719評論 0 5