java反射

反射

反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量,成员方法,构造方法)
反射就是让你动态的操作Java语言,让你可以在程序运行的时候获取类的结构:属性,构造函数,方法等一切信息,并且操作这些信息。
前提:要获得该类字节码文件对象,就是Class对象
实际开发中的应用:

开发IDE(集成开发环境),比如IDEA,Eclipse
各种框架的设计和学习 比如Spring,Hibernate,Struct,Mybaits…

Class对象的三种获取方式

方式1: 通过类名.class获得
方式2:通过对象名.getClass()方法获得
方式3:通过Class类的静态方法获得: static Class forName(“类全名”)
每一个类的Class对象都只有一个。

public static void main(String[] args) throws ClassNotFoundException {
        Class<Chirld> l1 = Chirld.class;
        Chirld chirld = new Chirld();
        Class<? extends Chirld> l2 = chirld.getClass();
        Class l3 = Class.forName("com.zlxd.controller.Chirld");
        System.out.println(l1==l2);
        System.out.println(l2==l3);
        System.out.println(l2);
        System.out.println(chirld);
    }
true
true
class com.zlxd.controller.Chirld
com.zlxd.controller.Chirld@4459eb14

获取Class对象的三种方法比较

public class Student{
	static{
		System.out.println("静态代码块执行");
	}
	{
        System.out.println("构造代码块执行");
    }
     public Student(){
        System.out.println("构造方法执行");
    }
}

  • 第一种方式:使用 .class 方法。
public class TestDemo {
    public static void main(String[] args) {
        System.out.println("======1======");
        Class<Student> clazz1 = Student.class;
//        Class<?> clazz1 = Student.class;
    }
}

在这里插入图片描述
说明:JVM将使用类装载器,将类装入内存(前提是:类还没有装入内存),不做类的初始化工作,返回Class的对象。

  • 第二种方法:使用 Class.forName 静态方法。
public class TestDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("======2======");
        Class<?> clazz2 = Class.forName("daycode.Student");
    }
}

在这里插入图片描述
说明:装入类,并做类的静态初始化,返回Class的对象。

  • 第三种方法:使用类对象的 getClass() 方法
public class TestDemo {
    public static void main(String[] args){
        System.out.println("======3======");
        Class<? extends Student> clazz3 = new Student().getClass();
    }
}

在这里插入图片描述
说明:对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象(子对象的引用会赋给父对象的引用变量中)所属的类的Class的对象。

class对象是单例的?YES

public class TestDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<Student> clazz1 = Student.class;
        Class<?> clazz2 = Class.forName("daycode.Student");
        Class<? extends Student> clazz3 = new Student().getClass();
        System.out.println(clazz1 == clazz2 && clazz2 == clazz3);
    }
}

在这里插入图片描述

Class类常用方法

  • String getSimpleName(); 获得类名字符串:类名
  • String getName(); 获得类全名:包名+类名
  • T newInstance() ; 创建Class对象关联类的对象
public static void main(String[] args) throws ClassNotFoundException {
        Class l1 = Chirld.class;
        //获取类名字符创
        System.out.println(l1.getSimpleName());
        // 获得类全名:包名+类名
        System.out.println(l1.getName());
        // 创建对象
        Chirld stu = (Chirld) l1.newInstance();
        System.out.println(stu);
    }
Chirld
com.zlxd.controller.Chirld
com.zlxd.controller.Chirld@4459eb14    

反射之操作构造方法

Constructor类概述

反射之操作构造方法的目的:获得Constructor对象来创建类的对象。
Constructor类概述:类中的每一个构造方法都是一个Constructor类的对象

Class类中与Constructor相关的方法

    1. Constructor getConstructor(Class… parameterTypes)
      • 根据参数类型获得对应的Constructor对象。
      • 只能获得public修饰的构造方法
    1. Constructor getDeclaredConstructor(Class… parameterTypes)
      • 根据参数类型获得对应的Constructor对象,包括private
    1. Constructor[] getConstructors()
      获得类中的所有构造方法对象,只能获得public的
    1. Constructor[] getDeclaredConstructors()
      获得类中的所有构造方法对象,包括private修饰的

Constructor对象常用方法

    1. T newInstance(Object… initargs)
      根据指定的参数创建对象
    1. void setAccessible(true)
      设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)

示例代码:

public class Chirld extends Father{
    private String str;
    private String name;
    private Integer age;
    public Chirld(String str) {
        this.str = str;
        System.out.println("Chirld(String str)");
    }
    public Chirld(int str) {
        this.age = str;
        System.out.println("Chirld(Integer str)");
    }
    public Chirld(String str,String name) {
        this.str = str;
        this.name = name;
        System.out.println("Chirld(String str,String name)");
    }
    public Chirld() {
        System.out.println("Chirld()");
    }
    private Chirld(String name,Integer id){
        System.out.println("Chirld(String name,Integer id)");
    };
    @SneakyThrows
    public static void main(String[] args) throws ClassNotFoundException {
        Class l1 = Chirld.class;
        //获取类名字符创
        System.out.println(l1.getSimpleName());
        // 获得类全名:包名+类名
        System.out.println(l1.getName());
        // 创建对象
        Chirld stu = (Chirld) l1.newInstance();
        //System.out.println(stu);
        Chirld chirld = (Chirld)l1.getConstructor().newInstance();//只能获取public修饰的构造方法
        Chirld chirld1 = (Chirld)l1.getConstructor(String.class).newInstance("asdf");//只能获取public修饰的构造方法
        Chirld chirld2 = (Chirld)l1.getDeclaredConstructor(String.class,Integer.class).newInstance("asdf",1);//私有和公共的都能获取
        Chirld chirld3 = (Chirld)l1.getDeclaredConstructor(int.class).newInstance(1);;//私有和公共的都能获取
        Constructor[] constructors = l1.getConstructors();
        for (int i = 1; i < constructors.length; ++i) {
            System.out.print("StringBuilder Class Public Constructors");
            System.out.println(constructors[i]);
        }
        Constructor[] declaredConstructors = l1.getDeclaredConstructors();
        for (int i = 1; i < declaredConstructors.length; ++i) {
            System.out.print("StringBuilder Class private Constructors");
            System.out.println(declaredConstructors[i]);
        }
    }
    public String getStr() {
        return str;
    }
    public void setStr(String str) {
        this.str = str;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Chirld
com.zlxd.controller.Chirld
Chirld()
Chirld()
Chirld(String str)
Chirld(String name,Integer id)
Chirld(Integer str)
StringBuilder Class Public Constructorspublic com.zlxd.controller.Chirld(java.lang.String,java.lang.String)
StringBuilder Class Public Constructorspublic com.zlxd.controller.Chirld(int)
StringBuilder Class Public Constructorspublic com.zlxd.controller.Chirld(java.lang.String)
StringBuilder Class private Constructorspublic com.zlxd.controller.Chirld()
StringBuilder Class private Constructorspublic com.zlxd.controller.Chirld(java.lang.String,java.lang.String)
StringBuilder Class private Constructorspublic com.zlxd.controller.Chirld(int)
StringBuilder Class private Constructorspublic com.zlxd.controller.Chirld(java.lang.String)

总结:

  • 通过Class对象的getConstructors方法获取该类的全部构造函数。使用不同参数调用getConstructor方法能够获取该类的不同构造函数。
  • 将对应构造函数签名参数列表的参数传入构造函数的newInstance方法能够对对象进行实例化并根据构造方法参数类型添加实参。
  • 在Class对象的getConstructor方法中传入该类所不具有的构造函数参数列表时,将出现异常。
  • 私有的构造函数也能获取到。

反射之操作方法

Method类概述:
反射之操作方法的目的
* 操作Method对象来调用成员方法
Method类概述
* 每一个方法都是一个Method类的对象。

Class类中与Method相关的方法
  • Method getMethod(String name,Class…args);

    • 根据方法名和参数类型获得对应的方法对象,只能获得public的
  • Method getDeclaredMethod(String name,Class…args);

    • 根据方法名和参数类型获得对应的方法对象,包括private的
  • Method[] getMethods();

    • 获得类中的所有方法对象,返回数组,只能获得public修饰的且包含父类的
  • Method[] getDeclaredMethods();

    • 获得类中的所有方法对象,返回数组,只获得本类的,包含private修饰的
Method对象常用方法
  • Object invoke(Object obj, Object… args)
    • 调用指定对象obj的该方法
    • args:调用方法时传递的参数
  • void setAccessible(true)
    设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)

示例代码

public class Chirld extends Father{
    private String str;
    private String name;
    private Integer age;
    public Chirld(String str) {
        this.str = str;
        System.out.println("Chirld(String str)");
    }
    public Chirld(int str) {
        this.age = str;
        System.out.println("Chirld(Integer str)");
    }
    public Chirld(String str,String name) {
        this.str = str;
        this.name = name;
        System.out.println("Chirld(String str,String name)");
    }
    public Chirld() {
        System.out.println("Chirld()");
    }
    private Chirld(String name,Integer id){
        System.out.println("Chirld(String name,Integer id)");
    };
    public String getStr() {
        return str;
    }
    public void setStr(String str) {
        this.str = str;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
        System.out.println(name);
    }
    public static void setName1(String name) {
        System.out.println(name);
    }

    @SneakyThrows
    public static void main(String[] args) throws ClassNotFoundException {
        Class l1 = Chirld.class;
        Chirld stu = (Chirld) l1.newInstance();
        Objects ob= l1.newInstance();
        Method getName = l1.getMethod("getName");
        System.out.println(getName);
        Method getName1 = l1.getDeclaredMethod("setName1",String.class);
        System.out.println(getName1);
        Method[] methods = l1.getMethods();//获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
        for (int i = 1; i < methods.length; ++i) {
            System.out.print("StringBuilder Class Public childandfather");
            System.out.println(methods[i]);
        }
        Method[] method= l1.getDeclaredMethods();//获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
        for (int i = 1; i < method.length; ++i) {
            System.out.print("StringBuilder Class Public childandfather");
            System.out.println(method[i]);
        }
        Method setName = l1.getMethod("setName",String.class);
        //成员方法调用需要添加对象参数
        setName.invoke(stu,"asdf========================================");
        setName.invoke(ob,"asdf========================================");//与上面结果一致
        //静态方法调用可以添加对象也可以不加为null
        getName1.invoke(null,"asdfdasasfsafa===========");
        getName1.invoke(stu,"asdfdasasfsafa===========");
    } 

StringBuilder Class Public childandfatherpublic final native java.lang.Class java.lang.Object.getClass()
StringBuilder Class Public childandfatherpublic final native void java.lang.Object.notify()
StringBuilder Class Public childandfatherpublic final native void java.lang.Object.notifyAll()
StringBuilder Class Public childandfatherpublic java.lang.String com.zlxd.controller.Chirld.getName()
StringBuilder Class Public childandfatherpublic void com.zlxd.controller.Chirld.setName(java.lang.String)
StringBuilder Class Public childandfatherpublic void com.zlxd.controller.Chirld.setStr(java.lang.String)
StringBuilder Class Public childandfatherpublic static void com.zlxd.controller.Chirld.setName1(java.lang.String)
StringBuilder Class Public childandfatherpublic java.lang.String com.zlxd.controller.Chirld.getStr()
asdf========================================
asdf========================================
asdfdasasfsafa===========
asdfdasasfsafa===========
 

总结:

  • 1静态方法调用的时候传入可以是对象也可以为null成员方法调用必须传入对象
  • 2getMethods获取父类中只能是public的方法

反射之操作变量

Field类概述

反射之操作变量的目的
* 通过Field对象给对应的变量赋值和取值

Field类概述
* 每一个成员变量都是一个Field类的对象。

Class类中与Field相关的方法
  • Field getField(String name);
    • 根据成员变量名获得对应Field对象,只能获得public修饰
  • Field getDeclaredField(String name);
    • 根据成员变量名获得对应Field对象,包含private修饰的
  • Field[] getFields();
    • 获得所有的成员变量对应的Field对象,只能获得public的
  • Field[] getDeclaredFields();
    • 获得所有的成员变量对应的Field对象,包含private的
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)

  • Object get(Object obj)

  • int getInt(Object obj)

  • long getLong(Object obj)

  • boolean getBoolean(Object ob)

  • double getDouble(Object obj)

  • void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。

  • Class getType(); 获取属性的类型,返回Class对象。

setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。
getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法。

示例代码

public class ReflectDemo05 {
    /*
        Field[] getFields();
            * 获得所有的成员变量对应的Field对象,只能获得public的
        Field[] getDeclaredFields();
            * 获得所有的成员变量对应的Field对象,包含private的
     */
    @Test
    public void test02() throws Exception {
        // 获得Class对象
        Class c  = Student.class;
        // 获得所有的成员变量对应的Field对象
        // Field[] fields = c.getFields();
        // 获得所有的成员变量对应的Field对象,包括private
        Field[] fields = c.getDeclaredFields();
        for (Field f: fields) {
            System.out.println(f);
        }
    }

    /*
        Field getField(String name);
            根据成员变量名获得对应Field对象,只能获得public修饰
        Field getDeclaredField(String name);
            *  根据成员变量名获得对应Field对象,包含private修饰的
     */
    @Test
    public void test01() throws Exception {
        // 获得Class对象
        Class c  = Student.class;
        // 创建对象
        Object obj = c.newInstance();
        // 获得成员变量name对应的Field对象
        Field f = c.getField("name");
        // 给成员变量name赋值
        // 给指定对象obj的name属性赋值为jack
        f.set(obj,"jack");

        // 获得指定对象obj成员变量name的值
        System.out.println(f.get(obj)); // jack
        // 获得成员变量的名字
        System.out.println(f.getName()); // name


        // 给成员变量gender赋值
        // 获得成员变量gender对应的Field对象
        Field f1 = c.getDeclaredField("gender");
        // 暴力反射
        f1.setAccessible(true);
        // 给指定对象obj的gender属性赋值为男
        f1.set(obj,"男");

        System.out.println(obj);

    }
}
setAccessible应用

实际开发中,setAccessible具体的用处主要有两处:
作用于方法上,method.setAccessible(true);

public static void test02() throws Exception{
		User u = new User();
		Class clazz = u.getClass();
		Method m = clazz.getDeclaredMethod("getUname", null);
		m.setAccessible(true);
		m.invoke(u, null);	
	}

作用于属性上,field.setAccessible(true);

if (field.isAnnotationPresent(TestIdSign.class)){
            try {
                field.setAccessible(true);
                field.set(object,testId);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("set testID illegalAccessException",e);
            }
        }

将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查;实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问 ;

由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值