今天来学习一下Java的反射机制,如有不当请多指教!
概述
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
Java中的反射主要和Class
类有关。Class类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是说不需要我们自己去处理创建,JVM已经帮我们创建好了。
反射的使用
获取Class对象
1、getClass()
getClass()是Object类中的方法,也就是说每个类都有自己的Class对象。
Student s1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass1 = s1.getClass();
2、.class
任何数据类型(包括基本数据类型)都有一个“静态”的class属性,比如String.Class
Class stuClass2 = Student.class;
3、Class.forName(String className) —— 推荐
通过Class类的静态方法forName获取Class对象(常用)
Class stuClass3 = Class.forName("czy.Student");//注意此字符串必须是真实路径→包名.类名
注意:在运行期间,一个类,只有一个Class对象产生。
获取构造方法
public class Constructors {
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class c = Class.forName("czy.Student");
//2.获取所有公有构造方法
Constructor[] conArray = c.getConstructors();
//3、获取所有的构造方法(包括:私有、受保护、默认、公有)
Constructor[] conArray = c.getDeclaredConstructors();
//4、获取公有、无参的构造方法
Constructor con = c.getConstructor();
//因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//调用构造方法
Object obj = con.newInstance();
//5、获取私有构造方法,并调用
con = c.getDeclaredConstructor(char.class);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance('男');
}
}
获取成员变量
public class Fields {
public static void main(String[] args) throws Exception {
//1、获取Class对象
Class stuClass = Class.forName("czy.Student");
//2、获取所有公有的字段
Field[] fieldArray = stuClass.getFields();
//3、获取所有的字段(包括私有、受保护、默认的)
Field[] fieldArray = stuClass.getDeclaredFields();
//4、获取公有字段"name"并调用
Field f = stuClass.getField("name");
//获取一个对象
Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student student = new Student();
//为字段设置值
f.set(obj, "刘德华");//为Student对象中的name属性赋值--》student.name = "刘德华"
//5、获取私有字段"phone"并调用
f = stuClass.getDeclaredField("phone");
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "13415038974");
}
}
获取成员方法
public class MethodClass {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("czy.Student");
//2.获取所有公有方法
Method[] methodArray = stuClass.getMethods();
//3.获取所有的方法,包括私有的
Method[] methodArray = stuClass.getDeclaredMethods();
//4.获取公有的show1()方法
Method m = stuClass.getMethod("show1", String.class);
//调用show1()方法
Object obj = stuClass.getConstructor().newInstance();
m.invoke(obj, "刘德华");
//5.获取私有的show4()方法
m = stuClass.getDeclaredMethod("show4", int.class);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(由反射获取),一个是实参
}
}
反射的其它用法
通过反射越过泛型检查
例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class intClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = intClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100);
}
}
当然这样只能躲过编译器检查,去遍历的话还是会抛出异常的。