java反射

92 阅读5分钟

java反射

认识反射

反射是框架设计的灵魂

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

反射就是加载类,并允许以编程的的方式解刨类中的各种成分(成员变量,方法、构造器等);

一、加载类,获取类的字节码:Class对象

特别注意:反射第一步,获取类的字节码:Class对象

反射111.png

获取Class对象的三种方式

  • Class c1= 类名.class
  • 调用class提供的方法: public static Class forName(String package);
  • Object提供的方法:public Class getClass(); Class c3=对象.getClass();

以下都用Student 类进行剖析

package 反射;
​
public class Studentss {
    private String names;
    private int age;
    private char sex;
    private double score;
​
    public Studentss() {
    }
​
    @Override
    public String toString() {
        return "Studentss{" +
                "names='" + names + ''' +
                ", age=" + age +
                ", sex=" + sex +
                ", score=" + score +
                '}';
    }
​
    public Studentss(String names, int age, char sex, double score) {
        this.names = names;
        this.age = age;
        this.sex = sex;
        this.score = score;
    }
​
    public String getNams() {
        return names;
    }
​
    public void setNames(String names) {
        this.names = names;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public char getSex() {
        return sex;
    }
​
    public void setSex(char sex) {
        this.sex = sex;
    }
​
    public double getScore() {
        return score;
    }
​
    public void setScore(double score) {
        this.score = score;
    }
}

获取Class对象

public class demo {
    public static void main(String[] args) throws Exception {
        //反射   反射第一步得到这个类的class 对象
        //获取class对象
         //第一种方式
        Class c1=Studentss.class;
​
        //第二种方式
       Class c2= Class.forName("java-code\src\反射\Studentss.java"); //里面是文件的位置
​
       //第三种方式
       Studentss s1=new Studentss();
      Class c3=s1.getClass();
    }
}

在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的

.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。运用

.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例

二、获取类的构造器

class提供了从类中获取构造器的方法。

方法说明
constructor<?>[] getConstructors()获取全部构造器(只能获取public修饰的))
Constructor<?>[] getDeclaredConstructors()获取全部构造器(只要存在就能拿到))
constructor getconstructor(class<?>... parameterTypes)获取某个构造器(只能获取public修饰的))
Constructor getDeclaredConstructor(class<?>... parameterTypes)获取某个构造器(只要存在就能拿到))

获取类的构造器的作用:依然是初始化一个对象返回

constructor提供的方法说明
T newInstance(object. . . initargs)调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
public class demo {
    public static void main(String[] args) throws Exception {
        //反射   反射第一步得到这个类的class 对象
        //获取class对象
//        第一种方式
        Class c1=Studentss.class;
​
        //获取类的构造器  无参数构造器
        Constructor constructor=c1.getConstructor();
        System.out.println(constructor.getName()+"-->"+
                constructor.getParameterCount());
​
        //获取有参构造器  里面需要加上参数类型
        System.out.println("获取有参构造器---------------");
        Constructor constructor1=c1.getConstructor(String.class,int.class
                ,char.class,double.class);
        System.out.println(constructor1.getName()+"-->"+
                constructor1.getParameterCount());
        //使用构造器创建对象
        Studentss stu= (Studentss) constructor1.newInstance("张三",18,'男',99);
        System.out.println(stu);

反射.Studentss-->0 获取有参构造器--------------- 反射.Studentss-->4 Studentss{names='张三', age=18, sex=男, score=99.0}

三、获取类的成员变量

Class提供了从类中获取成员变量的方法。

方法说明
public Field[] getFields()获取类的全部成员变量(只能获取public修饰的)
public Field[] getDeclaredFields()获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name)获取类的某个成员变量(只能获取public修饰的)
public Field getDeclaredField(string name)获取类的某个成员变量(只要存在就能拿到)

获取成员变量的作用:依然是赋值、取值

方法说明
void set(object obj, object value ) :赋值
object get(object obj)取值
public void setAccessible( boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
  //获取类的成员变量、
        //获取全部的成员变量
        Field[] field = c1.getFields();  //因为只可以获取public的变量,所以返回的是空
        for (Field field1 : field) {
            //输出变量的名字和类型
            System.out.println(field1.getName()+"-->"+field1.getType());
        }
        //获取全部存在的变量
        Field[] declaredField = c1.getDeclaredFields();
        for (Field field1 : declaredField) {
            System.out.println(field1.getName()+"-->"+field1.getType());
        }
​
        System.out.println("------获取单个变量-----"); //也是只可以获取public的变量
//        Field age = c1.getField("age");
//        System.out.println(age.getName()+"-->"+age.getType());
        Field age = c1.getDeclaredField("age");
        System.out.println(age.getName()+"-->"+age.getType());
        System.out.println("为变量赋值和获取值");
​
        //为变量赋值和获取值
        age.setAccessible(true);  //禁止检查访问控制
        age.set(stu,90);
        System.out.println(stu);
        //取值
        Object o =  age.get(stu);
        System.out.println(o);

四、获取成员类的方法

反射第一步,先的到Class 对象

Class提供了从类中获取成员方法的API。

方法说明
Method[] getMethods()获取类的全部成员方法(只能获取public修饰的)
Method[] getDeclaredMethods()获取类的全部成员方法(只要存在就能拿到)
Method getMethod(string name,class<?>... parameterTypes)获取类的某个成员方法(只能获取public修饰的)
Method getDeclaredMethod(String name,class<?>... parameterTypes)获取类的某个成员方法(只要存在就能拿到)

成员方法的作用:依然是执行

Method提供的方法说明
public object invoke(object obj,object. . . args)触发某个对象的该方法执行
public void setAccessible( boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
 //获取成员方法
        System.out.println("获取成员方法");
        Method[] methods = c1.getMethods(); //返回一个方法数组
        for (Method method : methods) {
            System.out.println(method.getName()+"-->"+method.getParameterCount()
            +"-->"+method.getReturnType());
        }
​
        //获取某个方法
        Method getNams = c1.getMethod("getNams");
//        当有方法重载的时候就需要指定参数的类型可以区分具体获取哪一个方法
//        Method getNams = c1.getMethod("getNams",String.class);
        System.out.println(getNams.getName()+"-->"+getNams.getParameterCount()
                +"-->"+getNams.getReturnType());
​
        //执行方法
        getNams.setAccessible(true); //禁止检查访问控制
        Object invoke = getNams.invoke(stu);
        System.out.println(invoke);  //张三

反射的作用、应用场景

反射的作用?

  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装
  • 最后重要的用途是:适合做java的框架,基本上,主流的框架都会基于反射设计出一些通用 的功能