一、反射机制
Java反射机制是指在程序的运行过程中,对于任意一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能够知道调用它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为JAVA语言的反射机制
二、反射的核心内容
反射的核心内容是 JVM 在运行时动态加载类或调用方法/访问属性,不需要事先知道运行对象是谁
举例说明:
一般情况下,我们在使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作
//实例化对象
Apple apple = new Apple();
//调用方法
apple.setPrice(4);
而反射则是一开始并不知道我们要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象,这时候,需要我们使用 JDK 提供的反射 API 进行反射调用:
//获取类的 Class 对象实例
Class clz = Class.forName("com.demo.reflect.Apple");
//获取方法的 Method 对象
Method method = clz.getMethod("setPrice", int.class);
//根据 Class 对象实例获取 Constructor 对象
Constructor constructor = clz.getConstructor();
//使用 Constructor 对象的 newInstance 方法获取反射类对象
Object object = constructor.newInstance();
//利用 invoke 方法调用方法
method.invoke(object, 4);
三、反射的底层原理
众所周知,Java的Object 类,是所有Java 类的父类,其内声明了hashCode()、equals()、clone()、toString()、getClass()等方法,其中就包括getClass()方法。
当一个class被加载,或当类加载器(class loader)的defineClass()方法被JVM调用时,JVM 便自动产生一个Class 对象。
四、反射的主要功能
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所有的成员变量和方法
-
在运行时调用任意一个对象的方法
注:运行时,而不是编译时
五、反射的主要用途
-
反编译 .class---->.java;
-
通过反射机制访问Java对象的属性、方法、构造方法等;
-
当我们在使用IDEA或者Eclipse等开发工具的时候,当我们实例化对象后,并想调用它的属性和方法时,一按点号,编译器就会自动列出它的属性和方法,这里就是用到了反射机制;
-
反射最重要的用途就是开发各种通用框架,很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
六、反射常用API
-
Java.lang.Class
-
Java.lang.reflect.Constructor
-
Java.lang.reflect.Field
-
Java.lang.reflect.Method
-
Java.lang.reflect.Modifier
七、反射的基本运用
1.获取Class对象
-
调用运行时类的属性:.class
前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠, 程序性能最高
示例: Class clazz1 = String.class;
-
通过运行时类的对象,调用getClass()
前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
示例:
Student student = new Student();
Class<? extends Student> c1 = student.getClass();
-
调用Class的静态方法:forName(String classPath)
前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName() 获取,可能抛出ClassNotFoundException
示例: Class clazz = Class.forName(“java.lang.String”);
-
使用类的加载器:ClassLoader
示例:
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass("reflect.Teacher");
2.判断是否为某个类的实例
一般可以通过使用instanceof
关键字来判断是否为某个类的实例,当然也可以通过反射Class对象中的isInstance()来判断是否为某个类的实例
public static void main(String[] args) {
// 通过反射Class.isInstance判断
String reflect = "reflect";
Class<String> stringClass = String.class;
boolean instance = stringClass.isInstance(reflect);
System.out.println(instance); // true
// 通过instanceof关键字判断
boolean result = reflect instanceof String;
System.out.println(result); // true
}
3.创建实例
- 使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;
Object str = c.newInstance();
- 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("reflect");
System.out.println(obj);
4.获取属性
方法 | 作用 |
---|---|
public Field[] getFields() | 返回此Class 对象所表示的类或接口的public 的Field |
public Field[] getDeclaredFields() | 返回此Class 对象所表示的类或接口的全部Field |
public int getModifiers() | 以整数形式返回此Field 的修饰符 |
public Class<?> getType() | 得到Field 的属性类型 |
public String getName() | 返回Field 的名称 |
@Test
public void demo(){
Class clazz = ReflectDemo.class;
//获取属性结构
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
System.out.println();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
}
//权限修饰符 数据类型 变量名
@Test
public void demo2(){
Class clazz = ReflectDemo.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t");
//2.数据类型
Class type = f.getType();
System.out.print(type.getName() + "\t");
//3.变量名
String fName = f.getName();
System.out.print(fName);
System.out.println();
}
}
}
5.获取方法
方法 | 作用 |
---|---|
public Method[] getMethods() | 返回此Class 对象所表示的类或接口的public 的方法 |
public Method[] getDeclaredMethods() | 返回此Class 对象所表示的类或接口的全部方法 |
public Class<?> getReturnType() | 取得全部的返回值 |
public Class<?>[] getParameterTypes() | 取得全部的参数 |
public int getModifiers() | 取得修饰符 |
public Class<?>[] getExceptionTypes() | 取得异常信息 |
@Test
public void demo(){
Class clazz = ReflectDemo.class;
//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}
System.out.println();
//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
System.out.println(m);
}
}
/*
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws XxxException{}
*/
@Test
public void demo2(){
Class clazz = ReflectDemo.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
//1.获取方法声明的注解
Annotation[] annos = m.getAnnotations();
for(Annotation a : annos){
System.out.println(a);
}
//2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
//3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
//4.方法名
System.out.print(m.getName());
System.out.print("(");
//5.形参列表
Class[] parameterTypes = m.getParameterTypes();
if(!(parameterTypes == null && parameterTypes.length == 0)){
for(int i = 0;i < parameterTypes.length;i++){
if(i == parameterTypes.length - 1){
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
//6.抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
if(exceptionTypes.length > 0){
System.out.print("throws ");
for(int i = 0;i < exceptionTypes.length;i++){
if(i == exceptionTypes.length - 1){
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ",");
}
}
System.out.println();
}
}
}
6.获取构造器
方法 | 作用 |
---|---|
public Constructor<T>[] getConstructors() | 返回此 Class 对象所表示的类的所有public 构造方法。 |
public Constructor<T>[] getDeclaredConstructors() | 返回此 Class 对象表示的类声明的所有构造方法。 |
public int getModifiers() | 取得修饰符 |
public String getName() | 取得方法名称 |
public Class<?>[] getParameterTypes() | 取得参数的类型 |
/*
获取构造器结构
*/
@Test
public void demo(){
Class clazz = ReflectDemo.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors){
System.out.println(c);
}
System.out.println();
//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
System.out.println(c);
}
}
/*
获取运行时类的父类
*/
@Test
public void demo2(){
Class clazz = ReflectDemo.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
}
/*
获取运行时类的带泛型的父类
*/
@Test
public void demo3(){
Class clazz = ReflectDemo.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
/*
获取运行时类的带泛型的父类的泛型
代码:逻辑性代码 vs 功能性代码
*/
@Test
public void demo4(){
Class clazz = ReflectDemo.class;
Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
//获取泛型类型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
//System.out.println(actualTypeArguments[0].getTypeName());
System.out.println(((Class)actualTypeArguments[0]).getName());
}
/*
获取运行时类实现的接口
*/
@Test
public void demo5(){
Class clazz = ReflectDemo.class;
Class[] interfaces = clazz.getInterfaces();
for(Class c : interfaces){
System.out.println(c);
}
System.out.println();
//获取运行时类的父类实现的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for(Class c : interfaces1){
System.out.println(c);
}
}
/*
获取运行时类所在的包
*/
@Test
public void demo6(){
Class clazz = ReflectDemo.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
/*
获取运行时类声明的注解
*/
@Test
public void demo7(){
Class clazz = ReflectDemo.class;
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annos : annotations){
System.out.println(annos);
}
}
}
标签:反射,Java,System,基础知识,public,println,clazz,Class,out
From: https://blog.csdn.net/HollyShit_/article/details/140838541