反射(Reflection)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。
反射的特征:动态性
Class类定义在java.lang包下(java.lang.Class)
程序在经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾),此过程是编译的过程。
使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程称为类的加载。
加载到内存中的类称为运行时类,此运行时类就作为Class的一个实例。Class的实例就对应一个运行时类。
类加载的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存
标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
类加载器作用是用来把类(class)装载进内存的
加载到内存中的运行时类会缓存一定的时间,在此时间之内可以通过不同的方式来获取此运行时类。以下几种方式是获取运行时类,不是创建运行时类。(personClass1、personClass2等等都是获取的唯一存在的运行时类)
方式一
调用运行时类的属性:.class
Class<Person> personClass = Person.class;
Class personClass = Person.class;
方式二
通过运行时类的对象调用getClass()方法
Person p1 = new Person();
Class personClass2 = p1.getClass();
方式三(主要使用)
可以更好的体现动态性
调用Class的静态方法:forName(String classPath)
此时的classPath是包含包在内的完整路径(否则无法准确知道准确的类)
Class personClass3 = Class.forName("Understand.Person");
方式四(了解)
使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class personClass4 = classLoader.loadClass("Understand.Person");
newInstance()方法
调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器
使用要求:
类中要求提供一个public空参构造器的原因:
Class<Person> pclass = Person.class;
Person person = pclass.newInstance();
System.out.println(person);
此时的Person类完整代码如下
@MyAnnotation(value = "hi")
public class Person extends Creature<String> implements Comparable<String>, MyInterface{
private String name;
int age;
public int id;
public Person(){
}
@MyAnnotation(value = "abc")
private Person(String name){
this.name = name;
}
Person(String name,int age){
this.name = name;
this.age = age;
}
@MyAnnotation
private String show(String nation){
System.out.println("国籍:" + nation);
return nation;
}
public String display(String interest){
return interest;
}
@Override
public void info() {
System.out.println("我是一个人");
}
@Override
public int compareTo(String s) {
return 0;
}
private static void showDesc(){
System.out.println("可爱的猫");
}
@Override
public String toString() {
return "Person{" +
"name=‘" + name + ‘\‘‘ +
", age=" + age +
", id=" + id +
‘}‘;
}
}
Person类的父类Creature类
public class Creature<T> implements Serializable {
private char gender;
public double weight;
private void breath(){
System.out.println("生物呼吸");
}
public void eat(){
System.out.println("生物进食");
}
}
自定义接口MyInterface
public interface MyInterface {
void info();
}
自定义注释
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE, ElementType.MODULE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "hello";
}
getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = personClass.getFields();
for(Field f : fields){
System.out.println(f);
}
getDeclaredFields():获取当前运行时类当中声明的所有属性(不包含父类中声明的属性)
Field[] declaredFields = personClass.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
权限修饰符
getModifiers()
该方法返回值为int,是因为Modifier类将各种权限修饰符用数字来表示。想要显示变量的权限修饰符,要使用Modifier中的toString()方法
数据类型
getType()
变量名
getName()
Class personClass = Class.forName("Get.Person");
Field[] declaredFields = personClass.getDeclaredFields();
for(Field f : declaredFields){
//1. 权限修饰符
int modifiers = f.getModifiers();
System.out.println("权限修饰符:" + Modifier.toString(modifiers));
//2. 数据类型
Class type = f.getType();
System.out.println("数据类型:" + type.getName());
//3. 变量名
String name = f.getName();
System.out.println("变量名:" + name);
}
getMethods():获取当前运行类及其父类所有声明为public权限的方法
Method[] methods = personClass.getMethods();
for(Method m : methods){
System.out.println(m);
}
getDeclaredMethods():获取当前运行时类中声明的所有的方法(不包含父类中声明的方法)
Method[] declaredMethods = personClass.getDeclaredMethods();
for(Method m : declaredMethods){
System.out.println(m);
}
注解
getAnnotations()
权限修饰符
getModifiers()
返回值类型
getReturnType()
方法名
getName()
形参列表
getParameterTypes()
抛出异常类型
getExceptionTypes()
Class<?> personClass = Class.forName("Get.Person");
Method[] declaredMethods = personClass.getDeclaredMethods();
for(Method m : declaredMethods){
//6. 注解
Annotation[] annotations = m.getAnnotations();
for(Annotation a : annotations){
System.out.println("注解:" + a);
}
System.out.println();
//1. 权限修饰符
int modifiers = m.getModifiers();
System.out.print(Modifier.toString(modifiers) + "\t");
//2. 返回值类型
System.out.print(m.getReturnType().getName() + "\t");
//3. 方法名
System.out.print(m.getName() + "\t");
System.out.print("(");
//4. 形参列表
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(")");
//5. 抛出异常
Class[] exceptionTypes = m.getExceptionTypes();
if(!(exceptionTypes == null || 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() + ",");
}
}
}
getConstructors():获取当前运行时类当中声明为public类型的构造器
Class personClass = Class.forName("Get.Person");
Constructor[] constructors = personClass.getConstructors();
for(Constructor c : constructors){
System.out.println(c);
}
getDeclaredConstructors():获取当前运行时类中所有的构造器
Constructor[] declaredConstructors = personClass.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
System.out.println(c);
}
getSuperclass():获取运行时类的父类
Class personClass = Class.forName("Get.Person");
Class superclass = personClass.getSuperclass();
System.out.println(superclass);
getGenericSuperclass():获取运行时类带泛型的父类
Type genericSuperclass = personClass.getGenericSuperclass();
System.out.println(genericSuperclass);
getActualTypeArguments():获取运行时类的带泛型父类的泛型
Type genericSuperclass = personClass.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType)genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(Arrays.toString(actualTypeArguments));
getInterfaces():获取运行时类实现的接口
Class[] interfaces = aClass.getInterfaces();
for(Class i : interfaces){
System.out.println(i);
}
getPackage():获取运行时类当前所在的包
Class aClass = Class.forName("Get.Person");
Package aPackage = aClass.getPackage();
System.out.println(aPackage);
getAnnotations():获取运行时类所声明的注解
Annotation[] annotations = aClass.getAnnotations();
for(Annotation a : annotations){
System.out.println(a);
}
创建运行时类的对象
获取指定的属性
getDeclaredField(String fieldName)
通常采用getDeclaredField(String fieldName)方法获取属性。为获取运行时类中指定变量名(fieldName)的属性
保证当前属性是可访问的:使用setAccessible()方法
name.setAccessible(true);
只用使用这个方法,才可以对权限是非public的变量进行修改。
在编写的时候,可以不管变量的权限修饰符是那种,都写上此方法
对属性的操作
set(Object obj, Object value)
Class aClass = Class.forName("Get.Person");
//1. 创建运行时类的对象
Person p = (Person) aClass.newInstance();
//2. 获取指定的属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
//设置当前属性的值
name.set(p,"Tom");
//获取当前属性的值
String pName = (String) name.get(p);
System.out.println("name:" + pName);
Method show = aClass.getDeclaredMethod("show", String.class)
show.setAccessible(true);
show.invoke(p,"CN");
Class aClass = Class.forName("Get.Person");
Person p = (Person) aClass.newInstance();
Method show = aClass.getDeclaredMethod("show", String.class);
show.setAccessible(true);
String returnCn = (String) show.invoke(p, "CN");
System.out.println(returnCn);
利用 当前类.class或者null 表示当前类
Method showDesc = aClass.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//Person.class表示当前类
showDesc.invoke(Person.class);
Class aClass = Class.forName("Get.Person");
Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
Person p = (Person) declaredConstructor.newInstance("Tom");
System.out.println(p);
原文:https://www.cnblogs.com/CrabDumplings/p/13525023.html