Java中的反射(详细介绍)

反射

  • 一、反射常用的API
  • 二、反射的应用
    • 2.1 得到某个类的Class对象
    • 2.2 根据Class创建类对象
    • 2.3 获得构造方法
    • 2.4 获取其他方法,即普通方法
    • 2.5 调用方法
    • 2.6 获取属性

前言:
以前在物理课堂上就学习过反射的内容,而现在在java代码中,反射的意义又有所不同了。在Java中,反射就是通过某种机制,动态得到这个类所有信息(属性,方法,构造方法…), 也可以动态的调用这个类所有的属性,方法,构造方法…

一、反射常用的API

  1. Class类:反射的核心类,反射所有的操作都是围绕该类来生成的,通过它,可以获取类的属性,方法等内容;
  2. Field类:表示类的属性,可以获取和设置类中属性的值 Method类:表示类的方法,它可以用来获取类中方法的信息,或者执行方法
  3. Constructor类:表示类的构造方法

二、反射的应用

例子(有一个Student类):

/**
*  Student类
*/
public class Student {
    //属性
    private int id;
    private String name;
	//有参构造方法
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
	//无参构造方法
    public Student() {
    }
	//私有构造方法
    private Student(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
	//普通方法
    public void study(){
        System.out.println(this.name+"学生正在学习!!");
    }
	//toString()方法
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Student").append('[')
                .append("id=")
                .append(id)
                .append(",name=")
                .append(name)
                .append(']');
        return sb.toString();
    }
}

2.1 得到某个类的Class对象

  • 类名.class 得到该类的Class对象
  • 类的对象.getClass()
  • 通过Class类的static方法:. forName(类的全限定名); 类的全限定名: 包名.类名
//第一种方式: 类名.class
Class<Student> clazz = Student.class;
//第二种方式: 类的对象.getClass()
Student stu = new Student();
//Student本类, 子类 上界
Class clazz2 = stu.getClass();
//第三种: 通过Class类的static方法: forName(类的全限定名)
Class<?> clazz3  = Class.forName("com.fs.Student");

2.2 根据Class创建类对象

1.调用Class的newInstance() 调用公开的无参构造

IllegalAccessException 无法访问的异常:无参构造方法是private修饰

 Student stu =  clazz.newInstance();   // 相当于new Student() 

2.私有Constructor的newInstance()方法, 即创建指定构造函数
调用公开有参构造方法时:

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

创建对象:

//得到指定的构造方法,如果有多个参数,中间用","隔开
Constructor<Student> c1 = clazz.getDeclaredConstructor(int.class,String.class);
        Student  stu2  = c1.newInstance(1, "张三");

3.(私有)private修饰的构造方法
即调用例子中private方法时:

 private Student(int id) {  
     this.id = id; 
  }

创建对象:

Constructor<Student> c2 = clazz.getDeclaredConstructor(int.class);
//如果是private修饰,默认无法访问.
//可以设置允许访问private的  setAccessible(true)
c2.setAccessible(true);
Student  stu3  = c2.newInstance(1);

2.3 获得构造方法

(1)获得本类中所有的公开的构造方法,即private修饰的构造方法不能获得

Constructor[] cons = cls.getConstructors();
for(int i=0;i<cons.length;i++){
	System.out.println(cons[i]);
}

(2)获取本类中的所有构造方法,包括private修饰的构造方法

Constructor[] cons = cls.getDeclaredConstructors();
for(int i=0;i<cons.length;i++){
	System.out.println(cons[i]);
}

(3)获到本类中指定的某一个构造方法

//得到指定的构造 方法,如果有多个参数,中间用","隔开
Constructor con =  cls.getDeclaredConstructor(String.class,Integer.class);
//也可以使用另一种方式来获得:cls.getConstructor(parameterTypes)

2.4 获取其他方法,即普通方法

  1. 获得所有的方法,包括继承自父类的方法,但只能是public 修饰的方法
Method[] ms =  cls.getMethods();
for(int i=0;i<ms.length;i++){
	System.out.println(ms[i]);
}
  1. 获得本类所有的方法,不包括继承自父类的方法,但private 修饰的方法也能获得
Method[] ms =  cls.getDeclaredMethods();
for(int i=0;i<ms.length;i++){
	System.out.println(ms[i]);
}
  1. 获取某一个指定的方法
//获得指定方法(无参)
Method ms =  cls.getDeclaredMethod("show");
System.out.println(ms);
//获得指定方法(有参)
Method ms =  cls.getMethod("print", String.class);
System.out.println(ms);

注意:当使用private 修饰符时,要在调用方法前,将权限打开

ms.setAccessible(true);

2.5 调用方法

通过invoke调用方法,obj表示在哪个对象里调用方法,后续的参数都是方法的传入的参数

String str = (String) ms.invoke(obj, "测试有参方法");
System.out.println("方法执行的结果:"+str);

2.6 获取属性

(1)获取所有属性,包括继承自父类的属性,但不能得到private修饰的属性

Field [] fs = cls.getFields();
for(int i=0;i<fs.length;i++){
	System.out.println(fs[i]);
}

(2)获得所有私有属性

Field [] fs = cls.getDeclaredFields();
for(int i=0;i<fs.length;i++){
	System.out.println(fs[i]);
}

(3)获得某个指定的属性
//获得指定的属性

Field f = cls.getDeclaredField("mastername");
//mastername属性为私有的,所以要先解除封装
f.setAccessible(true);
System.out.println(f.get(obj));


//修改指定的属性
Field f = cls.getDeclaredField("mastername");
f.setAccessible(true);
f.set(obj, "lisi");
System.out.println(f.get(obj));

你可能感兴趣的:(java,jvm,开发语言)