欢迎光临散文网 会员登陆 & 注册

java反射reflection

2022-09-14 09:46 作者:虚云幻仙  | 我要投稿

/**
* reflection反射
* 初次创建某一个类的对象时,JVM会先通过类加载器ClassLoader将类文件xxx.class从磁盘中加载到内存(io操作)
* 在方法区中将类生成一个类对象Class<xxx>对象,类对象/Class对象中有类文件的所有信息,每个类的Class对象只生成一个,用来创建类的所有对象
* 通过这个类的唯一的Class对象创建类的对象,当第二次及以后创建对象时,同样使用这个Class对象创建,不再重复加载类文件
*/

public class TestReflection1 implements Serializable {
   //创建一个类
   String name;
   public int age;

   public TestReflection1(String name, int age) {
       this.name = name;
       this.age = age;
   }

   private TestReflection1(String name) {
       this.name = name;
   }
   //私有构造器

   public TestReflection1(int age) {
       this.age = age;
   }

   public TestReflection1() {
   }

   @Override
   public String toString() {
       return "TestReflection1{" +
               "name='" + name + '\'' +
               ", age=" + age +
               '}';
   }
    private void printAge(){
       System.out.println(age);
   }
   //私有方法
   public boolean setAge(int a){
       age  = a;
       return true;
   }
}
class GetClass{
   public static void main(String[] args) {
       TestReflection1 t1 = new TestReflection1("quan",20);
       //Class对象在方法区,新的对象在堆heep,变量t1在栈stack中main栈帧中
       Class<? extends TestReflection1> tClass = t1.getClass();
       //通过实例化的对象.getClass()得到对象所属的类的Class对象,返回类型为Class<? extends 类名>,Class对象只有一份,所有实例化对象调用.getClass()会返回同一个Class对象
       //每个实例化对象都是由这一个Class对象创建的

       System.out.println(tClass);
       //Class对象.toString() 返回“class 包名.类名”
       System.out.println(tClass.getName());
       //.getName()返回"包名.类名"
       Class<GetClass> getClassClass = GetClass.class;
       //通过类的静态属性.class得到Class对象,每个类都有class静态属性,当内存中没有该Class对象时JVM会去磁盘中加载
       try {
           Class<?> aClass = Class.forName("java.lang.String");
           //通过Class类的静态方法.forName(String className)得到Class对象,字符串必须是完整的"包名.类名",返回类型为Class<?>因为编译时没有解析字符串只能用通配符
           System.out.println(aClass);
       } catch (ClassNotFoundException e) {
           throw new RuntimeException(e);
       }

       Constructor<?>[] declaredConstructors = tClass.getDeclaredConstructors();
       //Class对象.getDeclaredConstructors()方法返回构造器类数组Constructor[],declared声明的,返回的是这个类中的所有构造器类的对象,包括private等四种访问控制符修饰的所有构造器对象
       for (Constructor<?> c :
               declaredConstructors) {
           System.out.println(c);
       }
       /*结果
       public TestReflection1()
       public TestReflection1(int)
       private TestReflection1(java.lang.String)
       public TestReflection1(java.lang.String,int)
        */

       Constructor<?>[] constructors = tClass.getConstructors();
       //不加declared的get只返回public的构造器
       System.out.println(Arrays.toString(constructors));
       //结果:[public TestReflection1(), public TestReflection1(int), public TestReflection1(java.lang.String,int)]
       try {
           Constructor<? extends TestReflection1> declaredConstructor = tClass.getDeclaredConstructor(int.class);
           //不加s的get返回单个构造器,需要传入Class<?>...p可变参数对应构造器的形参类型,这里传入的是int.class即int的Class对象,返回只传一个int参数的构造器
           System.out.println(declaredConstructor);
           //结果:public TestReflection1(int)
//            System.out.println(tClass.getConstructor(String.class));
           //不加declared不加s,只查找public的构造器,但TestReflection1(String name)是private的,所以找不到传参为String的构造器,抛出异常java.lang.NoSuchMethodException: TestReflection1.<init>(java.lang.String)

           System.out.println(tClass.getConstructor(null));
           //只传null对应无参构造器,结果为:public TestReflection1() ,idea提示将null改为(Class<?>)null
//            System.out.println(tClass.getConstructor(int.class,String.class));
           //参数顺序和构造器形参顺序不同也会报错,形参顺序不同可以构成重载

           Constructor<? extends TestReflection1> constructor = tClass.getConstructor(String.class, int.class);
           TestReflection1 yang = constructor.newInstance("yang", 20);
           //构造器对象.newInstance(Object...args)方法会生成新的对象,要求传入的参数和构造器的形参类型一致
       } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
           throw new RuntimeException(e);
       }
       Field[] fields = tClass.getFields();
       //.getFields()方法返回public的属性Field[]数组,和构造器对象一样,属性也是对象,这里的Field指成员变量,属于对象,不包含属于类的静态变量
       System.out.println(Arrays.toString(fields));
       //结果为:[public int TestReflection1.age]
       for (Field declaredField : tClass.getDeclaredFields()) {
           //加Declared忽略访问控制符,返回所有Field
           System.out.print(declaredField.getName()+"\t");
           //.getName()返回属性的名字,结果:name     age
       }
       try {
           Field age = tClass.getField("age");
           //不加s返回单个,查找和传参的字符串名字一致的属性,public的属性
           System.out.println(age);
           //结果:public int TestReflection1.age
           System.out.println(tClass.getDeclaredField("name"));
           //加declared忽略访问控制符
           TestReflection1 t2 = tClass.newInstance();
           //通过Class对象.newInstance()创建无参的实例
           age.set(t2,23);
           //Field对象.set(类的对象,值) 用于设定指定类的对象的成员变量的值,上面通过.getField("age")得到了age属性的Field对象,引用变量为age
           //通过Field对象age.set对指定t2的属性age的值进行设定,设定的值的类型同样需要小于等于属性的类型

           System.out.println(age.get(t2));
           //Field对象.get(类的对象)返回指定对象的成员变量的值,使用age.get()会返回age属性的值,传参t2会返回t2对象的age属性的值,返回值类型为Object
           age.setInt(t2,24);
           int i = age.getInt(t2);
           //使用指定具体类型的set、get,setInt要求参数为int类型,getInt返回int类型参数而不是Object
           //对于属性的使用和正常通过对象调用一样,受访问控制符的限制,在类外不能查改private属性(除非关闭安全检查)

       } catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) {
           throw new RuntimeException(e);
       }

       Method[] methods = tClass.getMethods();
       //.getMethods()返回所有public修饰的普通方法对象数组Method[]
       for (Method m :
               methods) {
           System.out.println(m);
       }
       //继承的public方法也会返回,比如继承Object类的public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
       System.out.println(Arrays.toString(tClass.getDeclaredMethods()));
       //返回类内声明的所有方法,declared声明,通过继承得到的但是类内没有声明的方法不会返回
       // 结果为:[public java.lang.String TestReflection1.toString(), private void TestReflection1.printAge(), public boolean TestReflection1.setAge(int)]
       // 返回内容中有toString是因为重写了toString方法

       try {
           Method method1 = tClass.getMethod("setAge", int.class);
           //.getMethod(String name,Class<?>...types)和getConstructor()方法类似,需要指定方法名和形参列表,只能查找public修饰的方法
           System.out.println(method1.getName());
           //.getName()返回方法名,结果:setAge
           System.out.println(tClass.getDeclaredMethod("printAge"));
           //加declared忽略访问控制符,无参方法只传方法名
           TestReflection1 t3 = tClass.newInstance();
           Method setAge = tClass.getDeclaredMethod("setAge",int.class);
           Method printAge = tClass.getDeclaredMethod("printAge");
           Object a = setAge.invoke(t3, 23);
           //Method方法对象.invoke(类的对象,对应形参的参数值),调用哪个方法对哪个对象。invoke调用,返回的是方法的返回值,setAge()方法返回boolean,向上转换为Object返回
           System.out.println(a);
           //结果:true
//            Object pr = printAge.invoke(t3);
           //对t3调用printAge方法,无参数,方法声明void时invoke()返回null,但由于printAge()方法为private,调用时抛异常java.lang.IllegalAccessException: Class GetClass can not access a member of class TestReflection1 with modifiers "private"

           printAge.setAccessible(true);
           //通过.setAccessible(true)关闭安全检查,设为true后JVM不再对该对象的调用检查访问控制符
           Object pr = printAge.invoke(t3);
           //不再报错,accessible可使用的,默认setAccessible(false)开启安全检查,受到访问控制符修饰的属性、方法、构造器等对象均可以通过setAccessible(true)关闭安全检查
       } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
           throw new RuntimeException(e);
       }

       String n = tClass.getName();
       //.getName()返回 包名.类名
       Package aPackage = String.class.getPackage();
       //.getPackage()返回包对象
       System.out.println(aPackage);
       //结果:package java.lang, Java Platform API Specification, version 1.8
       System.out.println(aPackage.getName());
       //结果:java.lang
       System.out.println(tClass.getSimpleName());
       //.getSimpleName()返回不含包名的类名
       Class<?> superclass = tClass.getSuperclass();
       //.getSuperclass()返回父类
       System.out.println(superclass);
       //结果为:class java.lang.Object
       Class<?>[] interfaces = tClass.getInterfaces();
       //.getInterfaces()返回当前类所实现的所有接口的Class对象数组
       System.out.println(Arrays.toString(interfaces));
       //结果为:[interface java.io.Serializable]
   }
}

java反射reflection的评论 (共 条)

分享到微博请遵守国家法律