[JavaSE]第十四章 Java反射机制

14.1 Java 反射机制概述

  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
  • 加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构

image-20220116201026566

14.1.1 反射相关的主要 API

  • java.lang.Class:代表一个类

  • java.lang.reflect.Method:代表类的方法

  • java.lang.reflect.Field:代表类的成员变量

  • java.lang.reflect.Constructor:代表类的构造器

14.2 获取 Class 实例

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

2.换句话说,Class 的实例就对应着加载到内存中的一个运行时类
3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取
此运行时类

public final Class getClass():返回一个Class类,此类是Java反射的源头

14.2.1 Class 类常用的方法

  • static Class forName(String name):返回指定类名 name 的 Class 对象
  • Object newInstance():调用缺省构造函数,返回该 Class 对象的一个实例
  • getName():返回此Class对象所表示的实体(类、接口、数组类、基本类型 或 void)名称
  • Class getSuperClass():返回当前 Class 对象的父类的 Class 对象
  • Class[] getInterfaces():获取当前 Class 对象的接口
  • ClassLoader getClassLoader():返回该类的类加载器
  • Class getSuperclass():返回表示此 Class 所表示的实体的超类的 Class
  • Constructor[] getConstructors():返回一个包含某些 Constructor 对象的数组
  • Field[] getDeclaredFields():返回 Field 对象的一个数组
  • Method getMethod(String name,Class … paramTypes):返回一个 Method 对象,此对象的形参类型为 paramType

14.2.2 获取 Class 的实例的方式

	@Test
    public void test3() throws ClassNotFoundException {
        //方式一:调用运行时类的属性:.class
        Class<Person> clazz1 = Person.class;
        System.out.println(clazz1);//class top.shiyiri.reflection.Person

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

        //方式三:调用 Class 的静态方法:forName(String classPath)
        Class<?> clazz3 = Class.forName("top.shiyiri.reflection.Person");
        //clazz3 = Class.forName("java.lang.String");
        System.out.println(clazz3);

        System.out.println(clazz1 == clazz2);//true
        System.out.println(clazz1 == clazz3);//true
        
        //方式四:使用类的加载器:ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("top.shiyiri.reflection.Person");
        System.out.println(clazz4);
        System.out.println(clazz1 == clazz4);//true
    }
  • Class 实例可以是哪些结构的说明

    	@Test
        public void test4() {
            Class c1 = Object.class;
            Class c2 = Comparable.class;
            Class c3 = String[].class;
            Class c4 = int[][].class;
            Class c5 = ElementType.class;
            Class c6 = Override.class;
            Class c7 = int.class;
            Class c8 = void.class;
            Class c9 = Class.class;
            int[] a = new int[10];
            int[] b = new int[100];
            Class c10 = a.getClass();
            Class c11 = b.getClass();
            // 只要元素类型与维度一样,就是同一个Class
            System.out.println(c10 == c11);//true
        }
    

14.3 类的加载和 ClassLoader

14.3.1 类的加载过程

image-20220116203134578

  • 类加载器作用:用来把类(class)装载进内存的
	@Test
    public void test1() {
        //对于自定义类,使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);

        //调用系统类加载器的getParent():获取扩展类加载器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);

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

14.4 创建运行时类的对象

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

    /*
    newInstance():调用此方法,创建对应的运行时类的对象。内部调用运行时类的空参构造器
    要想此方法正常的创建运行时类的对象,要求:
    1.运行时类必须提供空参的构造器
    2.空参的构造器的访问权限能够在其他类中进行访问

    在 JavaBean 中要求提供一个 public 的空参构造器。原因:
    1.便于通过反射,创建运行时类的对象
    2.便于子类继承此运行时类,默认调用 super(),保证父类由此构造器
     */
    Person person = clazz.newInstance();
    System.out.println(person);//Person(name=null, age=0)
}

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

14.5.1 接口

  • public Class<?>[] getInterfaces():确定此对象所表示的类或接口实现的接口
    @Test
    public void test5() {
        Class clazz = Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for (Class c: interfaces) {
            System.out.println(c);
            /*
            interface java.lang.Comparable
            interface top.shiyiri.reflection2.MyInterface
             */
        }

        System.out.println();

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

14.5.2 继承的父类

  • public Class<? Super T> getSuperclass():返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class
    @Test
    public void test2() {
        Class<Person> clazz = Person.class;

        Class<? super Person> superclass = clazz.getSuperclass();
        //class top.shiyiri.reflection2.Creature
        System.out.println(superclass);
    }

14.5.3 构造器

  • public Constructor<T>[] getConstructors():返回此 Class 对象所表示的类的所有 public 构造方法
  • public Constructor<T>[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法
  • public int getModifiers():取得修饰符
  • public String getName():取得方法名称
  • public Class<?>[] getParameterTypes():取得参数的类型
@Test
    public void test1() {
        Class<Person> clazz = Person.class;

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

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

        //getConstructors():获取当前运行时类中声明的所有构造器
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor: constructors) {
            System.out.println(constructor);
            /*
            top.shiyiri.reflection2.Person(java.lang.String,int)
            private top.shiyiri.reflection2.Person(java.lang.String)
            public top.shiyiri.reflection2.Person()
             */
        }
    }

14.5.4 方法

  • public Method[] getDeclaredMethods():返回此 Class 对象所表示的类或接口的全部方法
  • public Method[] getMethods():返回此 Class 对象所表示的类或接口的 public 的方法
  • public Class<?> getReturnType():取得全部的返回值
  • public Class<?>[] getParameterTypes():取得全部的参数
  • public int getModifiers():取得修饰符
  • public Class<?>[] getExceptionTypes():取得异常信息
	@Test
    public void test1() {
        Class<Person> clazz = Person.class;

        //getMethods():获取当前运行时类及其父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for (Method method: methods) {
            System.out.println(method);
        }

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

        //getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method: declaredMethods) {
            System.out.println(method);
        }
    }

    /*
    @Xxx
    权限修饰符 返回值类型 方法名(参数名1, 参数名2) throws xxxException{}
     */
    @Test
    public void test2() {
        Class<Person> clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method: declaredMethods) {
            //1.获取方法声明的注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation: annotations) {
                System.out.println(annotation);
            }

            //2.权限修饰符
            System.out.print(Modifier.toString(method.getModifiers())+"\t");

            //3.返回值类型
            System.out.print(method.getReturnType().getName() + "\t");

            //4.方法名
            System.out.print(method.getName());
            System.out.print("(");
            //5.形参列表
            Class<?>[] parameterTypes = method.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 = method.getExceptionTypes();
            if (exceptionTypes != null && exceptionTypes.length > 0) {
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length -1) {
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ", ");
                }
            }

            System.out.println();
        }
    }

14.5.5 Field

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

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

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

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

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

@Test
    public void test1() {
        Class<Person> clazz = Person.class;

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

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

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

    //权限修饰符 数据类型 变量名
    @Test
    public void test2() {
        Class<Person> clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field de: declaredFields) {
            //1.权限修饰符
            int modifiers = de.getModifiers();
            System.out.print(Modifier.toString(modifiers)+"\t---");

            //2.数据类型
            Class<?> type = de.getType();
            System.out.print(type+"\t---");

            //3.变量名
            System.out.println(de.getName());
            /*
            private	---class java.lang.String	---name
                ---int	---age
            public	---int	---id
             */
        }
    }

14.6 调用运行时类的指定结构

14.6.1 调用指定方法

  • getMethod(String name,Class…parameterTypes):取得一个 Method 对象

  • Object invoke(Object obj, Object[] args)

    • Object 对应原方法的返回值,若原方法无返回值,此时返回 null

    • 若原方法若为静态方法,此时形参 Object obj 可为 null

    • 若原方法形参列表为空,则 Object[] args 为 null

    • 若原方法声明为 private,则需要在调用此invoke()方法前,显式调用方法对象的 setAccessible(true) 方法,将可访问 private 的方法

@Test
public void testMethod() throws Exception {

    Class clazz = Person.class;

    //创建运行时类的对象
    Person p = (Person) clazz.newInstance();

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

    //2.保证当前方法是可访问的
    //setAccessible(true)
    show.setAccessible(true);
    /*
    3.
    invoke():参数一:方法的调用者。参数二:给方法形参赋值的形参
    invoke()的返回值即为对应类中调用的方法的返回值
     */
    Object invoke = show.invoke(p, "中国");
    System.out.println(invoke);

    System.out.println("*************如何调用静态方法******************");

    Method showDesc = clazz.getDeclaredMethod("showDesc");
    showDesc.setAccessible(true);
    //Object invoke1 = showDesc.invoke(p);
    //静态方法可以不用设置对象,用null值即可
    Object invoke1 = showDesc.invoke(null);
    //Object invoke1 = showDesc.invoke(Person.class);
    System.out.println(invoke1);//null
}

14.6.2 调用指定属性

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

    //创建运行时类的对象
    Person p = (Person) clazz.newInstance();

    //getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
    Field name = clazz.getDeclaredField("name");

    //setAccessible(true):保证当前属性是可访问的
    name.setAccessible(true);
    //set():参数一:指明设置哪个对象的属性,参数二:将此属性值设置为多少
    name.set(p, "张三");
    /*
    获取当前属性的值
    get():参数一:获取哪个对象的额当前属性值
     */
    System.out.println(name.get(p));
}

14.6.3 调用指定构造器

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

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

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

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

14.7 动态代理

14.7.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 NickClothFactory implements ClothFactory {

    @Override
    public void produceCloth() {
        System.out.println("Nick工厂生产一批运动服");
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象
        NickClothFactory nickClothFactory = new NickClothFactory();

        //创建代理类的对象
        ProxyClothFactory clothFactory = new ProxyClothFactory(nickClothFactory);

        clothFactory.produceCloth();
    }
}

14.7.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 HumanUtil {
    public void method1() {
        System.out.println("************************通用方法一************************");
    }

    public void method2() {
        System.out.println("************************通用方法二************************");
    }
}

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

 */
class ProxyFactory {
    //调用此方法,返回一个代理类的对象。解决问题一
    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 {

        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        /*
        method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        obj:被代理类的对象
         */
        Object value = method.invoke(obj, args);
        //上述方法的返回值就作为当前类中的invoke()的返回值
        humanUtil.method2();
        return value;
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();

        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);

        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");

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

        NickClothFactory nickClothFactory = new NickClothFactory();
        ClothFactory instance = (ClothFactory)ProxyFactory.getProxyInstance(nickClothFactory);
        instance.produceCloth();

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【完整课程列表】 资源汇总下载地址:https://download.csdn.net/download/qq_27595745/55418618 Java SE编程入门教程 collection与collections(共7页).pptx Java SE编程入门教程 java GC(共6页).pptx Java SE编程入门教程 java instanceof(共3页).pptx Java SE编程入门教程 java IO(共28页).pptx Java SE编程入门教程 java Math(共11页).pptx Java SE编程入门教程 java object(共9页).pptx Java SE编程入门教程 java static final(共24页).pptx Java SE编程入门教程 java this和super(共10页).pptx Java SE编程入门教程 java 常用API(共22页).pptx Java SE编程入门教程 javaGUI编程快速入门(1)(共82页).pptx Java SE编程入门教程 java包装器(共9页).pptx Java SE编程入门教程 java反射机制(共16页).pptx Java SE编程入门教程 java泛型(共11页).pptx Java SE编程入门教程 java封装继承多态(共56页).pptx Java SE编程入门教程 java集合(共38页).pptx Java SE编程入门教程 java接口(共21页).pptx Java SE编程入门教程 java类和对象方法以及包的使用(共56页).pptx Java SE编程入门教程 java类和对象方法以及包的使用(共62页).pptx Java SE编程入门教程 java判断循环(共79页).ppt Java SE编程入门教程 java入门以及变量debug(共63页).pptx Java SE编程入门教程 java设计模式(共17页).pptx Java SE编程入门教程 java数组(共33页).pptx Java SE编程入门教程 java网络编程(共29页).pptx Java SE编程入门教程 java线程(共61页).pptx Java SE编程入门教程 java序列化(共14页).pptx Java SE编程入门教程 java异常(共57页).pptx Java SE编程入门教程 java正则(共8页).pptx Java SE编程入门教程 properties(共3页).pptx Java SE编程入门教程 String字符串(共27页).pptx Java 位运算.docx java正则表达式例子大全 共10页.doc JAVA正则表达式实例教程 共17页.docx JAVA正则表达式实例教程 共17页.pdf 递归算法.docx 堆和栈.wps

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值