java的反射机制。获取Class实例的4种方式。通过反射获取类的属性、方法、注解、父类、接口等全部信息。通过反射调用类的属性、方法。
1.接口类 Person
package com.example.demo.springProxy.dynamicProxy;
public interface Person {
void wakeup();
void sleep();
}
2.父类 TFather
package com.example.demo.springProxy.dynamicProxy;
public class TFather {
/**
* 专家id
*/
public Long expertId;
/**
*专家名称(模糊匹配)
*/
String name;
public TFather (Long expertId, String name) {
this.expertId = expertId;
this.name = name;
}
public TFather () {
}
public void do1(){
}
public void do2(String x2){
}
public int do3(String x3){
return 1;
}
private void doMy(){
}
}
3.子类 Teacher,继承TFather,实现 Person接口
package com.example.demo.springProxy.dynamicProxy;
import java.io.File;
import java.io.FileNotFoundException;
public class Teacher extends TFather implements Person {
private Integer id;
private String name;
public Teacher() {
}
public Teacher(String name) {
this.name = name;
}
@Override
public void wakeup() {
System.out.println("老师"+name+"早晨醒来啦");
}
@Override
public void sleep() {
System.out.println("老师"+name+"晚上睡觉啦");
}
private int currentCount(){
return 1;
}
private int currentNameUpdate(Integer id,String name){
return 1+id;
}
private Long currentService(Integer id,String name)throws FileNotFoundException {
return 1L;
}
}
4.通过反射获取 类的所有信息
package com.example.demo.springProxy.dynamicProxy;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
public class ReflectTest {
public static void main(String[] args) {
try {
useReflect();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取Class类实例的四种方法
*/
public static void do1() {
try {
//方式一:调用运行时类的属性:.class
Class clazz1 = Teacher.class;
System.out.println(clazz1);//class com.example.demo.springProxy.dynamicProxy.Teacher
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Teacher("王教授");
Class clazz2 = p1.getClass();
System.out.println(clazz2);//class com.example.demo.springProxy.dynamicProxy.Teacher
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.example.demo.springProxy.dynamicProxy.Teacher");
Class clazz5 = Class.forName("java.lang.String");
System.out.println(clazz3);//class com.example.demo.springProxy.dynamicProxy.Teacher
System.out.println(clazz5);//class java.lang.String
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
//方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = Test.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.example.demo.springProxy.dynamicProxy.Teacher");
System.out.println(clazz4);//class com.example.demo.springProxy.dynamicProxy.Teacher
System.out.println(clazz1 == clazz4);//true
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 利用反射 创建对象
*/
public static void test1() {
Class<Teacher> clazz = Teacher.class;
/*
newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器
*/
try {
Person obj = clazz.newInstance();
System.out.println(obj);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 利用反射获取 类的所有信息
*/
public static void test2(){
Class clazz = Teacher.class;
/*
一、通过反射获取 成员变量(属性)
1.getFields(): 类和父类 public访问权限的属性
2.getDeclaredFields():类中声明的所有属性。(不包含父类中声明的属性)
*/
Field[] fields = clazz.getFields();//getFields() 类和父类 public访问权限的属性
Field[] declaredFields = clazz.getDeclaredFields();//getDeclaredFields() 类中声明的所有属性
for(Field f : declaredFields){
//1.权限修饰符
String fMod = Modifier.toString(f.getModifiers());
System.out.print( fMod+ "\t");
//2.数据类型
String fType = f.getType().getName();
System.out.print(fType + "\t");
//3.变量名
String fName = f.getName();
System.out.print(fName);
System.out.println();
}
/*
二、通过反射获取 方法
1.getMethods():类、所有父类中 public权限的方法
2.getDeclaredMethods():类中声明的所有方法。(不包含父类中方法)
*/
Method[] methods = clazz.getMethods();//类及其所有父类中声明为public权限的方法
Method[] declaredMethods = clazz.getDeclaredMethods();//类中声明的所有方法。(不包含父类的方法)
for(Method m : declaredMethods){
//1.获取方法声明的注解
Annotation[] annos = m.getAnnotations();
for(Annotation a : annos){
System.out.println(a);
}
//2.权限修饰符
String mMod=Modifier.toString(m.getModifiers());
System.out.print(mMod + "\t");
//3.返回值类型
String mReturnType=m.getReturnType().getName();
System.out.print( mReturnType+ "\t");
//4.方法名
String methodName=m.getName();
System.out.print(methodName);
System.out.print("(");
//5.形参列表(遍历)
Class[] parameterTypes = m.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
String paramType=parameterTypes[i].getName();
if (i == parameterTypes.length - 1) {
System.out.print( paramType+ " args_" + i);
break;
}
System.out.print(paramType + " 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++){
String exceptionType=exceptionTypes[i].getName();
if(i == exceptionTypes.length - 1){
System.out.print(exceptionType);
break;
}
System.out.print(exceptionType + ",");
}
}
System.out.println();
}
/*
三、通过反射获取 构造器
*/
//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);
}
/*
四、通过反射获取 当前类的父类
*/
Class superclass = clazz.getSuperclass();//普通父类
System.out.println(superclass);
Type genericSuperclass = clazz.getGenericSuperclass();//带泛型的父类
System.out.println(genericSuperclass);
/*
五、通过反射获取 当前类实现的接口
*/
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);
}
/*
六、通过反射获取 当前类所在包
*/
Package pack=clazz.getPackage();
System.out.println(pack);
/*
七、通过反射获取 当前类声明的注解
*/
Annotation[] annos=clazz.getAnnotations();
for (Annotation anno : annos) {
System.out.println(anno);
}
}
/**
* 通过反射 调用运行时类的指定结构
*/
public static void useReflect() throws InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
/*
关于setAccessible方法的使用
⭕ Method和Field、Constructor对象都有setAccessible()方法。
⭕ setAccessible启动和禁用访问安全检查的开关。
⭕ 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
⭕ 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被 调用,那么请设置为true,使得原本无法访问的私有成员也可以访问,
参数值为false则指示反射的对象应该实施Java语言访问检查。
*/
/*
1. 调用运行时类中指定的属性
*/
Class clazz=Teacher.class;
//通过反射 创建运行时类的对象
Teacher p=(Teacher)clazz.newInstance();
// 1.getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field name=clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
//3.获取、设置指定对象的此属性值
name.set(p,"test");
System.out.println(name.get(p));
/*
2. 调用运行时类中的指定的方法
*/
//1.获取指定的某个方法getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
Method method=clazz.getDeclaredMethod("currentNameUpdate",Integer.class,String.class);
//2.保证当前方法是可访问的
method.setAccessible(true);
//3. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参 ,invoke()的返回值即为对应类中调用的方法的返回值
Object returnValue=method.invoke(p,10,"uu");
/*
Object invoke(Object obj, Object … args)
说明:
⭕ Object 对应原方法的返回值,若原方法无返回值,此时返回null
⭕ 若原方法若为静态方法,此时形参Object obj可为null
⭕ 若原方法形参列表为空,则Object[] args为null
⭕ 若原方法声明为private,则需要在调用此invoke()方法前,显式调用 方法对象的setAccessible(true)方法,将可访问private的方法。
*/
System.out.println(returnValue);
/*
3 .获取指定的构造器
*/
//1.getDeclaredConstructor():参数:指明构造器的参数列表
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//2.保证此构造器是可访问的
constructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象
Person per = (Person) constructor.newInstance("Tom");
System.out.println(per);
}
}
5.感谢大佬的文章,欢迎大家去膜拜大佬,参考链接如下
java反射机制