1.什么是反射机制
反射机制是在运行状态下,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java的反射机制。
2.反射机制的作用
反射机制主要提供了以下功能:
(1)在运行时判断任意一个对象所属的类;
(2)在运行时构造任意一个类的对象;
(3)在运行时判断任意一个类所具有的成员变量和方法;
(4)在运行时调用任意一个对象的方法;
(5)生成动态代理。
3.反射机制的优缺点
首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
静态编译: 在编译的时确定类型,绑定对象,即通过。
动态编译: 运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的耦合性。
反射机制优点: 可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于Java这种线编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
反射机制缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。
4.反射机制中的类
(1)java.lang.Class;
介绍: Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息记录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
基本的Java类型(boolean、byte、char、short、int、long、float和double)和关键字void也都对应一个Class对象。
每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。
一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
(2)java.lang.reflect.Constructor(提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法);
(3)java.lang.reflect.Field(提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类);
(4)java.lang.reflect.Method(提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。这个类不难理解,它是用来封装反射类方法的一个类);
(5)java.lang.reflect.Modifier。
5.如何获取反射机制中的类
1)获取类的Class对象
Class类的实例表示正在运行的Java应用程序中的类和接口。获取类的Class对象有多种方式:
调用getClass | Boolean var1 =true; Class<?> classType2 = var1.getClass(); System.out.println(classType2); 输出:class java.lang.Boolean |
运用.class语法 | Class<?> classType4 = Boolean.class; System,out.println(classType4); 输出:class java.lang.Boolean |
运用static method Class.forName() | Class<?> classType5 = Class.forName(“java.lang.Boolean”); System,out.println(classType5); 输出:class java.lang.Boolean |
运用primitive wrapper classes的TYPE语法(这里返回的是原生类型,和Boolean.class返回的不同) | Class<?> classType3 = Boolean.TYPE; System,out.println(classType3); 输出:boolean |
2)获取类的Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值 。Java的Class<T>类提供了几个方法获取该类的属性:
public FieldGetField(String name) | 返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段 |
public Field[] getFields() | 返回一个包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段 |
public Field getDeclaredField(String name) | 返回一个Field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段 |
public Field[] getDeclaredFields() | 返回Field对象的一个数组,这些对象反映此Class对象所表示的类或借口所声明的所有字段 |
getFields和getDeclaredFields区别:
(1)getFields返回的是声明为public的属性,包括父类中定义;
(2)getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
3)获取类的Method
通过反射机制得到某各类的某个方法,然后调用对应于这个类的某个实例的该方法,Class<T>类提供了几个方法来获取类的方法:
public Method getMethod(String name, Class<T>… parameterTypes) | 返回一个Method对象,它反映此Class对象所表示的类或接口的指定公共成员方法 |
public Method[] getMethods() | 返回一个包含某些Method对象的数组,这些对象反映此Class对象所表示的类或接口(包括哪些又该类或接口声明的以及从超类和超接口集成的那些的类或方法)的公共member方法 |
public Method getDeclaredMethod(String name, Class<T>… parameterTypes) | 返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法 |
public Method[] getDeclaredMethods() | 返回Method对象的一个数组,这些对象反映此Class对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 |
4)获取类的Constructor
通过反射机制得到某各类的构造器,然后调用该构造器创建该类的一个实例,Class<T>类提供了几个方法获取类的构造器:
public Constructor<T> getConstructor(Class<T> …parameterTypes) | 返回一个Constructor对象,它反映此Class对象所表示的类的指定公共构造方法 |
public Constructor<T>[] getConstructors() | 返回一个包含某些Constructor对象的数组,这些对象反映此Class对象所表示的类的所有公共构造方法 |
public Constructor<T> getDeclaredConstructor(Class<T>… parameterTypes) | 返回一个Constructor对象,该对象反映此Class对象所表示的类或接口的指定构造方法 |
public Constructor<T>[] getDeclaredConstructors() | 返回Constructor对象的一个数组,这些对象反映此Class对象表示的类声明的所有构造方法,它们是公共、保护、默认(包)访问和私有构造方法 |
5)新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建:
调用无自变量constructor | 1、调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败. Class<?> classType = ExtendType.class; Object inst = classType.newInstance(); System.out.println(inst); 2、调用默认Constructor对象的newInstance方法 Class<?> classType = ExtendType.class; Constructor<?> constructor1 = classType.getConstructor(); Object inst = constructor1.newInstance(); System.out.println(inst); |
调用带参数constructor | 3、调用带参数Constructor对象的newInstance方法 Constructor<?> constructor2 = classType.getDeclaredConstructor(int.class, String.class); Object inst = constructor2.newInstance(1, “123”); System.out.println(inst); |
6)调用类的函数
通过反射获取类Method对象,调用Method的Invoke方法调用函数。
7)设置/获取类的属性值
通过反射获取类的Field对象,调用Field方法设置或获取值。
实例展示
package reflect;
public class Person {
private int age;
private String name;
public Person(){}
public Person(int age, String name){
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package reflect;
public interface ActionInterface {
public void walk(int m);
}
package reflect;
public class SuperMan extends Person implements ActionInterface{
private boolean blueBriefs;
public void fly(){
System.out.println("超人会飞");
}
public boolean isBlueBriefs(){
return blueBriefs;
}
public void setBlueBriefs(boolean blueBriefs){
this.blueBriefs = blueBriefs;
}
@Override
public void walk(int m){
System.out.println("超人会走,走了"+m+"米就走不动了");
}
}
package reflect;
import java.lang.reflect.*;
public class ReflectDemo {
/**
* 为了看清楚Java反射部分代码,所有异常最后都跑出来给虚拟机处理
*/
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException, NoSuchMethodException {
System.out.println("demo1:通过Java反射机制得到类的包名和类名");
demo1();
System.out.println("");
System.out.println("demo2:验证所有的类都是Class类的实例对象");
demo2();
System.out.println("");
System.out.println("demo3:通过Java反射机制,用 Class 创建类对象,这也就是反射存在的意义所在");
demo3();
System.out.println("");
System.out.println("demo4:通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象");
demo4();
System.out.println("");
System.out.println("demo5:通过Java反射机制操作成员变量, set 和 get");
demo5();
System.out.println("");
System.out.println("demo6:通过Java反射机制得到类的一些属性:继承的接口、父类、函数信息、成员信息、类型等");
demo6();
System.out.println("");
System.out.println("demo7:通过Java反射机制调用类方法");
demo7();
System.out.println("");
System.out.println("demo8:通过Java反射机制得到类加载器信息");
demo8();
}
/**
* demo1: 通过Java反射机制得到类的包名和类名
*/
public static void demo1(){
Person person = new Person();
System.out.println("包名:"+person.getClass().getPackage().getName());
System.out.println("完整类名:"+person.getClass().getName());
}
/**
* demo2: 验证所有的类都是Class类的实例对象
*/
public static void demo2() throws ClassNotFoundException{
//定义两个类型都未知的Class, 设置初值为null, 看看如何给它们赋值成Person类
Class<?> class1 = null;
Class<?> class2 = null;
//写法1,可能抛出ClassNotFoundException异常,多用这个写法
class1 = Class.forName("reflect.Person");
System.out.println("写法1,包名: " + class1.getPackage().getName() + ", 完整类名:" + class1.getName());
//写法2
class2 = Person.class;
System.out.println("写法2,包名: " + class2.getPackage().getName() + ", 完整类名:" + class2.getName());
}
/**
* demo3: 通过Java反射机制,用Class创建类对象,这也就是反射存在的意义所在
*/
public static void demo3() throws ClassNotFoundException, InstantiationException,IllegalAccessException {
Class<?> class1 = null;
class1 = Class.forName("reflect.Person");
//由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数
Person person = (Person) class1.newInstance();
person.setName("小明");
person.setAge(20);
System.out.println(person.getName() + " , " + person.getAge());
}
/**
* demo4: 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象
*/
public static void demo4() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException{
Class<?> class1 = null;
Person person1 = null;
Person person2 = null;
class1 = Class.forName("reflect.Person");
Constructor<?>[] constructors = class1.getConstructors();
person1 = (Person) constructors[0].newInstance();
person1.setName("小刚");
person1.setAge(20);
System.out.println(person1.getName() + " , " + person1.getAge());
person2 = (Person) constructors[1].newInstance(21, "xiaofei");
System.out.println(person2.getName() + " , " + person2.getAge());
}
/**
* demo5: 通过Java反射机制操作成员变量,set和get
*/
public static void demo5() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
Class<?> class1 = Class.forName("reflect.Person");
Object obj = class1.newInstance();
Field personNameField = class1.getDeclaredField("name");
personNameField.setAccessible(true); //取消访问检查
personNameField.set(obj, "小虎");
System.out.println("修改之后得到的属性变量的值:" + personNameField.get(obj));
}
/**
* demo6: 用过Java反射机制得到类的一些属性:继承的接口、父类、函数信息、成员信息、类型等
*/
public static void demo6() throws ClassNotFoundException {
Class<?> class1 = Class.forName("reflect.SuperMan");
//取得父类名称
Class<?> superclass = class1.getSuperclass();
System.out.println("SuperMan类的父类名:" + superclass.getName());
Field[] fields = class1.getDeclaredFields();
for(int i = 0; i < fields.length; i++){
System.out.println("类中的成员" +i+ ": " + fields[i]);
}
//取得类方法
Method[] methods = class1.getDeclaredMethods();
for(int i = 0; i < methods.length; i++){
System.out.println("取得SuperMan类的方法" + i + ":");
System.out.println("函数名:" + methods[i].getName());
System.out.println("函数返回类型:"+ methods[i].getReturnType());
System.out.println("函数访问修饰符:"+ Modifier.toString(methods[i].getModifiers()));
System.out.println("函数代码写法:"+ methods[i]);
}
//取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法
Class<?> interfaces[] = class1.getInterfaces();
for(int i = 0; i < interfaces.length; i++){
System.out.println("实现的接口类名: " + interfaces[i].getName());
}
}
/**
* demo7: 通过Java反射机制调用类方法
*/
public static void demo7() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> class1 = Class.forName("reflect.SuperMan");
System.out.println("调用无参方法fly():");
Method method = class1.getMethod("fly");
method.invoke(class1.newInstance());
System.out.println("调用有参方法walk(int m):");
method = class1.getMethod("walk", int.class);
method.invoke(class1.newInstance(), 100);
}
/**
* demo8: 通过Java反射机制得到类加载器信息
* 在java中由3种类加载器
* 1) Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见
* 2) Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext
* 3) AppClassLoader 加载classpath指定的类,是最常用的加载器,同时也是java中默认的加载器。
*/
public static void demo8() throws ClassNotFoundException {
Class<?> class1 = Class.forName("reflect.SuperMan");
String name = class1.getClassLoader().getClass().getName();
System.out.println("类加载器类名:" + name);
}
}