反射机制
动态获取类中信息,就是java反射。一般需要一个接口!
1. Java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;
2. 对于任意一个对象,都能够调用它的任意一个方法和属性;
3. 这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。
比如说现在有一个做好的应用程序(Tomcat),并向外提供了Interface Servlet这个接口,当Tomcat运行以后,通过web.xml配置文件找到相应的Servlet.class文件并加载(学习框架的时候,首先要知道这个框架是干嘛的,第二要知道这个框架的配置文件怎么用,其次就是框架中对象的常见用法!注意接口和配置文件(其中包含了变化的参数信息))
4. 描述字节码文件的类Class,对于类向上抽取共性就形成了这个类。Class提供了方法从字节码文件中获取.class文件中字段、方法、名称、构造函数、一般函数。反射就是依靠Class类来完成的!
5. 那么如何获取一个类的字节码文件对象呢?
要想对字节码文件进行解剖,必须要有字节码文件对象。下面展示了获取对象的几种方式:
1.Object类中的getClass()方法,要用这种方式,必须要明确具体的类并创建对象(麻烦!)
首先写一个Person的bean:
package bean;
public class Person {
private int age;
private String name;
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
System.out.println("PersonParam run...");
}
public Person() {
super();
System.out.println("Person run...");
}
public void show(){
System.out.println(name + "...show run..." + age);
}
private void method(){
System.out.println("method run");
}
public void paramMethod(String str,int num){
System.out.println("paramMethod run..." + str + ":" + num);
}
public static void staticMethod(){
System.out.println("staticMethod run...");
}
}
然后用以下代码进行测试:
package reflect;
import bean.Person;
public class ReflectDemo {
public static void main(String[] args) {
getClassObject_1();
}
public static void getClassObject_1(){
Person p = new Person();
Class clazz = p.getClass();
Person p1 = new Person();
Class clazz1 = p1.getClass();
System.out.println(clazz==clazz1);
}
}
然后可以看到输出结果:
2.方式二:任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。这个方法相对简单,但是还是要确定类名。用到类中的静态成员
还是不够扩展
private static void getClassObject_2() {
Class clazz = Person.class;
Class clazz1 = Person.class;
//类中的静态成员
System.out.println(clazz == clazz1);
}
3.方式三:(需要重点掌握)只要通过给定类的字符串名称就可以获取该类,更为扩展。可以用Class类中的方法完成。该方法就是forName(),这种方式只要有名称即可,更为方便 ,扩展性更强!反射以这种方法为主
public static void getClassObject_3() throws ClassNotFoundException {
String className = "bean.Person";
//包名一定要添加上!
//其实这个String可以写到配置文件中
Class clazz = Class.forName(className);
System.out.println(clazz);
}
下面是程序的输出结果:
获取Class中的构造函数
获取默认构造器
- 早期创建Person对象的方法是:
Person p = new Person();
,中间的过程是这样一new,就在所在ClassPath路径中找到Person的字节码文件;并创建这个字节码文件对象,再接着创建Person对象 - 现在使用反射的方法来创建这个对象:
String name = "bean.Person";
现在只有一个字符串名字,也想完成这个对象的创建动作(发给配置文件);Class clazz = Class.forName(name);
找寻该名称类文件,并加载进内存,并产生Class对象;Object obj = clazz.newInstance();
产生该类的对象(这种方法提高了扩展性),//调用Class中空参构造器
public static void createNewObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//早期创建Person对象
//这样一new,就在所在ClassPath路径中找到Person的字节码文件
//并创建这个字节码文件对象,再接着创建Person对象
Person p = new Person();
//现在只有一个字符串名字,也想完成这个对象的创建动作(发给配置文件)
String name = "bean.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象
Class clazz = Class.forName(name);
//产生该类的对象(这种方法提高了扩展性)
Object obj = clazz.newInstance(); //调用Class中空参构造器
}
获取有参构造器
一般被反射的类都带空参构造器
1. 获取指定名称类的对象,使用有参数的构造器 ,首先获取到指定的构造器,这个方法是getConstructor()
2. 早期的方法是Person p = new Person("张三",20);
3. 现在使用反射的方法:这个方法接收一个可变参数列表,但是都是Class类型的;方法返回一个构造器对象;通过这个对象的newInstance方法产生相应的对象。
private static void createNewObject_1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// Person p = new Person("张三",20);
//一般被反射的类都带空参构造器
/*
*获取指定名称类的对象,使用有参数的构造器
*首先获取到指定的构造器
*这个方法时getConstructor()
*/
String name = "bean.Person";
Class clazz = Class.forName(name);
//这个方法接收一个可变参数列表,但是都是Class类型的
Constructor constructor = clazz.getConstructor(String.class,int.class);//方法返回一个构造器对象
//通过这个对象的newInstance方法产生相应的对象
Object obj = constructor.newInstance("张三",20);
用反射的方法创建了对象:
获取字段
有两个方法可以字段:Field getField(String name)
方法获取公共的方法,包括父类中的;Field getDeclaredField(String name)
方法只获取本类中的方法,包括私有的方法;
在字段的访问时,总是存在由于权限控制符所引起的异常,这时候就要找到对应但是方法来解决,这时候就使AccessibleObject类(这个类有三个子类,Constructor、Filed、Method),使用类方法setAccessible()
来取消私有四段的访问检查!
- 获取字节码文件对象
- 调用字节码文件对象的
Field getField(String name)
方法,返回字段对象。这个字段可能设置了访问权限,所以先将权限检查取消!field.setAccessible(true)
方法 - 这个字段对象是类中的,并未与某个具体的类对象相关联!所以想要操作这个字段,就要与具体的对象关联后再操作!
- 关联后就可以使用相应的set、get方法对这个对象中的属性(字段)进行了操作!
/*
* 获取字节码文件的字段
*/
public static void getFieldDemo() throws Exception {
//获取字节码文件对象
Class clazz = Class.forName("bean.Person");
//获取字段
Field field = clazz.getDeclaredField("age");
//对私有字段的访问取消权限检查,暴力访问!
field.setAccessible(true);
//创建本类的一个对象
Object obj = clazz.newInstance();
//对这个字段设置一个值
field.set(obj, 20);
//将字段和对象关联起来并操作
Object o = field.get(obj);
//显示这个对象中“age”字段的值
System.out.println(o);
}
}
将设置后的显示:
获取方法
获取所有的公共方法:
/*
* 获取指定Class中的公共函数
*/
public static void getMethodDemo() throws Exception {
Class clazz = Class.forName("bean.Person");
Method[] ms = clazz.getMethods();
// System.out.println(Arrays.toString(ms));
for (Method method : ms) {
System.out.println(method);
}
}
}
将Person中的public方法都打印出来:其中包含了超类Object中的方法!
获取本类中的方法,包括私有:不包含父类Object中的方法
private static void getMethodDemo_1() throws Exception {
/*
* 获取本类中所有的方法,包括私有
*/
Class clazz = Class.forName("bean.Person");
Method[] method = clazz.getDeclaredMethods();
for (Method method2 : method) {
System.out.println(method2);
}
}
调用方法:
直接操作类中的字段来初始化对象(作为内容巩固!)
//方法1:通过设置字段来初始化对象
public static void getMethodDemo_2() throws Exception {
Class clazz = Class.forName("bean.Person");
//获取空参数的一般方法
Method method = clazz.getMethod("show", null);
//获取两个字段
Field field1 = clazz.getDeclaredField("name");
Field field2 = clazz.getDeclaredField("age");
field1.setAccessible(true);
field2.setAccessible(true);
//创建一个对象与两个字段关联
Object obj = clazz.newInstance();
//设置字段的值
field1.set(obj, "wangyue");
field2.set(obj, 5);
//调用无参的show()方法!
method.invoke(obj, null);
}
使用构造器来创建对象(方法回顾):
public static void getMethodDemo_3() throws Exception {
Class clazz = Class.forName("bean.Person");
//获取指定构造器
Constructor constructor = clazz.getConstructor(String.class,int.class);
//创建一个实例
Object obj = constructor.newInstance("wangyue",5);
//获取相应的方法
Method method = clazz.getMethod("show", null);
//将方法和实例相关联,并调用
method.invoke(obj, null);
}
调用有参方法:
private static void getMethodDemo_4() throws Exception {
Class clazz = Class.forName("bean.Person");
//获取指定方法
Method method = clazz.getMethod("paramMethod", String.class,int.class);
//创建实例
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("张三",28);
//关联实例并调用相关方法
method.invoke(obj, "李四",5);
}
本人是菜鸟一枚,当做学习笔记写博客。谢谢各路大咖驻足审阅