反射的概念
- 程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的,反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁
反射的作用
- Java反射框架主要提供以下功能:
- 在运行时判断对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类的成员变量的方法(甚至私有方法)
- 在运行时调用任意一个对象的方法
反射的主要用途
- 反射最重要的用途是开发各种应用框架:
- Spring系列
- Hibernate,MyBatis等ORM框架
- ...
详解反射机制
类的组成
一个类组成通常包括以下几个部分:类名、构造器、方法、成员变量、注解等,所以为了能够实例化任意一个类的对象,需要能够获得类的全部组成。JDK中的Reflection包提供了以下对应类供我们获取类的各个对应组成部分:Class Constructor Method Field等
- Class
- Class类是一个特殊的类,因为在每个对象加载到JVM后,都会产生一个Class的对象,用来跟踪Java对象代表的类,Class对象在JVm中只存在唯一一份
- 在Java中,万事万物皆对象,类也是对象,任何一个类都是java.lang.Class类的实例对象
示例代码一:
package com.whut.java;
class Foo{
public void print(){
System.out.println("foo...");
}
}
public class ClassDemo {
public static void main(String[] args){
// 任何一个类都是Class类的实例对象,获取Class实例对象有三种方式
// 1. 类名.class
Class clazz = Foo.class;
System.out.println(clazz.getName());
// 2. 对象.getClass()
Foo foo = new Foo();
Class clazz2 = foo.getClass();
System.out.println(clazz2.getName());
// 3. Class.forName(完整类名)
Class clazz3 = null;
try {
clazz3 = Class.forName("com.whut.java.Foo");
System.out.println(clazz3.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// Class对象在JVM中只存在唯一一份
System.out.println(clazz == clazz2);
System.out.println(clazz2 == clazz3);
}
}
复制代码
示例代码二:
package com.whut.java;
public class ClassDemo2 {
public static void main(String[] args){
Class clazz = int.class;
System.out.println(clazz.getName());
Class clazz2 = Integer.class;
System.out.println(clazz2.getName());
// 基本数据类型和对应包装类的Class对象不相同
System.out.println(clazz == clazz2);
Class clazz3 = void.class;
System.out.println(clazz3.getName());
/**
output:
int
java.lang.Integer
false
void
*/
}
}
复制代码
类的加载
- Java中类的加载有两种方式:静态加载类和动态加载类
- 静态加载类:使用new关键词,编译时加载需要的类,如果类不存在则无法通过编译
- 动态加载类:编译时不会检查需要的类是否存在,在运行时才会检查
- Method
Method类:一个方法就是一个Method实例对象
代码示例:
package com.whut.java;
import java.lang.reflect.Method;
public class ClassMethod {
public static void main(String[] args){
String str = "hello";
printClassMethodMessage(str);
}
public static void printClassMethodMessage(Object object){
// 获取类名
Class clazz = object.getClass();
System.out.println("class name: " + clazz.getName());
/**
* Method类,
*一个成员方法就是一个Method对象
* getMethods():获取类的所有public方法,包括从父类继承下来的方法
* getDeclaredMethods():获取类自己声明的所有方法,不理会访问权限
*/
Method[] methods = clazz.getMethods();
for(Method method : methods){
// 获取方法的返回值类型
Class returnType = method.getReturnType();
System.out.println("method return type:" + returnType.getName());
// 获取方法的名称
System.out.println("method name: " + method.getName());
// 获取方法的所有参数
Class[] paramTypes = method.getParameterTypes();
for (Class param : paramTypes ){
System.out.println("method param type: " +param.getName());
}
}
}
}
复制代码
- Field
一个成员变量就是一个Field对象
示例代码:
package com.whut.java;
import java.lang.reflect.Field;
public class ClassMember {
public static void main(String[] args){
String str = "hello";
printClassMemberMessage(str);
}
public static void printClassMemberMessage(Object object){
// 获取类名
Class clazz = object.getClass();
System.out.println("class name: " + clazz.getName());
/**
* Field类,
* 一个成员变量就是一个Field对象
* getFields():获取类的所有public的成员变量
* getDeclaredFields():获取类的所有自己声明的成员变量,不问权限
*/
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
// 获取成员变量类型
Class fieldType = field.getType();
System.out.println("field type: " + fieldType.getName());
// 获取成员变量名称
String fieldName = field.getName();
System.out.println("field name: " + fieldName);
}
}
}
复制代码
- Constructor
一个构造函数就是一个Constructor对象
示例代码:
package com.whut.java;
import java.lang.reflect.Constructor;
public class ClassConstructor {
public static void main(String[] args){
String str = "hello";
printClassConstructorMessage(str);
}
public static void printClassConstructorMessage(Object o){
// 获取类名
Class clazz = o.getClass();
System.out.println("class name: " + clazz.getName());
/**
* Constructor类,
* 构造函数也是对象,一个构造函数就是一个Constructor对象
* getDeclaredConstructors得到所有的构造函数
*/
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors){
// 获取构造函数的名称
System.out.println("constructor name: " + constructor.getName());
Class[] parameterTypes = constructor.getParameterTypes();
for (Class param : parameterTypes){
// 获取构造函数的参数列表类型
System.out.println("param type: " + param.getName());
}
}
}
}
复制代码
- 方法反射
package com.whut.java;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodReflect {
public static void main(String[] args){
A a = new A();
// 1. 要获取一个类的方法就是要获取类的信息,获取类的信息首先要获取类的类类型
Class clazz = a.getClass();
System.out.println("class name: " + clazz.getName());
try {
/**
* 2. 获取方法
* 方法有方法名称和参数列表决定
* getMethod():获取的是public的方法
* getDelcaredMethod(): 获取的是类自己声明的方法
*
* 方法的反射操作:
* 方法对象(反)来调用方法(射) 和 实例对象.方法 效果完全一致
* 方法如果有返回值,返回具体的返回值,否则返回null
*/
Method method = clazz.getMethod("print", int.class, int.class);
method.invoke(a, 10, 20);
Method method1 = clazz.getMethod("print", new Class[]{String.class, String.class});
method1.invoke(a, new String[]{"hello", "world"});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class A{
public void print(int a, int b){
System.out.println(a + b);
}
public void print(String a, String b){
System.out.println(a + b);
}
}
复制代码