在Java中每个类被加载后,系统会为该类生成一个Class对象,且是唯一的。通过Class对象就可以访问到JVM中的这个类。我们就可以拿到万恶之源——Class对象,去获得这个类的所有信息。
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖。
one
新建一个类,去拿到这个类在JVM中的Class对象。同时验证一下此万恶之源是唯一的。
提供一个类,我们去反射它。
package cn.liu.review;
public class Student {
private int id;
private String studentName;
private int age;
public Student() {}
public Student(int id, String studentName, int age) {
super();
this.id = id;
this.studentName = studentName;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
三种获取类信息的方式。
1.类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象
2.Class.forName("类名字符串") (注:类名字符串是包名+类名) 说明:装入类,并做类的静态初始化,返回Class的对象
3.实例对象.getClass() 说明:对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象
package cn.liu.review;
/**
* 测试反射
* @author Administrator
*
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
//拿到此类的Class对象,此Class对象在堆内存中存着此类的信息
//1.
Class clz = Class.forName("cn.liu.review.Student");
System.out.println(clz.hashCode());
//2.
Student s = new Student();
Class aa = s.getClass();
System.out.println(aa.hashCode());
//3.
Class bb = Student.class;
System.out.println(bb.hashCode());
}
}
two
通过反射获得类的信息(属性,构造器,方法等等)
package cn.liu.review;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 通过反射获得类的信息(属性,构造器,方法等等)
* @author Administrator
*
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
Class clz = Class.forName("cn.liu.review.Student");
//1.获得类的路径
System.out.println(clz.getName());//获得包名+类名
System.out.println(clz.getSimpleName());//获得类名
//2.获取属性信息
Field[] dfs = clz.getDeclaredFields();//返回所有属性
for(Field temp :dfs) {
System.out.println("属性:"+temp);
}
System.out.println("----------------------------");
Field[] fs = clz.getFields();//返回只能获得public的属性
for(Field temp:fs) {
System.out.println(temp);
}
System.out.println("----------------------------");
//3.获得方法信息
// Class对象所表示的类(包括那些由该类声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
Method[] ms= clz.getMethods();
for(Method temp:ms) {
System.out.println(temp);
}
System.out.println("----------------------------");
//如果方法有参数,必须传递类型
Method dm = clz.getDeclaredMethod("setStudentName", String.class);
System.out.println(dm);
//4.获得构造方法信息
Constructor[] dcs = clz.getDeclaredConstructors();
for(Constructor temp:dcs) {}
System.out.println(dcs);
System.out.println("----------------------------");
Constructor cs = clz.getConstructor(null);//获得特定参数的构造器
System.out.println(cs);
}
}
three
package cn.liu.review;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 利用反射动态调用构造器,对象,属性等等
* @author Administrator
*
*/
public class Demo03 {
public static void main(String[] args) throws Exception {
//拿到万恶之源Class对象
Class<Student> clz = (Class<Student>)Class.forName("cn.liu.review.Student");
//利用反射动态调用构造器
//调用构造参数,构造对象
Student s1 = clz.newInstance();//本质是调用了无参构造器
System.out.println("s1:"+s1.getStudentName());
//1.获得想要的构造器
Constructor dc = clz.getDeclaredConstructor(int.class,int.class,String.class);
//2.构造对象
Student s2 = (Student) dc.newInstance(2,2,"three");
System.out.println("s2:"+s2.getStudentName());
//通过反射调用普通方法
//1.创建对象
Student s3 = (Student) dc.newInstance(55,12,"小明");
//2.获得想要的方法
Method me = clz.getDeclaredMethod("setStudentName", String.class);
//3.传参,调用
me.invoke(s3, "小红");
System.out.println("s3:"+s3.getStudentName());
//通过反射操作属性
//1.获得指定的属性
Field f = clz.getDeclaredField("studentName");
f.setAccessible(true);//属性不需要做安全检查了可以访问private
//2.传参
f.set(s3, "小王");
System.out.println("s3:"+f.get(s3));//也是通过反射
}
}
four
反射操作注解,反射操作泛型等等。