• 0033 Java学习笔记-反射-初步1


    先看看通过反射能干嘛

    • 示例:修改对象的private实例变量
    package testpack;
    import java.lang.reflect.Field;
    public class Test1 {  
        public static void main(String[] args)throws Exception{ 
        	Person per=new Person("Java",21);
        	System.out.println("现在的per对象是:"+per);   //[name= Java , age= 21 ]
        	
        	Class<Person> perClazz=Person.class;           //获取Person类的Class对象
        	
        	Field fName=perClazz.getDeclaredField("name"); //获取Person类的名为“name”的变量,即使是private修饰
        	fName.setAccessible(true);                     //取消该变量的访问权限检查
        	fName.set(per, "C++");                         //将per对象的name变量改为“C++”
        	
        	Field fAge=perClazz.getDeclaredField("age");
        	fAge.setAccessible(true);
        	fAge.set(per, 33);                             //将per对象的age变量改为“33”
        	
        	System.out.println("private的实例变量被修改了,还是那个per对象:"+per); //[name= C++ , age= 33 ]
        }
    }
    class Person{
    	private int age;
    	private String name;
    	public Person(String n,int a){
    		name=n;
    		age=a;
    	}
    	public String toString(){
    		return "[name= "+name+" , age= "+age+" ]";
    	}
    }
    
    • 上面的示例中,虽然age和name被private修饰,但还是被修改了,那这岂不是很不安全,违背了封装的初衷?我也不知道

    java.lang.class

    • 有一个类很特别,它是所有类的类,它就是java.lang.class
    • 要使用一个类的时候,类加载器找到并加载这个类,同时返回其Class对象;也就是说只要一个类被加载了,那么就一定存在它的Class对象
    • 如何获得一个类的Class对象?以String类为例
      • Class.forName("java.lang.String"):用Class类的静态方法forName("包名+类名")来获取
      • String.class:通过调用一个类的class属性来获取
        • 一般用这种方式
        • 代码更安全。程序在编译阶段就可以检查要访问的Class对象是否存在。?不懂
        • 程序性能更好。因为无须调用方法。
      • String的实例.getClass():通过Object类的一个实例方法getClass()方法获取
    • 获取一个类的Class对象后,就可以调用其方法获得该对象和该类的真实信息了

    Class主要方法

    • 构造器:以下用“para”代表Class<?>...parameterTypes,这是个数可变的形参列表
      • Constructor getConstructor(para):返回该Class对象对应类的、带指定形参的public构造器
      • Constructor<?>[] getConstructors():返回对应类的所有public构造器
      • Constructor getDeclaredConstructor(para):返回对应类的、带指定形参列表的构造器,不论是什么访问权限
      • Constructor<?>[] getDeclaredConstructors():返回对应类的所有构造器,不论访问权限
    • 方法:
      • Method getMethod(String name,para):返回对应类的、指定方法名、指定形参列表的public方法
      • Method[] getMethods():返回指定类的所有public方法
      • Method getDeclaredMethod(String name,para):返回对应类的、指定方法名、指定形参列表的方法,不论访问权限
      • Method[] getDeclaredMethods():返回对应类的所有方法,不论访问权限
    • 成员变量
      • Field getField(String name):返回对应类的、指定名称的public成员变量
      • Filed[] getFields():返回对应类的所有public成员变量
      • Field getDeclaredField(String name):返回对应类的、指定名称的成员变量,不论访问权限
      • Field[] getDeclaredFields():返回对应类的所有成员变量,不论访问权限
    • 注解
      • <A extends Annotation> A getAnnotation(Class<A>AnnotationClass):获取对应类的指定的注解,不存在则返回null
      • <A extends Annotation> A getDeclaredAnnotation(Class<A>AnnotationClass):获取直接修饰该对应类的、指定的注解,不存在则返回null
      • Annotation[] getAnnotations():返回对应类上的所有注解
      • Annotation[] getDeclaredAnnotations():返回直接修饰该对应类的所有注解
      • <A extends Annotation> A[] getAnnotationsByType(Class<A>AnnotationClass):针对重复注解功能,返回修饰该对应类的、指定类型的多个注解
      • <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A>AnnotationClass):针对重复注解功能,获取直接修饰对应类的、指定类型的注解
    • 内部类
      • Class<?>[] getDeclaredClasses():返回对应类里包含所有内部类
    • 外部类:
      • Class<?> getDeclaringClass():返回对应类的所在的外部类
    • 接口:
      • Class<?> getInterfaces():返回对应类所实现的所有接口
    • 父类:
      • Class<?super T> getSuperclass():返回对应来的父类的Class对象
    • 修饰符:
      • int getModifiers():返回对应类或接口的所有修饰符对应的常量,应使用Modifier工具类的方法解码,才能获得真实的修饰符
    • 所在包:
      • Package getPackage():获取对应类所在的包
    • 类名:
      • String getName():返回对应类的名称,全局限定名(即包含包名)
      • String getSimpleName():返回对应类的名称,不包含包名的类名
    • is方法
      • boolean isAnnotation:是不是注解类型
      • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):对应类是否使用了Annotation修饰
      • boolean isAnonymousClass():对应类是否是一个匿名类
      • boolean isArray():对应类是否是一个数组
      • boolean isEnum():对应类是否是一个枚举
      • boolean isInterface():对应类是否是一个接口
      • boolean isInstance(Object obj):判断该obj是不是对应类的实例,可以完全替代instanceof
    • 相关方法示例:以Strin类为例
    package testpack;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test1  {  
        public static void main(String[] args)throws Exception{ 
        	Class clazz=String.class;
        	
        	System.out.println("---------------------------------下面是String的成员变量部分---------------------------------");
        	System.out.println("-----------所有的public成员变量-----------");
        	Field[] pfs=clazz.getFields();
        	for (Field f:pfs) {
        		System.out.println(f);
        	}
        	System.out.println("-----------所有成员变量-----------");
        	Field[] fs=clazz.getDeclaredFields();
        	for (Field f:fs) {
        		System.out.println(f);
        	}
        	
        	System.out.println("---------------------------------下面是String的构造器部分---------------------------------");
        	System.out.println("String的无参构造:"+clazz.getConstructor(null));
        	System.out.println("String以byte[]为参数的构造器:"+clazz.getConstructor(byte[].class));
        	System.out.println("String以StringBuffer为参数的构造器:"+clazz.getConstructor(StringBuffer.class));
        	System.out.println("---------------所有构造器-----------------");
        	Constructor[] cs=clazz.getDeclaredConstructors();
        	for(Constructor c:cs){
        		System.out.println(c);
        	}
        	
        	System.out.println("---------------------------------下面是String的方法部分---------------------------------");
        	System.out.println("String的名为intern的无参方法:"+clazz.getMethod("intern",null));
        	System.out.println("String的名为valueOf的参数为int的方法:"+clazz.getMethod("valueOf",int.class));
        	System.out.println("--------------所有方法--------------------");
        	Method[] ms=clazz.getDeclaredMethods();
        	for (Method m:ms) {
        		System.out.println(m);
        	}
        	System.out.println();
        	
        	System.out.println("---------------------------------下面是String的注解部分---------------------------------");
        	System.out.println("---------下面是String的所有注解---------------");
        	Annotation[] as=clazz.getAnnotations();
        	for (Annotation a:as) {
        		System.out.println(a);                      //没有输出:因为String类没有注解(但String类内部的一些元素有注解)
        	}
        	System.out.println("---------------------------------下面是String的所有内部类---------------------------------");
        	Class[] css=clazz.getDeclaredClasses();
        	for (Class c:css) {
        		System.out.println(c);
        	}
        	System.out.println("---------------------------------下面是String实现的所有接口---------------------------------");
        	Class[] is=clazz.getInterfaces();
        	for (Class i:is) {
        		System.out.println(i);
        	}
        	System.out.println("---------------------------------其他---------------------------------");
        	System.out.println("String的直接父类:"+clazz.getSuperclass());
        	System.out.println("String的修饰符:"+clazz.getModifiers());
        	System.out.println("String所在的包:"+clazz.getPackage());
        	System.out.println("String的全局限定名:"+clazz.getName());
        	System.out.println("String的类名:"+clazz.getSimpleName());
        }
    }
    
    

    关于参数的反射:since1.8

    • 构造方法和方法中包含形参列表,Java1.8增加了Parameter类来描述参数
    • 上面Class对象关于构造器和方法的返回值分别是:Constructor和Method,这两个类是Executable类的子类
    • Executable的主要方法有:
      • boolean isVarArgs():是否包含可变数量的形参
      • int getModifiers():获取修饰符
      • int getParameterCount():获取形参数量
      • Parameter[] getParameters():获取所有形参
    • Parameter的主要方法
      • int getModifiers():获取形参的修饰符
      • String getName():获取形参名
      • Type getParameterizedType():获取带泛型的形参类型
      • Class<?> getType():获取形参类型
      • boolean isNamePresent():所在类的class文件中是否包含了形参名信息;
        • 一般情况下,编译的时候都不包含形参名,除非加上“-parameters”选项
      • boolean isVarArgs():该参数是否为个数可变的形参
    • 见示例:
    package testpack;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Parameter;
    
    public class Test1  {  
        public static void main(String[] args)throws Exception{ 
        	Class clazz=String.class;
        	Constructor c=clazz.getConstructor(byte[].class,int.class,int.class);
        	System.out.println("该构造器的形参个数:"+c.getParameterCount());
        	Parameter[] ps=c.getParameters();
        	for (Parameter p:ps) {
        		System.out.println("该参数是:"+p);
        		System.out.println("该参数的修饰符:"+p.getModifiers());
        		System.out.println("该参数的形参名:"+p.getName());
        		System.out.println("形参类型:"+p.getType());
        		System.out.println("是否有形参名信息:"+p.isNamePresent());
        		System.out.println("是否是个数可变的形参:"+p.isVarArgs());
        		System.out.println("--------------------------");
        	}
        }
    }
    
  • 相关阅读:
    看门狗定时器
    fork 和 exec
    openwrt procd分析
    减肥经验总结
    gcc
    laravel5验证码
    laravel5通过auth.attempt事件加入登陆验证码
    双向链表
    mysql5.6源码安装
    laravel4通过控制视图模板路劲来动态切换主题
  • 原文地址:https://www.cnblogs.com/sonng/p/6116693.html
Copyright © 2020-2023  润新知