理解Java反射机制
转载请注明出处,谢谢!
一、Java反射简介
什么是反射?
Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对学习框架技术有很大的帮助。
首先,我们先区分下编译和运行:编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。
Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。
Java反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
Java反射有什么作用?
假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。
得到反射的三种方法?
类.class;
对象.getClass();
Class.forName("类的全称"),不仅表示了,类的类类型,还代表了动态加载类
一个类里都有什么?
类名、类修饰符、包信息、父类、实现的接口、属性、方法、构造器(构造方法)、注解多部分组成。
属性有几部分组成?
修饰符、类型、属性名、属性值四部分组成。
方法有几部分组成?
修饰符、返回类型、方法名、参数列表、方法体、返回值
构造器几部分组成?
修饰符、构造器名称(类名)、参数列表、方法体
二、Class类简介
java.lang.Class类介绍
要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。
Class
类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和 double
)和关键字void
也表示为Class
对象。
Class
没有公共构造方法。Class
对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass
方法自动构造的。
在面向对象的世界里,万事万物皆对象。(java语言中,静态的成员、普通数据类型除外)
那么类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢?
类是对象,类是java.lang.Class类的实例对象
java.lang.Class类的API介绍
方法摘要 | ||
---|---|---|
|
asSubclass(Class<U> clazz) 强制转换该 Class 对象,以表示指定的 class 对象所表示的类的一个子类。 |
|
T |
cast(Object obj) 将一个对象强制转换成此 Class 对象所表示的类或接口。 |
|
boolean |
desiredAssertionStatus() 如果要在调用此方法时将要初始化该类,则返回将分配给该类的断言状态。 |
|
static Class<?> |
forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。 |
|
static Class<?> |
forName(String name, 使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。 |
|
|
getAnnotation(Class<A> annotationClass) 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 |
|
Annotation[] |
getAnnotations() 返回此元素上存在的所有注释。 |
|
String |
getCanonicalName() 返回 Java Language Specification 中所定义的底层类的规范化名称。 |
|
Class<?>[] |
getClasses() 返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。 |
|
ClassLoader |
getClassLoader() 返回该类的类加载器。 |
|
Class<?> |
getComponentType() 返回表示数组组件类型的 Class 。 |
|
Constructor<T> |
getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 |
|
Constructor<?>[] |
getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 |
|
Annotation[] |
getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。 |
|
Class<?>[] |
getDeclaredClasses() 返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口。 |
|
Constructor<T> |
getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 |
|
Constructor<?>[] |
getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 |
|
Field |
getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 |
|
Field[] |
getDeclaredFields() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 |
|
Method |
getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 |
|
Method[] |
getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
|
Class<?> |
getDeclaringClass() 如果此 Class 对象所表示的类或接口是另一个类的成员,则返回的 Class 对象表示该对象的声明类。 |
|
Class<?> |
getEnclosingClass() 返回底层类的立即封闭类。 |
|
Constructor<?> |
getEnclosingConstructor() 如果该 Class 对象表示构造方法中的一个本地或匿名类,则返回 Constructor 对象,它表示底层类的立即封闭构造方法。 |
|
Method |
getEnclosingMethod() 如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method 对象,它表示底层类的立即封闭方法。 |
|
T[] |
getEnumConstants() 如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null。 |
|
Field |
getField(String name) 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 |
|
Field[] |
getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 |
|
Type[] |
getGenericInterfaces() 返回表示某些接口的 Type,这些接口由此对象所表示的类或接口直接实现。 |
|
Type |
getGenericSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。 |
|
Class<?>[] |
getInterfaces() 确定此对象所表示的类或接口实现的接口。 |
|
Method |
getMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 |
|
Method[] |
getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 |
|
int |
getModifiers() 返回此类或接口以整数编码的 Java 语言修饰符。 |
|
String |
getName() 以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 |
|
Package |
getPackage() 获取此类的包。 |
|
ProtectionDomain |
getProtectionDomain() 返回该类的 ProtectionDomain 。 |
|
URL |
getResource(String name) 查找带有给定名称的资源。 |
|
InputStream |
getResourceAsStream(String name) 查找具有给定名称的资源。 |
|
Object[] |
getSigners() 获取此类的标记。 |
|
String |
getSimpleName() 返回源代码中给出的底层类的简称。 |
|
Class<? super T> |
getSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的Class 。 |
|
TypeVariable<Class<T>>[] |
getTypeParameters() 按声明顺序返回 TypeVariable 对象的一个数组,这些对象表示用此 GenericDeclaration 对象所表示的常规声明来声明的类型变量。 |
|
boolean |
isAnnotation() 如果此 Class 对象表示一个注释类型则返回 true。 |
|
boolean |
isAnnotationPresent(Class<? extends 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。 |
|
boolean |
isAnonymousClass() 当且仅当底层类是匿名类时返回 true。 |
|
boolean |
isArray() 判定此 Class 对象是否表示一个数组类。 |
|
boolean |
isAssignableFrom(Class<?> cls) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。 |
|
boolean |
isEnum() 当且仅当该类声明为源代码中的枚举时返回 true。 |
|
boolean |
isInstance(Object obj) 判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。 |
|
boolean |
isInterface() 判定指定的 Class 对象是否表示一个接口类型。 |
|
boolean |
isLocalClass() 当且仅当底层类是本地类时返回 true。 |
|
boolean |
isMemberClass() 当且仅当底层类是成员类时返回 true。 |
|
boolean |
isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。 |
|
boolean |
isSynthetic() 如果此类是复合类,则返回 true,否则 false。 |
|
T |
newInstance() 创建此 Class 对象所表示的类的一个新实例。 |
|
String |
toString() 将对象转换为字符串。 |
三、示例分析
Class类的使用
package me.reflect; /**
* Class类的使用
* @author Administrator
*
*/
public class ClassDemo1 {
public static void main(String[] args) {
// Foo的实例对象如何表示
Foo foo1 = new Foo();// foo1就表示出来了.
// Foo这个类 也是一个实例对象,Class类的实例对象,如何表示呢
// 任何一个类都是Class的实例对象,这个实例对象有三种表示方式 // 第一种表示方式--->实际在告诉我们任何一个类都有一个隐含的静态成员变量class
Class c1 = Foo.class; // 第二中表达方式 已经知道该类的对象通过getClass方法
Class c2 = foo1.getClass(); /*
* 官网 c1 ,c2 表示了Foo类的类类型(class type) 万事万物皆对象, 类也是对象,是Class类的实例对象
* 这个对象我们称为该类的类类型
*
*/
// 不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象
System.out.println(c1 == c2); // 第三种表达方式
Class c3 = null;
try {
c3 = Class.forName("com.imooc.reflect.Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c2 == c3); // 我们完全可以通过类的类类型创建该类的对象实例---->通过c1 or c2 or c3创建Foo的实例对象
try {
Foo foo = (Foo) c1.newInstance();// 需要有无参数的构造方法
foo.print();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} class Foo { void print() {
System.out.println("foo");
}
}
view code
方法的反射
public static void printClassMethodMessage(Object obj) {
// 要获取类的信息 首先要获取类的类类型
Class c = obj.getClass();// 传递的是哪个子类的对象 c就是该子类的类类型
// 获取类的名称
System.out.println("类的名称是:" + c.getName());
/**
* Method类,方法对象 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有的public的函数,包括父类继承而来的
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods();// c.getDeclaredMethods()
for (int i = 0; i < ms.length; i++) {
// 得到方法的返回值类型的类类型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName() + " ");
// 得到方法的名称
System.out.print(ms[i].getName() + "(");
// 获取参数类型--->得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
成员变量的反射
public static void printFieldMessage(Object obj) {
Class c = obj.getClass();
/**
* 成员变量也是对象 java.lang.reflect.Field Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*/
// Field[] fs = c.getFields();
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
// 得到成员变量的类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
// 得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}
构造函数的反射
public static void printConMessage(Object obj) {
Class c = obj.getClass();
/*
* 构造函数也是对象 java.lang.Constructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数 getDeclaredConstructors得到所有的构造函数
*/
// Constructor[] cs = c.getConstructors();
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName() + "(");
// 获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
Java类加载机制
package me.reflect.dynamic; public interface OfficeAble { public void start();
} package me.reflect.dynamic; public class Word implements OfficeAble { public void start() {
System.out.print("word start.....");
}
} package me.reflect.dynamic; public class Excel implements OfficeAble{ @Override
public void start() {
System.out.print("Excel start....");
} } package me.reflect.dynamic; /**
* Java动态加载类测试类
* @author Administrator
*
*/
public class Office { public static void main(String[] args) {
//new创建对象是静态加载类,在编译的时刻就需要加载所有可能使用到的类
//通过动态加载类可以解决该问题
if("Word".equals(args[0])) {
Word w = new Word();
w.start();
}
if("Excel".equals(args[0])) {
Excel e = new Excel();
e.start();
}
}
} package me.reflect.dynamic; public class OfficeBetter { public static void main(String[] args) {
try {
//动态加载类,在运行时刻加载类
Class c = Class.forName(args[0]);
//通过类类型创建该类对象
OfficeAble oa = (OfficeAble) c.newInstance();
oa.start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
参考文章: