【Java 19】反射 - 反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理

25 篇文章 0 订阅
20 篇文章 0 订阅

反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理

反射

image-20200903174227938

Class clazz1 = Class.forName("com.wmiao.java.Person");
//Class clazz1 = Person.class;
Person p1 = (Person) clazz1.newInstance();

1 Java反射机制概述

1.1 Java Reflection介绍

image-20200903173949585

1.2 动态语言 vs 静态语言

image-20200903173955474

1.3 Java反射机制研究及应用

image-20200903174000533

1.4 Java反射主要API

image-20200903174006719

1.5 代码实例

package com.wmiao.java;

import org.junit.Test;

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

/**
 * @author wmiao
 * @version 1.0
 * @description: TODO
 * @date 2020/9/3 19:29
 */

public class ReflectionTest {

    //反射之前,对于Person的操作
    @Test
    public void test1(){

        //1.创建Person类的对象
        Person p1 = new Person("Tom",23);

        //2.通过对象,调用其内部的属性、方法
        p1.age = 10;
        System.out.println(p1.toString());
        p1.show();

        //在Perosn类外部,不可以通过Person类的对象调用其内部私有结构
        //比如:name、showNation()以及私有的构造器

    }

    //反射之后,Person的操作
    @Test
    public void test2() throws Exception {

        Class clazz = Person.class;

        //1.通过反射,创建Person类的对象
        Constructor cons = clazz.getConstructor(String.class,int.class);

        Object obj = cons.newInstance("Tom",12);
        Person p = (Person) obj;
        System.out.println(p.toString());

        //2.通过反射,调用对象指定的属性、方法
        //2.1 调用属性
        Field age = clazz.getDeclaredField("age");
        age.set(p,10);
        System.out.println(p.toString());

        //2.2 调用方法
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);

        //通过反射,可以通过Person类的对象调用其内部私有结构
        //调用私有的构造器
        Constructor cons1 = clazz.getDeclaredConstructor(String.class);
        cons1.setAccessible(true);
        Person p1 = (Person)cons1.newInstance("Jerry");
        System.out.println(p1);

        //调用私有的属性
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1,"HanMeiMei");
        System.out.println(p1);

        //调用私有的方法
        Method showNation = clazz.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        String nation = (String) showNation.invoke(p1,"中国");//p1.showNation("中国")
        System.out.println(nation);

    }

}

1.6 对于反射的疑问

  1. 反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?

    封装性的体现:public是公共的,可以拿去用,private是私有的,正常情况下你用不着。单例模式--------建议你去调

    反射:你非要用可以也可以调

  2. 通过直接new对象的方式 或 反射的方式 都可以调用公共的结构,开发中到底用哪个?

    建议:直接new的方式

    什么时候会使用:反射的方式。

    反射的特征:动态性(一开始【编译时】不知道要造哪个类的对象,如果出现这样的情况,就使用反射的方式)

    例子:登录和注册,编译时是不知道用户会继续两种操作的哪种,从而运行期间造出对应的对象。根据用户想进行哪种操作,发过来的消息,造相关的对象,去调相关的方法

1.7 技术面疑问

  1. 参与哪个项目中
  2. 项目的架构是什么
  3. 主要的哪一块是用什么技术来实现的

2 理解Class类并【获取Class实例】

关于java.lang.Class类的理解

  1. 类的加载过程:

    程序经过java.exe命令以后,会生成一个或多个字节码文件(.class结尾),接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。【加载到内存中的类,我们就称为运行时类】,此运行时类,就作为Class的一个实例

  2. 换句话说,【Class的实例就对应着一个运行时类

  3. 加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。

2.1 Class类介绍

image-20200903174016246

image-20200903174023606

2.2 Class类常用方法

image-20200903174028512

image-20200903174033715

2.3 【获取Class类的实例(四种方式)】

image-20200903174038117

public class ReflectionTest {

    @Test
    public void test3() throws ClassNotFoundException {

        //方式一:调用运行时类的属性:.class
        Class clazz1 = Person.class;
        //Class<Person> clazz1 = Person.class;
        System.out.println(clazz1);//class com.wmiao.java.Person

        //方式二:通过运行时类的对象,调用getClass()
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);

        //方式三:调用Class的静态方法:forName(String classPath)
        //throws ClassNotFoundException
        Class clazz3 = Class.forName("com.wmiao.java.Person");//类的全类名
        //clazz3 = Class.forName("java.lang.String");
        System.out.println(clazz3);

        //方式四:使用类的加载器:ClassLoader[了解]
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.wmiao.java.Person");
        System.out.println(clazz4);

        
        
        
        System.out.println(clazz1 == clazz2);//true
        System.out.println(clazz1 == clazz3);//true
        System.out.println(clazz1 == clazz4);//true

    }

}

2.4 哪些类型可以有Class对象?

image-20200903174042934

image-20200903174048497

3 类的加载与ClassLoader的理解

3.1 类的加载过程

image-20200903174057397

image-20200903174103369

image-20200903174108141

3.2 类的加载器

image-20200903174140159

3.3 了解:什么时候会发生类初始化?

image-20200903174119359

image-20200903174128765

3.4 了解:ClassLoader

3.4.1 类加载器的分类

image-20200903174145772

3.4.2 步骤与代码实例

image-20200903174151275

image-20200903174155708

public class ClassLoaderTest {

    @Test
    public void test1(){

        //对于自定义类,使用系统类加载器进行加载
        ClassLoader classLoader1 = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader1);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //调用系统类加载器的getParent():获取扩展类加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);//sun.misc.Launcher$ExtClassLoader@279f2327

        //调用扩展类加载器的getParent():无法获取引导类加载器
        //引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
        ClassLoader classLoader3 = classLoader2.getParent();
        System.out.println(classLoader3);//null

        ClassLoader classLoader4 = String.class.getClassLoader();
        System.out.println(classLoader4);//null

    }

    /*
    Properties:用来读取配置文件
     */
    @Test
    public void test2(){

        FileInputStream fis = null;
        try{

            Properties pros = new Properties();

            //此时的文件默认在当前的module下
            //读取配置文件的方式一:
            //fis = new FileInputStream("jdbc.properties");
            //pros.load(fis);//加载流对应的文件

            //此时的文件默认在当前的module的src下
            //读取配置文件的方式二
            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
            pros.load(is);

            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            System.out.println("user = " + user + ",password = " + password);

        }catch(IOException e){
            e.printStackTrace();
        }finally{
            if(fis != null){
                try{
                    fis.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }

    }

}

3.5 配置文件Properties

public class ClassLoaderTest {

    /*
    Properties:用来读取配置文件
     */
    @Test
    public void test2(){

        FileInputStream fis = null;
        try{

            Properties pros = new Properties();

            //此时的文件默认在当前的module下
            //读取配置文件的方式一:
            //fis = new FileInputStream("jdbc.properties");
            //pros.load(fis);//加载流对应的文件

            //此时的文件默认在当前的module的src下
            //读取配置文件的方式二
            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
            pros.load(is);

            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            System.out.println("user = " + user + ",password = " + password);

        }catch(IOException e){
            e.printStackTrace();
        }finally{
            if(fis != null){
                try{
                    fis.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }

    }

}

4 【创建运行时类的对象】

4.1 介绍

image-20200903224512954

4.2 步骤

image-20200903224520135

4.3 代码实例

new Instance():创建对应的运行时类的对象
内部调用了运行时类的空参构造器。

要想此方法正常的创建运行时类的对象,要求:
1.运行类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public

在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

public class NewInstanceTest {

    @Test
    public void test1() throws IllegalAccessException, InstantiationException {

        /*
        new Instance():创建对应的运行时类的对象
        内部调用了运行时类的空参构造器。
        
        要想此方法正常的创建运行时类的对象,要求
        1.运行类必须提供空参的构造器
        2.空参的构造器的访问权限得够。通常,设置为public
         */
        Class clazz1 = Person.class;
        Person p1 = (Person) clazz1.newInstance();
        System.out.println(p1);

        Class<Person> clazz2 = Person.class;
        Person p2 =clazz2.newInstance();
        System.out.println(p2);

    }

}

4.4 体会反射的动态性

运行时才知道要造什么对象

public class NewInstanceTest {

    @Test
    public void test2(){

        int num = new Random().nextInt(3);//0,1,2
        String classPath = "";
        switch (num){
            case 0:
                classPath = "java.util.Date";
                break;
            case 1:
                classPath = "java.lang.Object";
                break;
            case 2:
                classPath = "com.wmiao.java.Person";
                break;
        }
        //运行时才知道要造什么对象
        try {
            Object obj = getInstance(classPath);
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }


    }

    /*
    创建一个指定类的对象
    classPath:指定类的全类名
     */
    public static Object getInstance(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

5 获取运行时类的完整结构

5.1 获取全部完整结构的方法

image-20200903224531079

image-20200903224538382

image-20200903224547285

image-20200903224553298

image-20200903224559202

image-20200903224604804

@MyAnnotation(value = "hi")
public class Person extends Creature<String> implements  Comparable<String>,MyInterface{

    private String name;
    int age;
    public int id;

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

    public Person() {
    }

    @MyAnnotation(value = "1")
    public Person(String name) {
        this.name = name;
    }

    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍:" + nation);
        return nation;
    }

    public String display(String interest, int age){
        return interest + age;
    }

    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    private static void showDesc(){
        System.out.println("我是一个可爱的人");
    }
}

public class Creature<T> implements Serializable {

    private char gender;
    public double weight;

    private void breath(){
        System.out.println("生物呼吸");
    }

    public void eat(){
        System.out.println("生物吃东西");
    }

}

public interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "Hello";
}
5.1.1 实现的全部接口【实现接口】

public Class<?>[] getInterfaces():确定此对象所表示的类或接口实现的接口

public class OtherTest {
    
    //获取运行时类实现的接口
    @Test
    public void test5(){
        Class<Person> clazz = Person.class;

        //获取运行时类实现的接口
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> c : interfaces) {
            System.out.println(c);
        }
        /*
        interface java.lang.Comparable
        interface com.wmiao.java1.MyInterface
         */

        //获取运行时类的父类实现的接口
        Class<?>[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for (Class<?> c : interfaces1) {
            System.out.println(c);
        }
        /*
        interface java.io.Serializable
         */
    }

}
5.1.2 所继承的父类【父类的泛型】

public Class<? Super T> getSuperclass():返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class

public class OtherTest {

    //获取运行时类的父类
    @Test
    public void test2(){
        Class<Person> clazz = Person.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
        //class com.wmiao.java1.Creature
    }

    //获取运行时类的带泛型的父类
    @Test
    public void test3(){
        Class<Person> clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
        //com.wmiao.java1.Creature<java.lang.String>
    }

    //获取运行时类的带泛型的父类的泛型
    @Test
    public void test4(){
        Class<Person> clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();

        for (Type aT : actualTypeArguments) {
            System.out.println(aT);
        }
        //class java.lang.String

        for (Type aT : actualTypeArguments) {
            System.out.println(aT.getTypeName());
        }
        //java.lang.String

        for (Type aT : actualTypeArguments) {
            System.out.println(((Class)aT).getName());
        }
        //java.lang.String
    }

}
5.1.3 全部的构造器
  • public Constructor[] getConstructors():返回此 Class 对象所表示的类的所有public构造方法
  • public Constructor[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法

Constructor类中:

  • public int getModifiers():取得修饰符
  • public String getName():取得方法名称
  • public Class<?>[] getParameterTypes():取得参数的类型
public class OtherTest {

    @Test
    public void test1(){

        Class<Person> clazz = Person.class;

        //getConstructors():获取当前运行时类中声明为public的构造器
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> c : constructors) {
            System.out.println(c);
        }

        System.out.println();

        //getDeclaredConstructors():获取当前运行时类中声明的所有构造器。(不包含父类的)
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor<?> c : declaredConstructors) {
            System.out.println(c);
        }

        /*
        public com.wmiao.java1.Person(java.lang.String,int)
        public com.wmiao.java1.Person(java.lang.String)

        public com.wmiao.java1.Person(java.lang.String,int)
        public com.wmiao.java1.Person(java.lang.String)
         */

    }

}
5.1.4 全部的Method
  • public Method[] getDeclaredMethods():返回此Class对象所表示的类或接口的全部方法
  • public Method[] getMethods():返回此Class对象所表示的类或接口的public的方法

Method类中:

  • public Class<?> getReturnType():取得全部的返回值
  • public Class<?>[] getParameterTypes():取得全部的参数
  • public int getModifiers():取得修饰符
  • public Class<?>[] getExceptionTypes():取得异常信息
public class MethodTest {

    @Test
    public void test1(){

        Class clazz = Person.class;
        
        //getMethods():获取当前运行时类及其父类中声明为public访问权限的方法
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        /*
        public int com.wmiao.java1.Person.compareTo(java.lang.Object)
        public int com.wmiao.java1.Person.compareTo(java.lang.String)
        public void com.wmiao.java1.Person.info()
        public java.lang.String com.wmiao.java1.Person.display(java.lang.String)
        public void com.wmiao.java1.Creature.eat()
        public final void java.lang.Object.wait() throws java.lang.InterruptedException
        public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
        public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
        public boolean java.lang.Object.equals(java.lang.Object)
        public java.lang.String java.lang.Object.toString()
        public native int java.lang.Object.hashCode()
        public final native java.lang.Class java.lang.Object.getClass()
        public final native void java.lang.Object.notify()
        public final native void java.lang.Object.notifyAll()
        private java.lang.String com.wmiao.java1.Person.name
        int com.wmiao.java1.Person.age
        public int com.wmiao.java1.Person.id
         */




        //getDeclaredFields():获取当前运行时类中声明的所有方法。(不包含父类的)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }
        /*
        public int com.wmiao.java1.Person.compareTo(java.lang.Object)
        public int com.wmiao.java1.Person.compareTo(java.lang.String)
        public void com.wmiao.java1.Person.info()
        private java.lang.String com.wmiao.java1.Person.show(java.lang.String)
        public java.lang.String com.wmiao.java1.Person.display(java.lang.String)
         */

    }

    //@Xxxx
    //权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws 异常信息{}
    @Test
    public void test2(){

        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            //1.注解:getAnnotations()
            Annotation[] annos = m.getAnnotations();
            for (Annotation anno : annos) {
                System.out.println(anno);
            }
            //2.权限修饰符:getType()
            int modifiers = m.getModifiers();
            System.out.print(Modifier.toString(modifiers) + "\t");

            //3.返回值类型:getReturnType()
            Class<?> returnType = m.getReturnType();
            System.out.print(returnType.getName() + "\t");

            //4.方法名:getName()
            String name = m.getName();
            System.out.print(name);

            //5.形参列表
            System.out.print("(");
            Class<?>[] parameterTypes = m.getParameterTypes();
            if(!(parameterTypes == null && parameterTypes.length == 0)){
                for (int i = 0; i < parameterTypes.length; i++) {
                    if(i == parameterTypes.length - 1){
                        System.out.print(parameterTypes[i].getName() + " " + "args_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + " " + "args_" + i + ",");
                }
            }
            System.out.print(")");

            //6.抛出的异常
            Class<?>[] exceptionTypes = m.getExceptionTypes();
            if(exceptionTypes.length > 0){
                System.out.println(" throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if(i == exceptionTypes.length - 1){
                        System.out.print(parameterTypes[i].getName());
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + ",");
                }
            }

            /*
            public volatile	int	compareTo(java.lang.Object args_0)
            public	int	compareTo(java.lang.String args_0)
            public	void	info()
            @com.wmiao.java1.MyAnnotation(value=Hello)
            private	java.lang.String	show(java.lang.String args_0)
            public	java.lang.String	display(java.lang.String args_0,int args_1)
             */

            System.out.println();
        }

    }

}
5.1.5 全部的Field
  • public Field[] getFields():返回此Class对象所表示的类或接口的public的Field
  • public Field[] getDeclaredFields():返回此Class对象所表示的类或接口的全部Field

Field方法中:

  • public int getModifiers():以整数形式返回此Field的修饰符

  • public Class<?> getType():得到Field的属性类型

  • public String getName() :返回Field的名称

/**
 * @author 吴淼杰
 * @version 1.0
 * @description: 获取当前运行时类的属性结构
 * @date 2020/9/4 1:57
 */

public class FieldTest {

    @Test
    public void test1(){

        Class clazz = Person.class;

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        /*
        public int com.wmiao.java1.Person.id
        public double com.wmiao.java1.Creature.weight
         */




        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类的)
        Field[] declaredField = clazz.getDeclaredFields();
        for (Field f : declaredField) {
            System.out.println(f);
        }
        /*
        private java.lang.String com.wmiao.java1.Person.name
        int com.wmiao.java1.Person.age
        public int com.wmiao.java1.Person.id
         */

    }

    //权限修饰符 数据类型 变量名
    @Test
    public void test2(){

        Class clazz = Person.class;
        Field[] declaredField = clazz.getDeclaredFields();
        for (Field f : declaredField) {
            //1.权限修饰符:getModifiers()
            //public static final int PUBLIC = 0x00000001;
            //public static final int PRIVATE = 0x00000002;
            //public static final int PROTECTED = 0x00000004;
            //......
            int modifiers = f.getModifiers();
            System.out.print(Modifier.toString(modifiers) + "\t");

            //2.数据类型:getType()
            Class type = f.getType();
            System.out.print(type.getName() + "\t");

            //3.变量名:getName()
            String name = f.getName();
            System.out.println(name);

            /*
            private	java.lang.String	name
            	int	age
            public	int	id
             */

        }

    }

}
5.1.6 Annotation相关【】
  • getAnnotation(Class annotationClass)
  • getDeclaredAnnotations()
public class OtherTest {
    
    //获取运行时类声明的注解
    @Test
    public void test7(){

        Class<Person> clazz = Person.class;

        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //@com.wmiao.java1.MyAnnotation(value=hi)

    }
    
    //获取运行时类的方法声明的注解
    @Test
    public void test1(){

        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            //1.注解:getAnnotations()
            Annotation[] annos = m.getAnnotations();
            for (Annotation anno : annos) {
                System.out.println(anno);
            //@com.wmiao.java1.MyAnnotation(value=Hello)
        }
    }
        
}
5.1.7 泛型相关【】
  • Type getGenericSuperclass():获取父类泛型类型
  • ParameterizedType:泛型类型
  • getActualTypeArguments():获取实际的泛型类型参数数组
public class OtherTest {
    
    //获取运行时类的带泛型的父类的泛型
    @Test
    public void test4(){
        Class<Person> clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        
        
        
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();

        for (Type aT : actualTypeArguments) {
            System.out.println(aT);
        }
        //class java.lang.String

        for (Type aT : actualTypeArguments) {
            System.out.println(aT.getTypeName());
        }
        //java.lang.String

        for (Type aT : actualTypeArguments) {
            System.out.println(((Class)aT).getName());
        }
        //java.lang.String
    }

}
5.1.8 类所在的包
  • Package getPackage()
public class OtherTest {
    
    //获取运行时类所在的包
    @Test
    public void test6(){

        Class<Person> clazz = Person.class;

        Package aPackage = clazz.getPackage();
        System.out.println(aPackage);
		//package com.wmiao.java1
        
    }

}

5.2 小结

image-20200903224615456

6 【调用运行时类的指定结构】【重要:方法】

6.1 调用指定方法【】

image-20200903224628796

image-20200903224633343

public class ReflectionTest {

    /*
    如何操作运行时类中指定的方法 -- 需要掌握
     */
    @Test
    public void testField2() throws Exception{

        //调用非静态方法
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        //1.getDeclaredField(参数1, 参数2):获取指定的方法
        //参数1:指明获取的方法的名称
        //参数2:指明获取的方法的形参列表
        Method show = clazz.getDeclaredMethod("show", String.class);

        //2.保证当前方法是可以访问的
        show.setAccessible(true);

        //3.invoke(参数1, 参数2)
        //参数1:方法的调用者
        //参数2:给方法形参赋值的实参
        //返回值即为对应类中调用的方法的返回值
        Object obj = show.invoke(p, "CHN");
        System.out.println((String) obj);


        /***************************************/


        //调用静态方法
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用的运行时类中的方法没有返回值,则invoke()返回null
        Object returnVal = showDesc.invoke(Person.class);
        //Object returnVal = showDesc.invoke(null);
        System.out.println(returnVal);//null

    }
}

6.2 调用指定属性

image-20200903224638630

image-20200903224643953

public class ReflectionTest {

    /*
    如何操作运行时类中指定的属性 -- 需要掌握
     */
    @Test
    public void testField1() throws Exception{
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        //1.getDeclaredField():获取指定变量名的属性
        Field name = clazz.getDeclaredField("name");

        //2.保证当前属性是可访问的
        name.setAccessible(true);

        //3.获取、设置指定对象的此属性值
        name.set(p,"Tom");
        String pName = (String) name.get(p);
        System.out.println(pName);
    }

    /*
    不需要掌握:不理想,对属性的要求高
    */
    @Test
    public void testField() throws Exception{
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        //getField():获取指定的属性(要求运行时类中属性声明为public)
        //通常不采用此方式
        Field id = clazz.getField("id");

        /*
        设置当前属性的值
        set(参数1, 参数2):
        参数1:指明设置哪个对象的属性
        参数2:将此属性值设置为多少
         */
        id.set(p,1001);

        /*
        获取当前属性的值
        get(参数1):
        参数1:指明获取哪个对象的属性
         */
        int pId = (int) id.get(p);
        System.out.println(pId);
    }

}

6.3 调用指定构造器

public class ReflectionTest {

    @Test
    public void testConstructor() throws Exception {
        Class clazz = Person.class;

        //private Person(String name)
        /*
        1.获取指定的构造器
        getDeclaredConstructor():
        参数:指明构造器的参数列表
         */
        Constructor constructor = clazz.getDeclaredConstructor(String.class);

        //2.保证此构造器是可访问的
        constructor.setAccessible(true);

        //3.调用此构造器创建运行时类的对象
        Person per = (Person) constructor.newInstance("Tom");
        System.out.println(per);

    }
}

7 反射的应用:动态代理

7.1 代理设计模式的原理

  1. 我们想调用的是被代理类的对象的方法,然而被代理类的对象的创建、方法的调用都是由代理类发起的,或者说代理类对被代理类的对象和方法进行封装,由代理类来决定要不要创建被代理类的对象、以及何时创建、调用方法、方法何时调用,都是由代理类封装的。

    特点:代理类和被代理类都要实现同样的一套接口

    比如明星,共同的接口定义了sing()方法,经纪人和明显都要重写sing()方法,当我们通过调用经纪人的sing()时,里面就封装明星对sing()方法的调用

  2. 动态代理,就是有经纪人和明星,律师和诉讼方,中介和买房人………等等的一对,调用方法是通用的,这个通用方法就不能是编译期间确定下来的,只能运行期间来看,使用反射。在运行期间,根据代理类,去创建被代理类的对象,去调用方法

image-20200903224657513

image-20200903224708457

7.1.1 静态代理

特点:代理类和被代理类在编译期间,就确定下来了

//共同的接口
interface ClothFactory{

    void produceCloth();

}

//代理类
class ProxyClothFactory implements ClothFactory{

    private ClothFactory factory;//用被代理类对象进行实例化

    public ProxyClothFactory(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {

        System.out.println("准备");
        factory.produceCloth();
        System.out.println("收尾");

    }
}

//被代理类
class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("Nike生成衣服");
    }
}

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

        //创建被代理类的对象
        NikeClothFactory nike = new NikeClothFactory();
        //创建代理类的对象
        ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        //ProxyClothFactory proxyClothFactory = new ProxyClothFactory(new NikeClothFactory());

        proxyClothFactory.produceCloth();
    }
}

7.1.2 动态代理
interface Human{

    String getBelief();

    void eat(String food);

}

//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我吃" + food);
    }
}

/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法
 */

//代理类
class ProxyFatory{

    //调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxyInstance(Object obj){
        //obj:被代理类的对象

        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                handler);
    }

}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被代理类的对象进行赋值

    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //method:即为代理类对象调用的方法,此方法也就作为了被代理类要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj,args);
        //上诉方法的返回值就作为单曲类的invoke()的返回值
        return returnValue;

    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superman = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFatory.getProxyInstance(superman);
        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");

        System.out.println("**********************");

        NikeClothFactory nikeClothFactory = new NikeClothFactory();

        ClothFactory proxyClothFatory = (ClothFactory) ProxyFatory.getProxyInstance(nikeClothFactory);

        proxyClothFatory.produceCloth();
    }

}

7.2 Java动态代理API

image-20200903224716127

7.3 动态代理步骤

image-20200903224723530

image-20200903224729173

image-20200903224739042

image-20200903224745411

7.5 动态代理与AOP

image-20200903224750737

image-20200903224756949

image-20200904193310071

image-20200904193349935

image-20200904193338399

image-20200904193401820

image-20200904193414726

image-20200904193427605

image-20200904193432697

动态代理需复习 64:00

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值