JAVA012【反射,注解,junit,动态代理】

DAY12

1.反射概述

  • 反射是一种机制,通过该机制可以在程序运行过程中对类进行解剖并操作类中的成员:构造方法,成员方法,成员变量

    • 操作构造方法:创建类的对象
    • 操作成员方法:调用成员方法
    • 操作成员变量:给成员变量赋值和取值
  • 反射的应用场景:开发IDE(集成开发环境):比如IDEA,Eclipse

    • 开发框架:spring mybatis
  • package com.itheima._01反射概述;
    
    /**
        目标:理解反射的概念
    
        讲解:
             1. 什么是反射
                反射是一种机制,通过该机制可以在程序运行过程中对类进行解剖并操作
            类中的成员:构造方法,成员方法,成员变量。
                操作构造方法:创建类的对象
                操作成员方法:调用成员方法
                操作成员变量:给成员变量赋值和取值
    
             2. 反射的应用场景
                开发IDE(集成开发环境): 比如IDEA,Eclipse
                开发框架:spring,mybatis,springmvc
                学习框架:spring,mybatis,springmvc(重点)
    
             3. 反射的前提条件
                必须先获得字节码文件对象:Class对象
    
        小结:
            1. 什么是反射
                反射是一种机制,通过该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员。
                通俗说:反射就是换一种创建对象,调用方法,给成员变量赋值和取值的方法。
     */
    public class Demo01 {
        public static void main(String[] args) {
    
        }
    }
    

2.获取Class对象

package com.itheima._02获取Class对象;

/**
    目标:掌握Class对象的三种获取方式

    讲解
        1. Class对象的三种获取方式
            通过类名.class获取
            通过对象名.getClass()获取
            通过Class.forName("类全名字符串")获取

    小结:
        1. Class对象的三种获取方式
            类名.class
            对象名.getClass()
            Class.forName("类全名字符串")

        2. 每个类的Class对象有几个?
            1个 单例对象
 */
public class Demo02 {
    public static void main(String[] args) throws Exception {
        // 通过类名.class获取
        Class c1 = Student.class;

        // 通过对象名.getClass()获取
        // 创建学生对象
        Student stu = new Student();
        Class c2 = stu.getClass();

        // 通过Class.forName("类全名字符串")获取
        Class c3 = Class.forName("com.itheima._02获取Class对象.Student");

        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
    }
}

package com.itheima._02获取Class对象;

public class Student {

}



3.获取Class对象信息

package com.itheima._03获取Class对象信息;

import com.itheima._02获取Class对象.Student;

/**
    目标:通过Class对象的方法获取类名和类全名字符串

    讲解:
        1. 获取Class对象信息的两个方法
            String getName();  获得类全名字符串
            String getSimpleName(); 获得类名字符串

    小结:
        1. 获得类名的方法:getSimpleName

        2. 获得类全名字符串的方法:getName
 */
public class Demo03 {
    public static void main(String[] args){
        // 获得Class对象
        Class c = Student.class;
        System.out.println(c.getSimpleName()); // Student
        System.out.println(c.getName()); // com.itheima._02获取Class对象.Student
    }
}

4.反射操作构造方法

package com.itheima._04反射操作构造方法;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
    目标:利用反射操作构造方法:创建类的对象

    讲解:
        1. Constructor类概述
            类中的每一个构造方法都是Constructor类的对象,反射操作构造方法
        就是要获得构造方法对应的Constructor对象:通过Constructor对象创建类的对象

        2. 如何获取Constructor对象
            * Constructor getConstructor(Class... parameterTypes)
                *  根据参数类型获得构造方法对象:Constructor对象
                *  只能操作public修饰的构造方法
            * Constructor getDeclaredConstructor(Class... parameterTypes)
                *  根据参数类型获得构造方法对象:Constructor对象
                *  包括private修饰的构造方法

            * Constructor[] getConstructors()
            * Constructor[] getDeclaredConstructors()

        3. Constructor对象常用方法
            * T newInstance(Object... args)
                * 根据参数创建对象
            * void setAccessible(true)
                * 设置是否取消权限检查 ==> 暴力反射
                * true:取消检查权限
                * false:权限检查

    小结:
        反射操作构造方法的目的什么:创建类的对象

 */
public class Demo04 {
    /*
      反射操作public无参数构造方法
   */
    @Test
    public void test01() throws Exception{
        // Student obj = new Student();

        // 获得Class对象
        Class c = Student.class;
        // 获得无参数构造方法对应的Constructor对象
        Constructor cons = c.getConstructor();
        // 创建学生对象:触发无参数构造执行
        Object obj = cons.newInstance();
        System.out.println(obj);
    }

    /*
        反射操作public有参数构造方法
     */
    @Test
    public void test02() throws Exception {
        // 获得Class对象
        Class c = Student.class;
        // 根据参数类型获得Constructor对象
        Constructor cons = c.getDeclaredConstructor(String.class,int.class,String.class);
        // 创建学生对象
        Object obj = cons.newInstance("jack", 20,"女");
        System.out.println(obj);
    }

    /*
        反射操作private有参数构造方法
     */
    @Test
    public void test03() throws Exception {
        // 获得Class对象
        Class c = Student.class;
        // 根据参数类型获得Constructor对象
        Constructor cons = c.getDeclaredConstructor(String.class,int.class);
        // 设置取消权限检查:暴力反射
        cons.setAccessible(true);
        // 创建学生对象
        Object obj = cons.newInstance("jack", 20);

        System.out.println(obj);
    }
}
package com.itheima._04反射操作构造方法;

public class Student {
    private String name;
    private int age;
    private String gender;

    public Student(String name, int age, String gender) {
        System.out.println("三个参数的构造方法");
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    private Student(String name, int age) {
        System.out.println("两个参数的构造方法");
        this.name = name;
        this.age = age;
    }

    // 每个类的构造方法都对应一个Constructor对象
    public Student() {
        System.out.println("无参数构造方法");
    }

    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 String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    // 普通方法
    public void eat(){
        System.out.println("吃个蛋...");
    }

    private void sleep(int hour){
        System.out.println("睡了"+hour+"小时");
    }

    public String study(int hour,String name){
        System.out.println("学习了"+hour+"小时,和"+name+"学习");
        return "abc";
    }

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

5.反射操作成员方法

package com.itheima._05反射操作成员方法;

import com.itheima._04反射操作构造方法.Student;
import org.junit.Test;

import java.lang.reflect.Method;

/**
    目标:利用反射操作成员方法:调用方法

    讲解:
        1. Method类概述
            类中的每个成员方法都是Method类对象,反射操作成员方法就是要获得该成员方法对应的
            Method对象:通过Method对象调用该成员方法

        2. 如何获得Method对象
             Method getMethod(String methodName,Class...args)
                根据方法名和参数类型获得Method对象,只能操作public修饰的
             Method getDeclaredMethod(String methodName,Class...args)
                根据方法名和参数类型获得Method对象,包括private修饰的

             Method[] getMethods()
                 获得当前类的所有成员方法对象:包括父类的,不包括private修饰的
             Method[] getDeclaredMethods()
                 获得当前类的所有成员方法对象:不包括父类的,包括private修饰的


        3. Method对象常用方法
            Object invoke(Object obj, Object... args)
                * 调用方法
                * obj:调用哪个对象的方法
                * args:调用方法时要传递的参数
                * 返回值为被调用方法的返回值
            void setAccessible(true)
                 * 设置是否取消权限检查 ==> 暴力反射
                 * true:取消检查权限
                 * false:权限检查

    小结:
        反射操作成员方法的目的什么:调用方法

 */
public class Demo05 {
    /*
     * 反射操作无参数成员方法
     */
    @Test
    public void test01() throws Exception{
        /*Student stu = new Student();
        stu.eat();*/

        // 获得Class对象
        Class c = Student.class;
        // 创建学生对象
        Student stu = (Student) c.getConstructor().newInstance();
        // 根据方法名获得Method对象
        Method m = c.getMethod("eat");
        // 通过Method对象调用eat方法
        Object result = m.invoke(stu);
        System.out.println("result = " + result); // null
    }


    /*
        反射操作有参数成员方法
     */
    @Test
    public void test02() throws Exception{
        // 获得Class对象
        Class c = Student.class;
        // 创建对象
        Student stu = (Student) c.getConstructor().newInstance();
        // 根据方法名获得参数类型获得Method对象
        Method m = c.getMethod("study", int.class, String.class);
        // 通过Method对象调用study方法
        Object result = m.invoke(stu, 10,"rose");
        System.out.println("result = " + result); // abc
        System.out.println("---------------------------");

        // 操作private修饰的成员方法
        Method sleepMethod = c.getDeclaredMethod("sleep", int.class);
        // 暴力反射
        sleepMethod.setAccessible(true);
        // 调用对象stu的sleep方法
        sleepMethod.invoke(stu, 8);
    }

    /*
        反射之获得所有成员方法对象
     */
    @Test
    public void test03() {
        // 获得Class对象
        Class c = Student.class;
        // 获得当前类的所有成员方法对象:包括父类的,不包括private修饰的
        // Method[] methods = c.getMethods();

        // 获得当前类的所有成员方法对象:不包括父类的,包括private修饰的
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

6.反射操作成员变量

package com.itheima._06反射操作成员变量;

import com.itheima._04反射操作构造方法.Student;
import org.junit.Test;

import java.lang.reflect.Field;

/**
    目标:利用反射操作成员变量:赋值和取值

    讲解:
        1. Field类概述
            类中的每一个成员变量都是一个Field对象,反射操作成员变量就是要获得成员变量对应
        的Field对象:通过Field对象给成员变量赋值和取值

        2. 如何获得Field对象
            Field getDeclaredField(String name)
                根据成员变量名称获得Field对象

            Field[] getDeclaredFields()
                获得当前类的所有成员变量的Field对象

        3. Field对象常用方法
             void set(Object obj, Object value)
             void setInt(Object obj, int i)
             void setLong(Object obj, long l)
             void setBoolean(Object obj, boolean z)
             void setDouble(Object obj, double d)
                给对象obj的成员变量赋值

             Object get(Object obj)
             int getInt(Object obj)
             long getLong(Object obj)
             boolean getBoolean(Object ob)
             double getDouble(Object obj)
                获得对象obj对应成员变量的值

             void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。
             Class getType(); 获取属性的类型,返回Class对象。

    小结:
        反射操作成员变量的目的什么:给成员变量赋值和取值
 */
public class Demo06 {
    /*
       反射操作成员变量
    */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class c = Student.class;
        // 创建学生对象
        Object obj = c.getConstructor().newInstance();
        System.out.println("obj = " + obj);
        // 根据成员变量名称获得Field对象
        Field nameField = c.getDeclaredField("name");
        // 暴力反射
        nameField.setAccessible(true);
        // 给成员变量name赋值
        nameField.set(obj,"lisi");

        // 获得成员变量age对应的Field对象
        Field ageField = c.getDeclaredField("age");
        // 暴力反射
        ageField.setAccessible(true);
        // 给对象obj的成员变量age赋值
        ageField.setInt(obj, 20);

        // 获得成员变量age的值
        System.out.println(ageField.getInt(obj)); // 20

        System.out.println("obj = " + obj);
    }

    /*
        反射之获得所有成员变量对象
     */
    @Test
    public void test02() {
        // 获得Class对象
        Class c = Student.class;
        // 获得所有成员变量对象
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

7.反射综合案例

package com.itheima._07反射综合案例;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Properties;

/**
    目标:能够使用反射技术根据配置信息创建对象

    案例说明
         1. 有配置⽂件stu.properties,存储在当前模块下,内容如下:

             class=com.itheima.bean.Student
             name=rose
             gender=女
             age=18

         2.根据配置⽂件信息创建一个学生对象。
            Student stu = new Student("rose","女",18);

    实现步骤:
        1. 创建属性集合对象:Properties
        2. 加载配置文件中的数据到属性集合中
        3. 根据class获得类全名字符串
        4. 根据类全名字符从获得Class对象
        5. 根据Class对象获得Constructor对象
        6. 通过Constructor对象创建类的对象

 */
public class Demo07 {
    public static void main(String[] args)throws Exception{
        // 1. 创建属性集合对象:Properties
        Properties info = new Properties();
        // 2. 加载配置文件中的数据到属性集合中
        /*FileInputStream fis = new FileInputStream("xxx.properties");
        info.load(fis);
        fis.close();*/

        // 获得字节输入流关联配置文件
        /*
            Class对象的方法:
            public InputStream getResourceAsStream(String name)
               从src目录下查找资源文件,根据资源文件创建字节输入流对象
               name必须以 / 开头
         */
        // InputStream in = Demo07.class.getResourceAsStream("/stu.properties");
        // 加载配置文件的数据到集合中
        info.load(Demo07.class.getResourceAsStream("/stu.properties"));
        System.out.println(info);

        // 3. 根据class获得类全名字符串
        String className = info.getProperty("class");
        // 4. 根据类全名字符从获得Class对象
        Class c = Class.forName(className);
        // 5. 根据Class对象获得Constructor对象
        Constructor cons = c.getConstructor();
        // 6. 通过Constructor对象创建类的对象
        Object obj = cons.newInstance();

        System.out.println(obj);

        // 根据name获得对应值
        String name = info.getProperty("name"); // rose
        // 根据name获得对应的成员变量对象
        Field nameField = c.getDeclaredField("name");
        // 暴力反射
        nameField.setAccessible(true);
        // 给对象obj的成员变量name赋值
        nameField.set(obj,name);
        System.out.println("--------------------");

        // 根据gender获得对应值
        String gender = info.getProperty("gender"); // woman
        // 根据gender获得对应的成员变量对象
        Field genderField = c.getDeclaredField("gender");
        // 暴力反射
        genderField.setAccessible(true);
        // 给对象obj的成员变量gender赋值
        genderField.set(obj,gender);

        System.out.println(obj);
    }
}
package com.itheima._07反射综合案例;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Properties;
import java.util.Set;

/**
    目标:能够使用反射技术根据配置信息创建对象

    案例说明
         1. 有配置⽂件stu.properties,存储在当前模块下,内容如下:

             class=com.itheima.bean.Student
             name=rose
             gender=女
             age=18

         2.根据配置⽂件信息创建一个学生对象。
            Student stu = new Student("rose","女",18);

    实现步骤:
        1. 创建属性集合对象:Properties
        2. 加载配置文件中的数据到属性集合中
        3. 根据class获得类全名字符串
        4. 根据类全名字符从获得Class对象
        5. 根据Class对象获得Constructor对象
        6. 通过Constructor对象创建类的对象

 */
public class Demo071 {
    public static void main(String[] args)throws Exception{
        // 1. 创建属性集合对象:Properties
        Properties info = new Properties();
        // 2. 加载配置文件中的数据到属性集合中
        info.load(Demo071.class.getResourceAsStream("/book.properties"));
        System.out.println(info);

        // 3. 根据class获得类全名字符串
        String className = info.getProperty("class");
        // 4. 根据类全名字符从获得Class对象
        Class c = Class.forName(className);
        // 5. 根据Class对象获得Constructor对象
        Constructor cons = c.getConstructor();
        // 6. 通过Constructor对象创建类的对象
        Object obj = cons.newInstance();

        System.out.println(obj);

        // 获得键集合:[class,name,gender,age]
        Set<String> keySet = info.stringPropertyNames();
        for (String key : keySet) {
            if (key.equals("class"))continue;
            // 根据key获得对应值
            String value = info.getProperty(key); // rose woman "18"
            // 根据key获得对应的成员变量对象
            Field field = c.getDeclaredField(key);
            // 暴力反射
            field.setAccessible(true);
            // 判断成员变量的类型
            Class type = field.getType();
            // 判断是否是整型
            if (type == int.class){
                field.setInt(obj, Integer.parseInt(value));
            } else {
                // 给对象obj的成员变量赋值
                field.set(obj, value);
            }
        }
        System.out.println(obj);
    }
}

package com.itheima._07反射综合案例;

import com.itheima.bean.Book;
import com.itheima.bean.Student;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Properties;
import java.util.Set;

/**
    目标:能够使用反射技术根据配置信息创建对象

    案例说明
         1. 有配置⽂件stu.properties,存储在当前模块下,内容如下:

             class=com.itheima.bean.Student
             name=rose
             gender=女
             age=18

         2.根据配置⽂件信息创建一个学生对象。
            Student stu = new Student("rose","女",18);

    实现步骤:
        1. 创建属性集合对象:Properties
        2. 加载配置文件中的数据到属性集合中
        3. 根据class获得类全名字符串
        4. 根据类全名字符从获得Class对象
        5. 根据Class对象获得Constructor对象
        6. 通过Constructor对象创建类的对象

 */
public class Demo072 {

    public static void main(String[] args) throws Exception{
        Student stu = createObject("/stu.properties");
        Book book = createObject("/book.properties");
        System.out.println(stu.getAge());
        System.out.println(book.getAuthor());
    }

    /**
     * 根据配置文件创建对象
     */
    public static <T> T createObject(String fileName)throws Exception{
        // 1. 创建属性集合对象:Properties
        Properties info = new Properties();
        // 2. 加载配置文件中的数据到属性集合中
        info.load(Demo072.class.getResourceAsStream(fileName));
        // 3. 根据class获得类全名字符串
        String className = info.getProperty("class");
        // 4. 根据类全名字符从获得Class对象
        Class c = Class.forName(className);
        // 5. 根据Class对象获得Constructor对象
        Constructor cons = c.getConstructor();
        // 6. 通过Constructor对象创建类的对象
        T obj = (T) cons.newInstance();
        // 获得键集合:[class,name,gender,age]
        Set<String> keySet = info.stringPropertyNames();
        for (String key : keySet) {
            if (key.equals("class"))continue;
            // 根据key获得对应值
            String value = info.getProperty(key); // rose woman "18"
            // 根据key获得对应的成员变量对象
            Field field = c.getDeclaredField(key);
            // 暴力反射
            field.setAccessible(true);
            // 判断成员变量的类型
            Class type = field.getType();
            // 判断是否是整型
            if (type == int.class){
                field.setInt(obj, Integer.parseInt(value));
            } else if(type == double.class){
                field.setDouble(obj, Double.parseDouble(value));
            } else  {
                // 给对象obj的成员变量赋值
                field.set(obj, value);
            }
        }
        return obj;
    }
}

8.注解概述

package com.itheima._08注解概述;

/**
    目标:理解注解的作用

    讲解:
        1. 注解概述:参考pdf文档

        2. 注解的作用

    小结:
        1. 注解的作用:给程序带入参数

 */
public class Demo08 {
}

9.自定义注解

  • 注解定义格式

@interface 注解名{

数据类型 属性名();

数据类型 属性名()default 默认值

}

  • 注解属性使用类型

    • 八种基本数据类型
    • 四种引用数据类型:String Class 注解类型 枚举类型
    • 以及以上类型的数据形式
  • package com.itheima._09自定义注解;
    
    /**
        目标:掌握注解定义格式
    
        讲解:
            1. 注解定义格式
                @interface 注解名{
                    数据类型 属性名();
                    数据类型 属性名() default 默认值;
                }
    
            2. 注解属性适用类型
                 * 八种基本数据类型
                 * 四种引用数据类型:String,Class,注解类型,枚举类型
                 * 以及以上类型的数组形式
    
        小结:
            1. 注解的定义格式
                @interface 注解名{
                    数据类型 属性名();
                    数据类型 属性名() default 默认值;
                }
     */
    @interface Student{
        String name();
        int age() default 18;
    }
    public class Demo09 {
    }
    
    

10.使用自定义注解

package com.itheima._10使用自定义注解;

/**
 - 包含属性:String value()   书名
 - 包含属性:double price()  价格,默认值为 100
 - 包含属性:String[] authors() 多位作者
 */
public @interface Book {
    // 书名
    String value();
    // 价格
    double price() default 100;
    // 多位作者
    String[] authors();
}

package com.itheima._10使用自定义注解;

/**
    目标:掌握注解的使用格式和注意事项

    讲解:
        1. 注解的使用格式
            无属性的注解: @注解名
            有属性的注解: @注解名(属性名=属性值,....)

        2. 注解使用注意事项
            如果注解有属性且没有默认值,则使用注解时必须给该属性赋值。

        3. 注解使用演示
             3.1 定义一个注解:Book

             - 包含属性:String value()   书名
             - 包含属性:double price()  价格,默认值为 100
             - 包含属性:String[] authors() 多位作者

             3.2 定义类在成员方法上使用Book注解

    小结:
        1. 注解的使用格式
            @注解名
            @注解名(属性名=值,...)
 */
@Book(value = "红楼梦",authors = "曹雪芹",price = 99)
public class Demo10 {

    private String name;

    @Book(value = "西游记",authors = {"吴承恩","白求恩"},price = 200)
    public void buy(){

    }
}

11.注解特殊属性value

package com.itheima._11注解特殊属性value;

/**
    目标:掌握特殊属性value的使用

    讲解:
        1. 特殊属性value的特殊之处
            如果注解有且只有一个属性且属性名为value时,则在使用注解时给属性赋值时可以省略value名字。
            如果注解中除了value属性之外还有其他属性,在使用注解时只要有给其他属性赋值,则value属性名就不能省略了。

    小结:
        1. 什么情况下给注解属性赋值时可以省略属性名?
            当只给value属性赋值时

 */
@interface TestA{
    String value();
    int age() default 20;
}

@TestA(value = "xxx",age = 30)
public class Demo11 {

}

12.元注解概述

package com.itheima._12元注解概述;

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

/**
 - 包含属性:String value()   书名
 - 包含属性:double price()  价格,默认值为 100
 - 包含属性:String[] authors() 多位作者
 */
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Book {
    // 书名
    String value();
    // 价格
    double price() default 100;
    // 多位作者
    String[] authors();
}

package com.itheima._12元注解概述;

/**
    目标:能够理解常用元注解的作用

    讲解:
        1. 元注解概述
            官方定义的注解
            用来定义注解的注解
            任何官方的非元注解的定义都使用到了元注解

        2. 常用元注解
         @Inherited:用来标识该注解可以被子类继承
         @Target:用来标识注解的作用位置
            value属性可用值定义在ElementType枚举类中,常用值如下:
                    TYPE,         注解可以使用在类和接口上
                    FIELD,        注解可以使用在成员变量上
                    METHOD,       注解可以使用在成员方法上
                    CONSTRUCTOR,  注解可以使用在构造方法上
                    LOCAL_VARIABLE, 注解可以使用在局部变量上

         @Retention:用来标识注解的作用范围(生命周期)
                value属性值定义在RetentionPolicy枚举类中,常用值如下:
                     SOURCE:  源码阶段:注解只作用在源代码阶段,编译产生的字节码文件和运行时阶段就不存在了
                     CLASS : 字节码文件阶段: 注解作用在源码阶段,字节码文件阶段,运行时阶段就不存在了
                     RUNTIME: 运行时阶段:注解作用在整个项目的运行过程中,一直存在:三个阶段都存在。
    小结:
        1. 元注解@Target的作用:用来标识注解的作用位置
        2. 元注解@Retention的作用:用来标识注解的作用范围
 */
@Book(value = "水浒传11",authors = "施耐庵")
public class Demo12 {


    @Book(value = "水浒传11",authors = "施耐庵")
    public void buy(){

    }
}

13.注解解析

package com.itheima._13注解解析;

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

/**
 - 包含属性:String value()   书名
 - 包含属性:double price()  价格,默认值为 100
 - 包含属性:String[] authors() 多位作者
 - 限制注解使用的位置:类和成员方法上
 - 指定注解的有效范围:RUNTIME
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    // 书名
    String value();
    // 价格
    double price() default 100;
    // 多位作者
    String[] authors();
}

package com.itheima._13注解解析;

@Book(value = "西游记",price = 199,authors = "吴承恩")
public class BookStore extends SmallBookStore{

    @Book(value = "红楼梦",price = 666,authors = "曹雪芹")
    public void buy(){

    }
}

package com.itheima._13注解解析;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Pen {
    double price() default 1.5;
}

package com.itheima._13注解解析;

@Pen
public class SmallBookStore {
}

package com.itheima._13注解解析;

import org.junit.Test;

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

/**
    目标:注解的解析(了解)

    讲解:
        1. 什么是注解解析
            通过Java代码从注解上获得信息的过程

        2. 注解解析相关接口和类
            Annotation:类,所有注解都是Annotation子类
            AnnotatedElement:接口,定义了用来获得注解信息的相关方法
                 T getAnnotation(Class<T> annotationClass)
                    * 根据注解类型获得当前对象上使用的注解对象

                 Annotation[]  getAnnotations()
                    * 获得当前对象上所有的注解信息,包括继承父类的注解
                 Annotation[]  getDeclaredAnnotations()
                    * 获得当前对象上所有的注解信息,不包括继承父类的注解

                 boolean   isAnnotationPresent(Class<Annotation> annotationClass)
                    判断当前对象上有没有使用指定类型的注解,使用了返回true,否则false


            须知:Class、Field、Method、Constructor等类都已经实现了AnnotatedElement接口。

        3. 注解解析的原理
            * 注解作用在哪个成员上就获得该成员对应的对象来获得注解信息
                * 比如注解作用在成员变量上,则获得该成员变量对应的Field对象来获得注解信息。
                * 比如注解作用在成员方法上,则获得该成员方法对应的Method对象来获得注解信息。
                * 比如注解作用在构造方法上,则获得该构造方法对应的Constructor对象来获得注解信息。
                * 比如注解作用在类上,则获得该类对应的Class对象来获得注解信息。

        4. 注解解析示例演示
             4.1 定义注解Book,要求如下:
                 - 包含属性:String value()   书名
                 - 包含属性:double price()  价格,默认值为 100
                 - 包含属性:String[] authors() 多位作者
                 - 限制注解使用的位置:类和成员方法上
                 - 指定注解的有效范围:RUNTIME
             4.2 定义BookStore类,在类和成员方法上使用Book注解
             4.3 定义TestAnnotation测试类获取Book注解上的数据
    小结:
        1. 什么是注解解析
            通过Java代码获得注解信息的过程

        2. 获得注解数据的原理
         * 注解作用在哪个成员上就获得该成员对应的对象来获得注解信息
             * 比如注解作用在成员变量上,则获得该成员变量对应的Field对象来获得注解信息。
             * 比如注解作用在成员方法上,则获得该成员方法对应的Method对象来获得注解信息。
             * 比如注解作用在构造方法上,则获得该构造方法对应的Constructor对象来获得注解信息。
             * 比如注解作用在类上,则获得该类对应的Class对象来获得注解信息。
 */
public class TestAnnotation {

    // 获得类上使用的所有注解信息
    @Test
    public void test03() {
        // 1. 获得Class对象
        Class c = BookStore.class;
        // 2. 获得所有注解信息:包括继承父类的注解
        //  Annotation[] ans = c.getAnnotations();
        // 2. 获得所有注解信息:不包括继承父类的注解
        Annotation[] ans = c.getDeclaredAnnotations();
        for (Annotation an : ans) {
            System.out.println(an);
        }
    }


    // 获得类上使用的Book注解信息
    @Test
    public void test02() {
        // 1. 获得Class对象
        Class c = BookStore.class;
        if (c.isAnnotationPresent(Book.class)) {
            // 2. 获得Book注解对象
            Book book = (Book) c.getAnnotation(Book.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.authors()));
        }
    }

    // 获得buy方法上使用的Book注解信息
    @Test
    public void test01() throws Exception{
        // 1. 获得Class对象
        Class c = BookStore.class;
        // 2. 根据方法名获得Method对象
        Method m = c.getMethod("buy");
        if(m.isAnnotationPresent(Book.class)){
            // 3. 获得Book注解对象
            Book book = m.getAnnotation(Book.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.authors()));
        }
    }
}

14.注解案例—模拟Junit

package com.itheima._14注解案例_模拟junit;

import java.lang.reflect.Method;

/**
    案例目标:能够自定义注解:模拟Junit测试的@Test

    案例需求:
        1.自定义注解@MyTest:模拟了Junit测试的@Test注解
        2.创建一个类:MyTestTest,在该类中定义若干个方法
            * 部分方法使用@MyTest修饰,部分方法不使用
        3.创建一个测试类:Demo14,运行该类的main方法
            * 执行main方法时调用MyTestTest类所有使用了@MyTest注解修饰的方法
 */
public class Demo14 {
    public static void main(String[] args)throws Exception {
        // 1. 获得Class对象
        Class c = MyTestTest.class;
        // 创建MyTestTest对象
        Object obj = c.getConstructor().newInstance();
        // 2. 获得所有的成员方法对象:Method[]
        Method[] methods = c.getMethods();
        // 3. 遍历数组:Method
        for (Method m : methods) {
            // 4. 判断Method上是否使用@MyTest注解
            if (m.isAnnotationPresent(MyTest.class)){
                // 调用方法
                m.invoke(obj);
            }
        }

    }
}

package com.itheima._14注解案例_模拟junit;

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 {

}

package com.itheima._14注解案例_模拟junit;

import org.junit.Test;

public class MyTestTest {

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

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

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

15.代理模式概述

package com.itheima._15代理模式概述;

/**
    目标:理解代理模式的作用

    讲解:
        1. 代理模式的分类
            静态代理
            动态代理

        2. 代理模式的作用
            拦截对象真实对象的直接访问,
            在不修改真正对象的代码情况下对真实对象的功能进行增强。

        3. 代理举例

    小结:
        代理模式的作用:拦截对真实对象的直接访问,可以在不修改真实对象的代码的情况下对其功能进行增强。
 */
public class Demo151 {
}

16.动态代理演示

package com.itheima._16动态代理演示;

// 用来描述增删改查的功能
public interface Dao<T>{
    // 增
    public void save(T t);
    // 删
    public void delete(T t);
    // 改
    public void update(T t);
    // 查
    public T find(int id);
}

package com.itheima._16动态代理演示;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;

/**
    目标:能够创建动态代理对象

    讲解:
        0. 动态代理
            在程序运行过程中动态的创建代理类,根据代理类创建代理对象。

        1. 如何创建动态代理对象
            通过工具类Proxy的静态方法创建,该方法如下:
                static Object newProxyInstance(
                 ClassLoader loader,
                 Class[] interfaces,
                 InvocationHandler h)
                * 创建代理对象
                * loader:类加载器对象,传递真实对象的类加载器对象
                * interfaces:真实对象实现的接口
                * h: 传递InvocationHandler接口的实现类

        类加载器:
                应用类加载器(只要开发者编写的类都是使用该加载器加载),
                扩展类加载器,
                引导类加载器


        2. 动态代理案例演示:
            增强Set对象的add方法,实现添加成功给用户提示,添加失败给用户提示

    小结:
        如何创建动态代理对象:

 */
public class Demo161 {
    public static void main(String[] args) {
        // 创建Set对象:真实对象
        Set<String> set = new HashSet<>();

        // 创建代理对象
        Set proxy = (Set) Proxy.newProxyInstance(
                set.getClass().getClassLoader(),   // 类加载器对象
                new Class[]{Set.class},// 真实对象实现的接口
                new InvocationHandler() {  // 回调处理对象
                    // invoke调用时机:每当通过代理对象调用方法时都会被该方法拦截
                    // 参数1:proxy 代理对象
                    // 参数2:method 代理对象的调用的方法:拦截到的方法
                    // 参数3:args 代理对象调用方法时传递的参数
                    // 返回值:调用真实对象方法的返回值
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // [aaa]
                        String str = (String) args[0]; // aaaa
                        // 将元素添加真实对象set上
                        boolean b = set.add(str);
                        System.out.println("添加成功");
                        return b;
                    }
                }
        );

        // 通过代理对象调用方法添加元素
        proxy.add("aaa"); // 添加成功
        proxy.add("bbb"); // 添加失败

        System.out.println(set);
    }
}

package com.itheima._16动态代理演示;

/**
    目标:深入理解动态代理的开发步骤

    讲解:
        1.  动态代理示例演示
            2.1 现有一个数据访问层类(StudentDao)
                * 类中提供了对学生进行增删改查的方法。

            2.2 现有一个业务层类(StudentService)
                * 该类需要调用StudentDao类中定义好的方法对学生进行增删改查操作。

            2.3 要求:在调用StudentDao方法之前要先判断用户是否有权限
                * 如果有权限则允许调用StudentDao方法,并在调用完StudentDao方法之后要记录日志。
                * 如果没有权限则不允许调用StudentDao方法。
                * 不允许修改StudentDao类中代码实现以上需求。

    小结:
        动态代理的开发步骤小结:
            1. 明确要代理的功能(方法)有哪些?
            2. 将要代理的方法定义在接口中
            3. 真实对象需要实现接口重写接口中的方法
            4. 创建真实对象:不能直接通过真实对象调用方法了
            5. 通过Proxy工具类的静态方法创建代理对象:需要传递以下三个参数:
                参数1:真实对象的类加载器
                参数2:真实对象实现的接口Class数组
                参数3:回调处理对象:InvocationHandler接口实现类对象
                    创建InvocationHandler实现类对象并重写invoke方法
            6. 在invoke方法中根据需求对代理方法进行拦截,
                根据需求决定是否应该调用真实对象的方法

 */
public class Demo162 {

}

package com.itheima._16动态代理演示;

public class Student {

}

package com.itheima._16动态代理演示;

/**
 * 对学生进行增删改查操作的类:数据访问层,直接跟数据库打交道
 * @author pkxing
 */
public class StudentDao implements Dao<Student>{

    @Override
    public void save(Student t) {
        System.out.println("增加学生信息:" + t);
    }

    @Override
    public void delete(Student t) {
        System.out.println("删除学生信息:" + t);
    }

    @Override
    public void update(Student t) {
        System.out.println("更新学生信息:" + t);
    }

    @Override
    public Student find(int id) {
        System.out.println("查询学生信息");
        Student s =  new Student();
        System.out.println(s);
        return s;
    }
}

package com.itheima._16动态代理演示;

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

// 业务层调用数据访问层
public class StudentService {
    public static void main(String[] args) {
        // 创建数据访问层对象:真实对象
        StudentDao stuDao = new StudentDao();

        // 创建代理对象
        Dao proxy = (Dao) Proxy.newProxyInstance(
                stuDao.getClass().getClassLoader(), // 类加载器对象
                new Class[]{Dao.class}, // 真实对象实现的接口
                new InvocationHandler() {

                    // 检查是否有权限:有返回true,否则false
                    public boolean check(){
                        System.out.println("检查权限...");
                        return true;
                    }
                    // 记录日志信息
                    public void log(){
                        System.out.println("记录日志信息...");
                    }

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                         // 检查是否有权限
                        if (check()){
                            // 有则调用真实对象的方法
                            Object result = method.invoke(stuDao, args);
                            // 记录日志
                            log();
                            return result;
                        }
                        return null;
                    }
                }
        );
        // 创建学生对象
        Student stu = new Student();
        // 对学生进行增删改查:调用代理对象方法
        proxy.save(stu);
     Student s = (Student) proxy.find(1);
        proxy.delete(stu);
        proxy.update(stu);
}
}

17.总结


     - 能够通过反射技术获取Class字节码对象
        类名.class
        对象名.getClass();
        Class.forName("类全名字符串")

     - 能够通过反射技术获取构造方法对象,并创建对象。
        1. Class c = 类名.class
        2. Constructor cons = c.getConstructor(Class...type);
        3. Object obj = cons.newInstance(Object...args);

     - 能够通过反射获取成员方法对象,并且调用方法。
        1. Class c = 类名.class
        2. Method m = c.getMethod("成员方法名",Class...type);
        3. Object result = m.invoke(Object obj,Object...args);

     - 能够说出注解的作用:给程序带入参数

     - 能够自定义注解和使用注解
        定义格式: @interface 注解名{ 数据类型 数据名() }
        使用格式: @注解名(属性名=值,....)

     - 能够说出常用的元注解及其作用
        @Target:标识注解作用位置
        @Retention:标识注解作用范围
        @Inherited:标识注解可以被子类继承

     - 能够解析注解并获取注解中的数据
        AnnotatedElement:接口,定义了获得注解信息的方法
        Annotation:类,所有注解的父类

     - 能够完成注解的MyTest案例:参考代码

    知识回顾
        1. 网络通讯三要素
            IP地址:网络设备的唯一标识
            端口号:进程的唯一标识
            通讯协议:确定如何传输数据:数据传输格式
        2. UDP协议特点
            面向无连接
            速度快但不可靠
            基于数据包传输数据
            传输数据大小限制在64k
            只管发送,不确认对方是否收到
            DatagramPacket
            DatagramSocket

        3. TCP协议特点
            面向连接
            通过三次握手建立连接
            通过四次挥手断开连接
            基于IO流进行数据传输
            传输数据大小无限制
            速度慢但可靠
            Socket:客户端
            ServerSocket:服务器端

        4. Junit作用:用来对类中的方法进行测试,保证方法的正确性和稳定性。
            @Test:测试方法,必须public,没有返回值,没有参数
            @Before:该方法会在每个测试方法执行之前执行一次,用来执行初始化操作。
            @After:该方法会在每个测试方法执行之后执行一次,用来执行释放资源操作。

    今天内容
        1. 反射
        2. 注解
        3. 动态代理

    今天重点:
        1. 反射:能够操作构造方法,成员方法,成员变量
        2. 注解:使用注解
        3. 动态代理:理解作用和执行流程

    
        反射概述:一种创建对象,调用方法,给成员变量赋值和取值的方式
        反射操作构造方法:创建对象
            类中每个构造方法都是Constructor对象
            如何获得Constructor对象:通过Class对象的方法获得,方法如下:
                Constructor cons = c.getConstructor(Class...type);
            Constructor对象的常用方法:
                T newInstance(Object...args)

        反射操作成员方法:调用方法
            类中每个成员方法都是Method对象
            如何获得Method对象:通过Class对象的方法获得,方法如下:
               Method m = c.getMethod("方法名",Class...type)
            Method对象的常用方法:
                Object invoke(Object obj,Object...args)
                    调用方法,obj:方法调用者,args:调用方法传递的参数

        反射操作成员变量:赋值和取值
            类中每个成员变量都是Field对象
            如何获得Field对象:通过Class对象的方法获得,方法如下:
                Field f = c.getDeclaredField("成员变量名称");
            Field对象的常用方法:
                void setXxx(Object obj,Xxx value); 给对象obj的成员变量赋值为value
                Xxx getXxx(Object obj); 获得对象obj成员变量的值
                void setAccessible(true); 暴力反射

        反射操作成员的步骤
            1. 获得类的Class对象
                Class c = 类名.class;
            2. 调用Class对象的方法获得对应的对象
                c.getConstructor();
                c.getMethod();
                c.getDeclaredField();
            3. 调用对象的方法执行操作

        注解的作用:给程序带入参数(携带信息)
        注解的定义格式:
            @interface 注解名{
                数据类型 属性();
                数据类型 属性() default 默认值;
            }
 */
public class Demo17 {
}

18.总结

  • //获取 1.类对象=》
  • 通过类对象获取2.反射对象/3.方法
  • 然后调用: 4.方法.invoke(对象,“java”)
package kh;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class kh04 {
    public static void main(String[] args) throws Exception {
        //创建Class对象
        Class c = Class.forName("kh.show");
        
        //1.通过 Class对象.构造 创建反射对象
        Constructor cons = c.getConstructor(String.class);
        Object instance01 = cons.newInstance("哈哈01");
        System.out.println(instance01);


        //2.通过 Class对象.实例 创建对象
        Object instance02 = c.newInstance();
        //通过 Class对象 创建反射方法
        Method show = c.getMethod("look", String.class);
        //最后调用 方法.invoke(对象,"")
        show.invoke(instance02, "哈哈02");

    }


}

class show {
    private String h;

    public show(String h) {
        this.h = h;
    }

    public show() {
    }

    public void look(String s) {
        System.out.println(s);
    }

    @Override
    public String toString() {
        return "show{" +
                "h='" + h + '\'' +
                '}';
    }
}

## 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值