反射
反射是指在程序运行期间,能够观察和修改类或者类的对象的属性和行为的特性。
反射的作用:
Java反射机制提供了以下的功能 在运行时获取类的修饰符,包名,类名,实现的接口,继承的父类
在运行时获取类的所有属性名,修饰符,属性类型
在运行时获取所有方法,方法的返回值类型,方法名,方法参数数量,方法参数类型
在运行时调用加载类的方法
Java中的四种元注解:
@Retention:注解的保留位置
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target:注解的作用目标
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
一、自定义注解
//自定义注解 //注释可用在类、成员变量、方法、构造函数上 @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR}) @Documented//文档注解 @Inherited//可继承,允许子类继承父类的注解 @Retention(RetentionPolicy.RUNTIME)//注解保留在的位置 public @interface StudentAnnotation { String name(); int num(); }
二、创建一个对象类
@StudentAnnotation(name = "我是类", num =123) public class Student extends Thread implements Runnable,Callable{ @StudentAnnotation(name = "我是成员变量", num =121) private String stuName; private int age; private String stuNumb; @StudentAnnotation(name = "我是带参构造函数", num =121) public Student(String stuName, int age, String stuNumb) { this.stuName = stuName; this.age = age; this.stuNumb = stuNumb; } @StudentAnnotation(name = "我是无参构造函数", num =126) public Student() { } @StudentAnnotation(name = "我是方法showInf", num =122) public String showInf(){ return "姓名是:"+stuName+",年龄是:"+age+",学号是:"+stuNumb; } @StudentAnnotation(name = "我是方法test", num =122) private void test(){ System.out.println("我是私有方法!test()"); } public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getStuNumb() { return stuNumb; } public void setStuNumb(String stuNumb) { this.stuNumb = stuNumb; } @Override public void run() { // TODO Auto-generated method stub } @Override public Object call() throws Exception { // TODO Auto-generated method stub return null; } }
三、创建一个测试类,通过反射获取类的信息及属性,方法,构造函数,注解
public class TestCase { public static void main(String[] args) throws Exception { TestCase tc=new TestCase(); //三种获得类名的方式 Class cla1=Class.forName("ldl.fanshe619.Student"); Class cla2=Student.class; Class cla3=new Student().getClass(); System.out.println("类名是:"+cla1); tc.getSuperClassOrInterface(cla1); System.out.println(" --------------------------"); tc.getClassAndModifies(cla1); System.out.println("--------------------------"); tc.getFields(cla1); System.out.println("--------------------------"); tc.getMethods(cla1); System.out.println("--------------------------"); tc.getConstructors(cla1); System.out.println("--------------------------"); tc.getAnnotation(cla1); } //1.获取类的父类和实现的接口 public void getSuperClassOrInterface(Class cla) throws Exception{ String supname=cla.getSuperclass().getName(); System.out.println("继承的父类是:"+supname); Class[] c1=cla.getInterfaces(); System.out.print("实现的接口有:"); for(Class ca:c1){ System.out.print(ca+","); } } //2.获取类名和访问修饰符 public void getClassAndModifies(Class cla){ //获取类的访问修饰符 int a=cla.getModifiers(); Modifier.toString(a); System.out.println("类的修饰符是:"+Modifier.toString(a)); } //3.获取所有成员变量 public void getFields(Class cla) throws Exception{ //获得所有变量的信息 Field[] f=cla.getDeclaredFields(); System.out.println("所有成员变量:"); for(Field fe:f){ System.out.println(Modifier.toString(fe.getModifiers())+" "+fe.getType().getSimpleName()+" "+fe.getName()); } //获取单个变量的信息 Field fe=cla.getDeclaredField("stuName"); //System.out.println(fe); //创建Class对象 Object obj=cla.newInstance(); //屏蔽变量的私有特性,并赋值 fe.setAccessible(true); //没有屏蔽私有属性的变量会赋值失败 fe.set(obj, "张三"); Student st=(Student) obj; System.out.println("学生名为:"+st.getStuName()); } //4.获取所有成员方法 public void getMethods(Class cla) throws Exception{ //获取自己类中的方法(所有的公共方法和私有方法) Method[] me=cla.getDeclaredMethods(); //获取自己类中和所有父类中的所有公共方法 Method[] me2=cla.getMethods(); System.out.println("所有成员方法:"); for(Method meth:me){ System.out.println(Modifier.toString(meth.getModifiers())+" "+meth.getReturnType().getSimpleName()+" "+ meth.getName()+"()"+"{}"); } //获取test方法 Method mth=cla.getDeclaredMethod("test"); //屏蔽方法的私有属性 mth.setAccessible(true); //创建对象 Object obj=cla.newInstance(); //实现对test方法的调用,invoke中还可传参数(不定长参数) mth.invoke(obj); } //5.获取构造函数 public void getConstructors(Class cla) throws Exception{ //获取所有构造函数 Constructor[] con=cla.getConstructors(); for(Constructor cons:con){ System.out.println(cons); } //获取定义参数的构造函数 Constructor constr=cla.getConstructor(String.class,int.class,String.class); Object obj=constr.newInstance("王庆",18,"12345"); Student stu=(Student) obj; System.out.println(stu.showInf()); } //6.获取注解 public void getAnnotation(Class cla) throws Exception{ StudentAnnotation stu1=(StudentAnnotation) cla.getAnnotation(StudentAnnotation.class); System.out.println("类的注解是:"+stu1); StudentAnnotation stu2=cla.getDeclaredField("stuName").getAnnotation(StudentAnnotation.class); System.out.println("成员变量的注解是:"+stu2); StudentAnnotation stu3=cla.getDeclaredMethod("test").getAnnotation(StudentAnnotation.class); System.out.println("方法的注解是:"+stu3); StudentAnnotation stu4=(StudentAnnotation)cla.getConstructor().getAnnotation(StudentAnnotation.class); System.out.println("构造函数的注解是:"+stu4); } }