JAVA反射机制

 1.反射机制入门

 1.1反射机制原理:

 

 1.2JAVA反射机制可以完成:

1.在运行时判断任意一个对象所属的对象

2.在运行时构造一个类的对象

3.在运行时得到任意一个类所具有的成员变量和方法

4.在运行时调用任意一个对象的成员变量和方法

5.生成动态代理

反射相关的主要类:

1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象

2.java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法

3.java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量

        getFiled()不能得到私有属性

4.java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器

实例:

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

public class Reflection01 {
    public static void main(String[] args) throws Exception {
        //1.使用Properties类,读写文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath=properties.get("classfullpath").toString();
        String method=properties.get("method").toString();
        System.out.println("classfullpath="+classfullpath);
        System.out.println("method"+method);

        //2.使用反射机制解决问题
        //(1)加载类,返回Class类型的对象cls
        Class cls = Class.forName(classfullpath);
        //(2)通过cls得到类的对象的实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型="+o.getClass());
        //(3)通过cls得到加载类的com.reflection.Cat的method"hi"的方法对象
        //在反射中,可以把方法视为对象
        Method method1 = cls.getMethod(method);
        //通过method1调用方法,即通过方法对象来实现调用方法
        method1.invoke(o);//传统方法 对象.方法()    反射机制 方法.invoke(对象)  符合开闭原则

        //java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
        //Field name = cls.getField("name"); 不能获取私有属性
        Field age = cls.getField("age");
        System.out.println(age.get(o));//传统写法 对象.成员变量    反射:成员变量.get(对象)

        //java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
        Constructor constructor = cls.getConstructor();
        System.out.println(constructor);

        //()里面可以指定构造器的参数类型,返回有参构造器 没有东西则返回无参构造器
        Constructor constructor1 = cls.getConstructor(String.class);//String.class就是String类的class对象
        System.out.println(constructor1);
    }
}
1.3反射机制的优点与缺点

优点:可以动态的创建和使用对象,使用灵活,没有反射机制框架技术就会失去底部支撑

缺点:使用反射机制是执行解释,对执行的速度有影响

反射调用优化--关闭访问检查

1.Method和Field、Constructor对象都有setAccessible()方法

2.setAccessible作用是启动禁用访问安全检查的开关

3.参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false表示反射的对象执行访问检查

代码:

import java.lang.reflect.Method;

public class Reflection02 {
    public static void main(String[] args) throws Exception {
        m1();
        m2();
        m3();
    }

    //传统方法调用hi()方法
    public static void m1() {
        Cat cat = new Cat();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 99999999; i++) {
            cat.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法耗时="+(end-start));
    }

    //反射机制调用方法
    public static void m2() throws Exception {
        Class aClass = Class.forName("com.reflection.Cat");
        Object o = aClass.newInstance();
        Method hi = aClass.getMethod("hi");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 99999999; i++) {
            hi.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制调用方法耗时="+(end-start));
    }

    //反射调用优化+关闭访问检查
    public static void m3() throws Exception {
        Class aClass = Class.forName("com.reflection.Cat");
        Object o = aClass.newInstance();
        Method hi = aClass.getMethod("hi");
        hi.setAccessible(true);//在反射调用方法时,取消访问检查
        long start = System.currentTimeMillis();
        for (int i = 0; i < 99999999; i++) {
            hi.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制优化后调用方法耗时="+(end-start));
    }
}

2.Class类分析

2.1.基本介绍

1.Class也是类,因此也继承Object类

2.Class类不是new出来的,而是由系统创建的

3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次

4.每个类的实例都会记得自己是由哪个Class实例生成

5.通过Class可以完整的得到一个类的完整结构,通过一系列的API

6.Class类对象时存放在堆里面的

7.类的字节码二进制数据放在方法区,有的地方称为类的元数据(包括类的方法代码,变量,方法名,访问权限等等)

 2.2Class类的常用方法 

演示:

import java.lang.reflect.Field;

public class Class02 {
    public static void main(String[] args) throws Exception {
        String classFullPath="com.class_.Person";
        //1.获取Person对应的Class类对象
        Class<?> pClass = Class.forName(classFullPath);
        //2.显示cls对象是哪个类的Class对象  "com.class.Person"
        System.out.println(pClass);
        System.out.println(pClass.getClass());//输出pClass的运行类型 java.lang.Class
        //3.得到包名
        System.out.println(pClass.getPackage().getName());//com.class_
        //4.得到全类名
        System.out.println(pClass.getName());//com.class_.Person
        //5.通过反射创建实例
        Person person =(Person)pClass.newInstance();
        System.out.println(person);//Person{name='小张', age=12, gender='nan'}
        //6.通过反射获取属性
        Field name = pClass.getField("name");
        System.out.println(name.get(person));//小张
        //7.通过反射给属性字段赋值
        name.set(person,"小王");
        System.out.println(name.get(person));//小王
        //8.获得所有的属性
        Field[] fields = pClass.getFields();
        for (Field f: fields) {
            System.out.println(f.getName());
        }
    }
}
2.3获取Class类对象的6种方法

 

演示:

public class Class03 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.通过Class.forName
        String classFullPath="com.class_.Person";//可以通过读取配置文件获取
        Class<?> cls1 = Class.forName(classFullPath);
        System.out.println(cls1);

        //2.类名.class  应用场景:用于参数传递
        //()里面可以指定构造器的参数类型,返回有参构造器 没有东西则返回无参构造器
        //如:Constructor constructor1 = cls.getConstructor(String.class);//String.class就是String类的class对象
        Class<Person> cls2 = Person.class;
        System.out.println(cls2);

        //3.对象.getClass() 多用于有对象实例
        Person person = new Person();
        Class<? extends Person> cls3 = person.getClass();
        System.out.println(cls3);

        //4.通过类加载器[4种]来获取类的Class对象
        //(1)先获得类加载器personLoader
        ClassLoader personLoader = person.getClass().getClassLoader();
        //(2)通过类加载器得到Class对象
        Class<?> cls4 = personLoader.loadClass(classFullPath);
        System.out.println(cls4);

        //5.基本数据类型(int,char,boolean,float,double,byte,long,short)按下面的方法得到Class类对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Double> doubleClass = double.class;
        System.out.println(integerClass);//int

        //6.基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
        Class<Integer> type = Integer.TYPE;
        Class<Double> type1 = Double.TYPE;
        System.out.println(type);//int
    }
}
 2.4如下类型有Class类对象

1.外部类,成员接口,静态内部类,局部内部类,匿名内部类

2.interface:接口

3.数组

4.enum:枚举

5.annotation:注释

6.基本数据类型

7.void

演示:

import java.io.Serializable;

public class AllTypeClass {
    public static void main(String[] args) {
        Class<String> cls1 = String.class;//外部类
        Class<Serializable> cls2 = Serializable.class;//接口
        Class<Integer[]> cls3 = Integer[].class;//数组
        Class<float[][]> cls4 = float[][].class;//二维数组
        Class<Deprecated> cls5 = Deprecated.class;//注解
        Class<Thread.State> cls6 = Thread.State.class;//枚举
        Class<Long> cls7 = long.class;//基本数据类型
        Class<Void> cls8 = void.class;//void
        Class<Class> cls9 = Class.class;
    }
}

3.类加载

3.1静态加载与动态加载

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

1.静态加载:编译时加载相关的类,如果没有就会报错,依赖性太强

2.动态加载:运行时加载需要的类,如果运行时没有用到该类,则不报错,降低依赖性

类加载的时机:

1.当创建对象时(new) ->静态加载

2.当子类被加载时 ->静态加载

3.调用类中的静态成员时 ->静态加载

4.通过反射 ->动态加载

实例:

3.2类加载流程图

 类加载的三个主要阶段

●加载阶段:JVM在该阶段主要目的是将字节码从不同的数据源(可能是class文件,也可能是jar包,甚至是网络)转化为二进制字节流加载到内存当中,并生成一个代表该类的java.lang.Class对象 

●连接阶段

①验证:

1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

2.包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证

3.可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

②准备:JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始化值,如0,0L,null,false等),这些变量所使用的内存都将在方法区中进行分配

//1.n1是实例属性,不是静态变量,因此在准备阶段不会分配内存

//2.n2是静态变量,分配内存n2是默认初始化0,而不是20

//3.n3是static final为常量,与静态变量不一样,因为一旦赋值就不变 n3=30

public int n1=10;

public static int  n2=20;

public static final int n3=30;

③解析:虚拟机将常量池内的符号引用替换为直接引用的过程

●初始化阶段

1.到初始化阶段才真正开始执行类中定义的Java程序,此阶段是执行<clinit>()方法的过程;

2.<clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和·静态代码块中的语句,并进行合并。

3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁,同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。

3.3获取类结构信息

通过反射获取类的结构信息

演示实例:

package com.reflection;

import org.junit.Test;

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

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

    }

    //第一组API
    @Test
    public void m1() throws ClassNotFoundException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.reflection.Person");
        //1.getName:获取全类名
        System.out.println(personCls.getName());
        //2.getSimpleName:获取简单类名
        System.out.println(personCls.getSimpleName());
        //3.getFields:获取所有public修饰的属性,包含本类以及超类的
        Field[] fields = personCls.getFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println("本类以及父类的public属性:"+fields[i].getName());
        }
        //4.getDeclaredFields:获取本类的所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField: declaredFields) {
            System.out.println("本类的所有属性:"+declaredField.getName());
        }
        //5.getMethods:获取本类以及父类所有的public方法
        Method[] methods = personCls.getMethods();
        for (Method method: methods) {
            System.out.println("本类以及父类的public方法:"+method.getName());
        }
        //6.getDeclaredMethods:获取本类所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod: declaredMethods) {
            System.out.println("本类所有的方法"+declaredMethod.getName());
        }
        //7.getConstructors:获取本类的所有public构造器
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor constructor: constructors) {
            System.out.println("本类所有public构造器"+constructor.getName());
        }
        //8.getDeclaredConstructors:获取本类所有的构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor deconstructor:declaredConstructors) {
            System.out.println("本类所有的构造器:"+deconstructor.getName());
        }
        //9.getPackage:以Package的方式返回包的信息
        System.out.println("包的信息:"+personCls.getPackage());
        //10.getSuperClass:以Class形式返回父类信息
        System.out.println("父类信息:"+personCls.getSuperclass());
        //11.getInterfaces:以Class[]形式返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class ainterface:interfaces) {
            System.out.println("接口信息:"+ainterface);
        }
        //12.getAnnotations:以Annotation[]形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation:annotations) {
            System.out.println("注解信息:"+annotation);
        }
    }

    @Test
    public void m2() throws ClassNotFoundException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.reflection.Person");
        //getDeclaredFields:获取本类的所有属性
        //规定说明 :默认修饰符0  public 1   private  2    protected  4
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField: declaredFields) {
            System.out.println("本类的所有属性:"+declaredField.getName()+",该属性的修饰符值="+declaredField.getModifiers()
                    +",该属性的类型:"+declaredField.getType());
        }

        //getDeclaredMethods:获取本类所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod: declaredMethods) {
            System.out.println("本类所有的方法"+declaredMethod.getName()+",该方法的访问修饰符值="+declaredMethod.getModifiers()
            +",该方法的返回值类型="+declaredMethod.getReturnType());

            //输出当前方法的形参数组
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class parameterType:parameterTypes) {
                System.out.println("该方法的形参类型="+parameterType);
            }
        }

        //getDeclaredConstructors:获取本类所有的构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor deconstructor:declaredConstructors) {
            System.out.println("本类所有的构造器:"+deconstructor.getName());

            Class[] parameterTypes = deconstructor.getParameterTypes();
            for (Class parameterType:parameterTypes) {
                System.out.println("该构造器的形参类型="+parameterType);
            }
        }
    }
}

class A {
    public String aa;
    protected int bb;
    String cc;
    private double dd;

    public A() {
    }

    private A(String aa) {
        this.aa = aa;
    }

    public void b1(){

    }

    protected  void b2() {

    }

    void b3() {

    }

    private void b4() {

    }
}

interface IA{}
interface IB{}

@Deprecated
class Person extends A implements IA,IB{
    public String name;
    protected int age;
    String job;
    private double sal;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    public void a1(String name,int age,double sal){

    }

    protected  void a2() {

    }

    void a3() {

    }

    private void a4() {

    }
}

3.4反射爆破

1.通过反射创建对象

  • 方法一:调用类中public修饰的无参构造器
  • 方法二:调用类中指定构造器
  • Class类相关方法

        ①newInstance:调用类中的无参构造器,获取对应类的对象

        ②getConstructor(  Class  ):根据参数列表,获取对应的构造器对象

        ③getDeclaredConstructor(  Class ):根据参数列表,获取对应的构造器对象

  • Constructor类相关方法

        ①setAccessible:爆破

        ②newInstance(Object ):调用构造器

实例:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.先获取User的Class对象
        Class<?> userCls = Class.forName("com.reflection.User");
        //2.通过public无参构造器创建实例
        Object o = userCls.newInstance();
        System.out.println(o);
        //3.通过public有参构造器创建实例
        /*
        constructor对象即
            public User(String name, int age) {
            this.name = name;
            this.age = age;
    }
         */
        Constructor<?> constructor = userCls.getConstructor(String.class,int.class);
        Object xiaoMing = constructor.newInstance("小明", 12);
        System.out.println(xiaoMing);
        //4.通过非public有参构造器创建实例
        Constructor<?> declaredConstructor = userCls.getDeclaredConstructor(String.class);
        //爆破:暴力破解 ,使用反射可以访问private构造器/方法/属性
        declaredConstructor.setAccessible(true);
        Object xiaoHong = declaredConstructor.newInstance("小红");
        System.out.println(xiaoHong);
    }
}

class User{
    private String name;
    private int age;

    public User() {
    }

    private User(String name) {
        this.name = name;
    }

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

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

2.通过反射操作类中的属性

  • 根据属性名过去Field对象    Field f=Class对象.getDeclaredField(属性名)
  • 爆破:f.setAccessible(true)
  • 访问 f.set(o.值)       f.get(o)
  • 如果是静态属性,则set和get中的参数o,可以写成null

实例:

import java.lang.reflect.Field;

public class ReflectAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.获取Class对象
        Class<?> stuCls = Class.forName("com.reflection.Student");
        //2.创建对象
        Object o = stuCls.newInstance();
        System.out.println(o.getClass());
        //3.使用反射得到属性
        Field name = stuCls.getField("name");
        name.set(o,"Jane");
        System.out.println(o);
        System.out.println(name.get(o));
        //4.操作私有静态属性
        Field age = stuCls.getDeclaredField("age");
        age.setAccessible(true);
        //age.set(o,12);
        age.set(null,12);//因为age是static属性,o也可以写成null
        System.out.println(o);
        System.out.println(age.get(null));

    }
}

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

    public Student() {
    }

    private Student(String name) {
        this.name = name;
    }

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

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

3.通过反射操作类中的方法

  • 根据方法名和参数列表获取Method方法对象 Method m=Class.getDeclaredMethod
  • 获取对象 newInstance
  • 爆破 setAccessble
  • 访问:m.invoke(o)
  • 注意:如果是静态方法,invoke里面的参数可以写作o

实例:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectAccessMethod {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.获取Class对象
        Class<?> teaCls = Class.forName("com.reflection.Teacher");
        //2.创建对象
        Object o = teaCls.newInstance();
        //3.调用public方法
        Method hi = teaCls.getMethod("hi",String.class);
        hi.invoke(o,"hi");

        //4.调用private static方法
        Method hello = teaCls.getDeclaredMethod("hello", String.class);
        hello.setAccessible(true);//爆破
        hello.invoke(o,"你好");
        //hello.invoke(null,"你好~");

        //5.在反射当中,如果有返回值,统一返回Object 但是运行类型和方法定义的放回类型一样
        Object method = hi.invoke(o, "你们hi");
        System.out.println(method.getClass());
    }
}

class Teacher{
    public String name;
    private static int age;

    public Teacher() {
    }

    private Teacher(String name) {
        this.name = name;
    }

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

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

    public String hi(String s) {
        System.out.println("hi");
        return s;
    }

    private static void hello(String s) {
        System.out.println("hello");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ustinian.488

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值