目录
什么是反射?
反射的作用
反射的使用
什么是反射?
反射java语言中的一种机制,通过这种机制可以动态的实例化对象、读写属性、调用方法。
反射就是把java类中的各种成分映射成一个个的Java对象
反射的作用
通过反射可以使程序代码访问装载到JVM 中的类的内部信息
● 获取已装载类的成员变量信息
● 获取已装载类的方法
● 获取已装载类的构造方法信息
简单而言,就是在运行状态时, 能够去内存中通过权限类名找到对应的的Class对象,就能够调用类中的私有化的方法、属性。
反射的使用
首先我们准备一个测试类(Student)
package com.ljq.mymvc.reflect;
/**
* 测试类
*
* @author 一麟
*
*/
public class Student {
private String sid;
private String sname;
public Integer age;
static {
System.out.println("加载进jvm中!");
}
public Student() {
super();
System.out.println("调用无参构造方法创建了一个学生对象");
}
public Student(String sid) {
super();
this.sid = sid;
System.out.println("调用带一个参数的构造方法创建了一个学生对象");
}
public Student(String sid, String sname) {
super();
this.sid = sid;
this.sname = sname;
System.out.println("调用带二个参数的构造方法创建了一个学生对象");
}
@SuppressWarnings("unused")
private Student(Integer age) {
System.out.println("调用Student类私有的构造方法创建一个学生对象");
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public void hello() {
System.out.println("你好!我是" + this.sname);
}
public void hello(String name) {
System.out.println(name + "你好!我是" + this.sname);
}
@SuppressWarnings("unused")
private Integer add(Integer a, Integer b) {
return new Integer(a.intValue() + b.intValue());
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
如何拿到Class对象?
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.那么怎么获取呢?有如下三种方法:
1.Class.forName(完整的类名)
2.类名.class
3.对象.getClass()
代码如下:
//1、Class.forName() 获取Class
Class<Student> clazz =(Class<Student>)Class.forName("com.zking.reflect.Student");
//2、类.class
Class clazz02=Student.class;
//3、对象.getClass
Student stu = new Student();
Class clazz03 = stu.getClass();
System.out.println(clazz);
System.out.println(clazz02);
System.out.println(clazz03);
输出的结果为:
获得类的构造:
主要的方法:
1.getConstructor (获得构造器对象)
2.getDeclaredConstructor(获得私有化的构造器对象)
3.newInstance (反射实例化)
/**
* 通过反射进行实例化对象
*/
// 获得无参构造
Constructor<Student> c1 = clazz01.getConstructor();
Student stu02 = c1.newInstance();
stu02.setSid("3");
System.out.println("------------无参构造------------");
System.out.println(stu02 + "2号学生");
// 有参构造
Constructor<Student> c2 = clazz01.getConstructor(String.class);
Student stu03 = c2.newInstance("01");
stu03.setSname("小明" + "3号学生");
System.out.println("------------有参构造------------");
System.out.println(stu03);
// 多个参数的有参构造
Constructor<Student> c3 = clazz01.getConstructor(String.class, String.class);
Student stu04 = c3.newInstance("02", "小美");
System.out.println("------------多参构造------------");
System.out.println(stu04 + "4号学生");
// 调用私有化构造方法
Constructor<Student> c4 = clazz01.getDeclaredConstructor(Integer.class);
c4.setAccessible(true);
Student stu05 = c4.newInstance(18);
stu05.setSname("牛逼");
System.out.println("------------私有化构造------------");
System.out.println(stu05 + "5号学生");
获得类的方法:
主要的方法:
1.getMethod (通过方法名称获取到方法对象,若有参数放名称后面)
2.getMethod (通过方法名称获取到私有化方法对象)
3.invoke (类实例, "参数");
注:为什么参数放后面,通过查看源代码可以看到后面是一个可变参数 要么只写一个,要么写name后面。
继续采用上面的Student类,可以看到有三个方法,有参、无参和私有化。那么接下来我们就对这三个方法进行反射动态方法调用
/**
* 获得方法
*/
// 调用类方法
Method m1 = clazz01.getMethod("hello");
System.out.println("------------普通方法------------");
m1.invoke(stu05);
// 调用带参数的方法
Method m2 = clazz01.getMethod("hello", String.class);
System.out.println("------------有参方法------------");
m2.invoke(stu05, "27");
// 调用私有化有参方法
Method m3 = clazz01.getDeclaredMethod("add", Integer.class, Integer.class);
m3.setAccessible(true);
System.out.println("------------私有化方法------------");
System.out.println(m3.invoke(stu05, 27, 43));
获得类的属性:
主要的方法:
1.getField (“属性名”) 获得公开的属性
2.getDeclaredField (“属性名”) 既可以获得公开的属性又可以获得私有属性
3.getDeclaredFields (“属性名”) 获得全部
/**
* 通过反射机制获取对象属性
*/
// 反射公共属性
Field f1 = clazz01.getField("age");
f1.set(stu05, 56);
System.out.println("------------公共属性方法------------");
System.out.println(stu05 + "属性1");
System.out.println(f1.get(stu05));
// 反射私有化属性
Field f2 = clazz01.getDeclaredField("sname");
f2.setAccessible(true);
f2.set(stu05, "aa");
System.out.println("------------私有属性方法------------");
System.out.println(stu05);
System.out.println(f2.get(stu05));