Java高级技术

目录

前言

一、单元测试

1.1 Junit单元测试-快速入门

1.2 Junit框架的常见注解

二、反射

2.1 认识反射、获取类

2.2 获取类的构造器

2.3 获取类的成员变量

2.4 获取类的成员方法

2.5 作用、应用场景

三、注解

3.1 概述、自定义注解

3.2 元注解

3.3 注解的解析

3.4 应用场景

四、动态代理

4.1 程序为什么需要代理?代理长什么样?

4.2 解决实际问题、掌握使用代理的好处


前言

java高级技术笔记复盘【完】


一、单元测试

就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。

咱们之前是如何进行单元测试的?有啥问题?

  • 只能在main方法编写测试代码,去调用其他方法进行测试。
  • 无法实现自动化测试,一个方法测试失败,可能影响其他方法的测试。
  • 无法得到测试的报告,需要程序员自己去观察测试是否成功。

Junit单元测试框架

优点

  • 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立
  • 不需要程序员去分析测试的结果,会自动生成测试报告出来

1.1 Junit单元测试-快速入门

需求

  • 某个系统,有多个业务方法,请使用Junit单元测试框架,编写测试代码,完成对这些方法的正确性测试。

具体步骤

  • 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了
  • 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值)
  • 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试;
  • 开始测试:选中测试方法,右键选择“JUnit运行”,如果测试通过则是绿色;如果测试失败,则是红色

StringUtilTest.class

package com.ithema.d1_junit;

import org.junit.Assert;
import org.junit.Test;

//测试类
public class StringUtilTest {

    @Test
    //必须是公开的方法,且是无返回值,无参数的 测试方法, 否则会出bug。方法名建议前面加test并采用驼峰命名的方法。 上面加@Test注解
    public void testPrintNumber(){
        StringUtil.printNumber("nihao");
        StringUtil.printNumber(null);
    }


    @Test
    public void testGetMaxIndex(){
        int index1=StringUtil.getMaxIndex("nihao");
        System.out.println(index1);
        int index2=StringUtil.getMaxIndex(null);
        System.out.println(index2);

        //断言机制:程序员可以通过预测业务方法的结果
        Assert.assertEquals("方法内部有bug",4,index1);

    }
}

printNumber.class

package com.ithema.d1_junit;

//字符串工具类
public class StringUtil {


    public static  void printNumber(String name){
        if(name==null){
            System.out.println(0);
            return;//停掉方法
        }
        System.out.println("名字的长度是:"+name.length());
    }

   //求字符串的最大索引
   public static int getMaxIndex(String data){
        if(data==null){
            return -1;
        }
        return data.length()-1;
   }
}

1.2 Junit框架的常见注解

  • 在测试方法执行前执行的方法,常用于:初始化资源。
  • 在测试方法执行完后再执行的方法,常用于:释放资源。 

 StringUtil.class

package com.ithema.d1_junit;

//字符串工具类
public class StringUtil {

    public static  void printNumber(String name){
        if(name==null){
            System.out.println(0);
            return;//停掉方法
        }
        System.out.println("名字的长度是:"+name.length());
    }

   //求字符串的最大索引
   public static int getMaxIndex(String data){
        if(data==null){
            return -1;
        }
        return data.length()-1;
   }
}

StringUtilTest.class 

package com.ithema.d1_junit;

import org.junit.*;

//测试类
public class StringUtilTest {
  //BeforeClass 和 AfterClass 必须是静态的测试方法
    @BeforeClass
    public static void test11(){
        System.out.println("================================================================BeforeClass     test11被执行了==============================================================="+'\n');

    }

    @AfterClass
    public static void test12(){
        System.out.println("================================================================AfterClass     test12被执行了==============================================================="+'\n');

    }

    @Before
    public void test1(){
        System.out.println("================================================================Before     test1被执行了==============================================================="+'\n');
    }

    @After
    public void test2(){
        System.out.println("================================================================After     test2被执行了==============================================================="+'\n');
    }

    @Test
    //必须是公开的方法,且是无返回值,无参数的 测试方法, 否则会出bug。方法名建议前面加test并采用驼峰命名的方法。 上面加@Test注解
    public void testPrintNumber(){
        StringUtil.printNumber("nihao");
        StringUtil.printNumber(null);
    }


    @Test
    public void testGetMaxIndex(){
        int index1=StringUtil.getMaxIndex("nihao");
        System.out.println(index1);
        int index2=StringUtil.getMaxIndex(null);
        System.out.println(index2);

        //断言机制:程序员可以通过预测业务方法的结果
        Assert.assertEquals("方法内部有bug",4,index1);

    }
}

二、反射

2.1 认识反射、获取类

反射:就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)

获取Class对象的三种方式:

  • Classc1=类名.class
  • 调用Class提供方法:public staticClass forName(String package);
  • Object提供的方法:publicClass getClass();Class c3=对象.getClass();

Test1Class.class 

package com.itheima.d2_reflect;

public class Test1Class {
    public static void main(String[] args) throws Exception {
        Class c1=Student.class;
        System.out.println(c1.getName());//全类名
        System.out.println(c1.getSimpleName());//简名 Student

        Class c2 = Class.forName("com.itheima.d2_reflect.Student");
        System.out.println(c1 == c2);

        Student s=new Student();
        Class c3= s.getClass();
        System.out.println(c3 == c2);

    }
}

Student.class

package com.itheima.d2_reflect;

public class Student {
}

2.2 获取类的构造器

 获取类构造器的作用:依然是初始化一个对象返回

Cat.class

package com.itheima.d2_reflect;

public class Cat {
    private String name;
    private int age;

    private Cat() {
    }

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Test2Constructor.class 

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructors() throws Exception {
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;

        // 2、获取类的全部构造器
        //只能获取公共的public的构造器
        //Constructor [] constructors = c.getConstructors();
        //可以获得包括私有的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //3、遍历数组中的每个构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "---->" + constructor.getParameterCount());
        }
    }

    @Test
    public void testGetConstructor() throws Exception {
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2、获取某个构造器:无参数构造器
        //只能获取公共的public的构造器
        // Constructor constructor=c.getConstructor();
        Constructor constructor = c.getDeclaredConstructor();
        System.out.println(constructor.getName() + "===========>" + constructor.getParameterCount());


        //3、获取有参数构造器
        Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName() + "===========>" + constructor2.getParameterCount());

    }
}

Cat.class 

package com.itheima.d2_reflect;

public class Cat {
    private String name;
    private int age;

    private Cat() {
        System.out.println("无参数构造器执行了");
    }

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Test2Constructor.class 

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructors() throws Exception {
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;

        // 2、获取类的全部构造器
        //只能获取公共的public的构造器
        //Constructor [] constructors = c.getConstructors();
        //可以获得包括私有的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //3、遍历数组中的每个构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "---->" + constructor.getParameterCount());
        }

    }

    @Test
    public void testGetConstructor() throws Exception {
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2、获取某个构造器:无参数构造器
        //只能获取公共的public的构造器
        // Constructor constructor1=c.getConstructor();
        Constructor constructor1 = c.getDeclaredConstructor();
        System.out.println(constructor1.getName() + "===========>" + constructor1.getParameterCount());

        constructor1.setAccessible(true);//禁止检査访问权限
        Cat cat = (Cat) constructor1.newInstance();
        System.out.println(cat);



        //3、获取有参数构造器
        Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName() + "===========>" + constructor2.getParameterCount());
        constructor1.setAccessible(true);//禁止检査访问权限
        Cat cat1 = (Cat) constructor2.newInstance("叮当猫",3);
        System.out.println(cat1);


    }
}

2.3 获取类的成员变量

Cat.class 

package com.itheima.d2_reflect;

public class Cat {
    public static int a;
    public  static final String COUNTRY="中国";
    private String name;
    private int age;

    private Cat() {
        System.out.println("无参数构造器执行了");
    }

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 Test3Field.class

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

public class Test3Field {

    @Test
    public void testGetFiled() throws Exception {
        //1、反射第一步:必须是先得到类的Class对参
        Class c = Cat.class;
        //2、获取类的全部成员变量。
        Field[] fields = c.getDeclaredFields();
        //3、遍历这个成员变量数组
        for (Field field : fields) {
            System.out.println(field.getName() + "===============>" + field.getType());
        }


        //4、定位某个成员变量
        Field fName=c.getDeclaredField("name");
        System.out.println(fName.getName() + "===============>" + fName.getType());
        Field fAge=c.getDeclaredField("age");
        System.out.println(fAge.getName() + "===============>" + fAge.getType());

    }


}

  获取到成员变量的作用:依然是赋值、取值。

Test3Field.class 

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

public class Test3Field {

    @Test
    public void testGetFiled() throws Exception {
        //1、反射第一步:必须是先得到类的Class对参
        Class c = Cat.class;
        //2、获取类的全部成员变量。
        Field[] fields = c.getDeclaredFields();
        //3、遍历这个成员变量数组
        for (Field field : fields) {
            System.out.println(field.getName() + "===============>" + field.getType());
        }


        //4、定位某个成员变量
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "===============>" + fName.getType());
        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "===============>" + fAge.getType());


        //赋值
        Cat cat = new Cat();
        fName.setAccessible(true);// 禁止访问控制权限
        fName.set(cat, "加菲猫");
        fAge.setAccessible(true);// 禁止访问控制权限
        fAge.set(cat, 3);
        System.out.println(cat);

        //取值
        String name = (String) fName.get(cat);
        System.out.println(name);

        Integer age = (Integer) fAge.get(cat);
        System.out.println(age);
    }
}

2.4 获取类的成员方法

Cat.class 

package com.itheima.d2_reflect;

public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;

    public Cat() {
        System.out.println("无参数构造器执行了");
    }

    private void run() {
        System.out.println("🐱跑的快");
    }

    public void eat() {
        System.out.println("🐱吃的多");
    }

    private String eat(String name) {
        return "🐱吃的多" + name;
    }


    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

TestGetMethods.class 

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

public class Test4Method {

    @Test
    public void testGetMethods() throws Exception {
        //1、反射第一步:必须是先得到类的Class对参
        Class c = Cat.class;

        //2、获取类的全部成员方法。
        Method[] methods = c.getDeclaredMethods();
        //3、遍历这个数组中的每个方法对象
        for (Method method : methods) {
            System.out.println(method.getName()+"---->"
                    +method.getParameterCount()+
                    "---->"+method.getReturnType());
        }

        //获取某个方法的对象
        Method run=c.getDeclaredMethod("run");//拿run方法 且 无参数
        System.out.println(run.getName()+"---->"
                +run.getParameterCount()+
                "---->"+run.getReturnType());


        Method eat=c.getDeclaredMethod("eat",String.class);//拿run方法 且 无参数
        System.out.println(eat.getName()+"---->"
                +eat.getParameterCount()+
                "---->"+eat.getReturnType());
    }

}

 成员方法的作用:依然是执行

 Test4Method.class

package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

public class Test4Method {

    @Test
    public void testGetMethods() throws Exception {
        //1、反射第一步:必须是先得到类的Class对参
        Class c = Cat.class;

        //2、获取类的全部成员方法。
        Method[] methods = c.getDeclaredMethods();
        //3、遍历这个数组中的每个方法对象
        for (Method method : methods) {
            System.out.println(method.getName()+"---->"
                    +method.getParameterCount()+
                    "---->"+method.getReturnType());
        }

        //获取某个方法的对象
        Method run=c.getDeclaredMethod("run");//拿run方法 且 无参数
        System.out.println(run.getName()+"---->"
                +run.getParameterCount()+
                "---->"+run.getReturnType());


        Method eat=c.getDeclaredMethod("eat",String.class);//拿run方法 且 无参数
        System.out.println(eat.getName()+"---->"
                +eat.getParameterCount()+
                "---->"+eat.getReturnType());

        Cat cat=new Cat();
        run.setAccessible(true);//禁止检查访问权限
        Object rs=run.invoke(cat);//调用无参数的run方法,用cat对象触发调用
        System.out.println(rs);

        eat.setAccessible(true);//禁止检查访问权限
        String rs2= (String) eat.invoke(cat,"🐟");
        System.out.println(rs2);

    }
}

2.5 作用、应用场景

反射的作用?

  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装性
  • 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。

 实现步骤

  •  定义一个方法,可以接收任意对象。
  • 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
  • 遍历成员变量,然后提取成员变量在该对象中的具体值。
  • 把成员变量名、和其值,写出到文件中去即可。

Student.class

package com.itheima.d2_reflect;

public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", height=" + height +
                ", hobby='" + hobby + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public Student() {
    }

    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }
}

Teacher.class

package com.itheima.d2_reflect;

public class Teacher {
    private String name;
    private double salary;

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public Teacher() {
    }

    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
}

ObjectFrame.class

package com.itheima.d2_reflect;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class ObjectFrame {
    // 目标:保存任意对象的字段和其数据到文件中去


    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("D:\\code\\javasepro\\junit-reflect-annotation-proxy-app\\src\\data.txt", true));
        //1、obj是任意对象,到底有多少个字段要保存。
        Class c = obj.getClass();
        String cName = c.getSimpleName();
        ps.println("---------------------------" + cName + "------------------");
        //2、从这个类中提取它的全部成员变量
        Field[] fields = c.getDeclaredFields();

        //3、遍历每个成员变量
        for (Field field : fields) {
            //4、拿到成员变量的每个名字
            String name = field.getName();

            //5、拿到这个成员变量在对象中的数据
            field.setAccessible(true);//禁止检查访问控制
            String value = field.get(obj) + " ";
            ps.println(name + " = " + value);
        }
        ps.close();
    }
}

TestFrame.class

package com.itheima.d2_reflect;

import org.junit.Test;

public class Test5Frame {

    @Test
    public void save() throws Exception {
        Student s1 = new Student("张三", 45, '男', 180.2, "打游戏");
        Teacher t1 = new Teacher("李四", 1922.02);

        //需求:把任意对象的字段名和其对应的值等信息,保存到文件中去。
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);

    }
}

三、注解

3.1 概述、自定义注解

注解(Annotation)

  • 就是Java代码里的特殊标记,比如:@Override、@Test等
  • 作用是:让其他程序根据注解信息来决定怎么执行该程序
  • 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处

自定义注解

  • 就是自己定义注解

MyTest.Annotation 

package com.itheima.d3_Annotation;

public @interface MyTest1 {
    String aaa();

    boolean bbb() default true;

    String[] ccc();
}

AnntationTest.class

package com.itheima.d3_Annotation;

@MyTest1(aaa = "张三", ccc = {"HTML,JAVA"})
public class AnnotationTest1 {
    @MyTest1(aaa = "李四", bbb = false, ccc = {"Python", "前端", "Java"})
    public void test1() {

    }
}

特殊属性名: value

  • 如果注解中只有一个value属性,使用注解时,value名称可以不写!! 

MyTest2.class

package com.itheima.d3_Annotation;

public @interface MyTest2 {
    String value();//特殊属性

}

AnntationTest.class

package com.itheima.d3_Annotation;

@MyTest1(aaa = "张三", ccc = {"HTML,JAVA"})
//@MyTest2(value = "王五")
@MyTest2("王五")
public class AnnotationTest1 {
    @MyTest1(aaa = "李四", bbb = false, ccc = {"Python", "前端", "Java"})
    public void test1() {

    }
}

  • 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的
  • @注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口。

3.2 元注解

指的是:修饰注解的注解

 MyTest.Annotation

package com.itheima.d3_Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})// 当前被修饰的注解只能用在类和方法上。
public @interface MyTest3 {
}

AnntationTest.class

package com.itheima.d3_Annotation;

@MyTest3()
public class AnnotationTest2 {

    @MyTest3()
    public void test(){
    }
}

3.3 注解的解析

什么是注解的解析?
就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来

如何解析注解?

  • 指导思想:要解析谁上面的注解,就应该先拿到谁。
  • 比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解
  • 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
  • Class、Method、Field,Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。

 MyTets4.Annotation

package com.itheima.d3_Annotation;

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

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {

    String value();

    double aaa() default 100;

    String[] bbb();
}

Demo.class

package com.itheima.d3_Annotation;
@MyTest4(value = "蜘蛛精",aaa=99.5,bbb={"至尊宝","张三"})
public class Demo {

    @MyTest4(value = "孙悟空",aaa=199.9,bbb={"紫霞","李四"})
    public void test1(){


    }
}

AnnotationTest3.class

package com.itheima.d3_Annotation;


import org.junit.Test;

import java.lang.reflect.Method;
import java.util.Arrays;

public class AnnotationTest3 {

    @Test
    public void parseClass() {
        //1、先得到Class对象
        Class c = Demo.class;
        //2、解析类上的注解
        //判断这个类上是否包含了某个注解
        //判断这个类上是否包含了这个类的类型
        if(c.isAnnotationPresent(MyTest4.class)){
            MyTest4 myTest4 = (MyTest4) c.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }

    @Test
    public void parseMethod() throws Exception {
        //1、先得到Class对象
        Class c = Demo.class;
        Method m = c.getDeclaredMethod("test1");
        //2、解析方法上的注解
        //判断这个方法上是否包含了某个注解
        //判断这个方法上是否包含了这个方法的类型
        if (c.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4 = (MyTest4) c.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}

3.4 应用场景

 MyTest.Annotation

package com.itheima.d3_Annotation;

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

@Target(ElementType.METHOD)// 注解只能注解方法。
@Retention(RetentionPolicy.RUNTIME)// 让当前注解可以一直存活着。
public @interface MyTest {


}

AnnotationTest4.class 

package com.itheima.d3_Annotation;


import java.lang.reflect.Method;

public class AnnotationTest4 {

    //    @MyTest
    public void test1() {
        System.out.println("=======test1=======");
    }

    @MyTest
    public void test2() {
        System.out.println("=======test2=======");
    }

    //    @MyTest
    public void test3() {
        System.out.println("=======test3=======");
    }

    @MyTest
    public void test4() {
        System.out.println("=======test4=======");
    }


    public static void main(String[] args) throws Exception {
        AnnotationTest4 a = new AnnotationTest4();
        //启动程序
        //1、得到Class对象
        Class c = AnnotationTest4.class;

        //2、提取这个类中的全部成员方法
        Method[] methods = c.getDeclaredMethods();

        //3、遍历数组中的每个方法,看方法上是否存在MyTest注解,如果存在触发该方法执行
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyTest.class)) {
                //说明当前方法上存在@MyTest,触发当前方法执行
                method.invoke(a);
            }
        }
    }
}

四、动态代理

4.1 程序为什么需要代理?代理长什么样?

 Start.interface

package com.itheima.d4_proxy;

public interface Start {
    String sing(String name);

    void dance();
}

BigStart.class

package com.itheima.d4_proxy;

public class BigStart implements Start {
    private String name;


    public BigStart(String name) {
        this.name = name;
    }


    public String sing(String name) {
        System.out.println(this.name + "正在唱:" + name);
        return "谢谢! 谢谢!";
    }

    public void dance() {
        System.out.println(this.name + "正在优美的跳舞~~");
    }
}

ProxyUtil.class

package com.itheima.d4_proxy;

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

public class ProxyUtil {
    public static Start createProxy(BigStart bigStart) {
        //选择反射下的Proxy类
        /*
        * ClassLoader loader,
          Class<?>[] interfaces,
          InvocationHandler h
         *
         * 参数1:用于指定一个加载器
         * 参数2:指定生成的代理长什么样子,也就是有哪些方法
        *  参数3:用来指定生成的代理对象要干什么事情
        * */
        //
        Start startProxy = (Start) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Start.class},
                new InvocationHandler() {
                    @Override// 回调方法
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //代理对象要做的事情,会在这里写代码
                        if (method.getName().equals("sing")) {
                            System.out.println("准备话筒");
                            return method.invoke(bigStart, args);
                        } else if (method.getName().equals("dance")) {
                            System.out.println("准备场地");
                            return method.invoke(bigStart, args);
                        } else {
                            return method.invoke(bigStart, args);
                        }
                    }

                });
        return startProxy;
    }
}

Test.class

package com.itheima.d4_proxy;

public class Test {
    public static void main(String[] args) {

        BigStart s = new BigStart("zhang san");
        Start startProxy = ProxyUtil.createProxy(s);
        String rs = startProxy.sing("好日子");
        System.out.println(rs);
        startProxy.dance();
    }
}

4.2 解决实际问题、掌握使用代理的好处

UserService.interface

package com.itheima.d5_proxy2;

public interface UserService {
    //登录功能
    void login(String loginName, String passWord) throws Exception;

    //删除用户
    void deleteUsers() throws Exception;

    //查询用户,返回数组形式
    String[] selectUsers() throws Exception;
}

 UserSerivceImpl.class

package com.itheima.d5_proxy2;

public class UserServiceImpl implements UserService {

    @Override
    public void login(String loginName, String passWord) throws Exception {

        if ("admin".equals(loginName) && "123456".equals(passWord)) {
            System.out.println("您登录成功!");
        } else {
            System.out.println("您登录失败!");
        }
        Thread.sleep(1000);

    }

    @Override
    public void deleteUsers() throws Exception {
        System.out.println("成功删除了1万个用户~");
        Thread.sleep(1500);
    }

    @Override
    public String[] selectUsers() throws Exception {
        System.out.println("查询除了3个用户:");
        String[] names = {"张三", "李四", "王五"};
        Thread.sleep(500);
        return names;
    }
}

ProxyUtil.class

package com.itheima.d5_proxy2;

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

public class ProxyUtil {
    public static UserService createProxy(UserService userService) {
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{UserService.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("login") || method.getName().equals("deleteUsers") || method.getName().equals("selectUsers")) {
                            long startTime = System.currentTimeMillis();
                            Object rs = method.invoke(userService, args);
                            long endTime = System.currentTimeMillis();
                            System.out.println(method.getName() + "当前方法执行了:" + (endTime - startTime) / 1000.0 + "s");
                            return rs;
                        } else {
                            Object rs = method.invoke(userService, args);
                            return rs;
                        }
                    }
                });
        return userServiceProxy;

    }
}

Test.class

package com.itheima.d5_proxy2;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws Exception {
        //1、创建用户业务对象。
        UserService userService = ProxyUtil.createProxy(new UserServiceImpl());

        // 2、调用用户业务的功能。
        userService.login("admin", "123456");
        System.out.println("==================================================================");
        userService.deleteUsers();
        System.out.println("==================================================================");
        String[] names = userService.selectUsers();
        System.out.println("查询到的用户是:" + Arrays.toString(names));
        System.out.println("==================================================================");
    }

}

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值