Java 反射

一、Model 类

public class Person {
    private String name;
    private int age;

    public Person(){

    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String toString(){
        return "大家好";
    }

    public String sayHello(String name,int age){
        return name+","+age;
    }
}

二、实例化

  • 创建JavaBean无参实例
public class ReflectDemo01 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //三种方式获取类类型
        Class clazz = Person.class;
        Class clazz = person.getClass();
        Class clazz = Class.forName("Person");
        //反射创建无参实例
        Person person = (Person) clazz.newInstance();
        person.setAge(16);
        person.setName("wjx");
        System.out.print(person.getName()+","+person.getAge());
    }
}
  • 创建JavaBean有参实例
public class ReflectDemo02 {
    public static void main(String[] args){
        try {
            Class clazz =Class.forName("Person");
            //获取所有public修饰的构造方法集合
            Constructor constructor[] =clazz.getConstructors();
            //获取该类声明的所有构造方法集合
            Constructor constructor[] =clazz.getDeclraredConstructors();
            //创建有参数的实例对象,获取构造方法的Index与Person类的构造方法先后顺序有关
            Person person = (Person) constructor[1].newInstance("wjx",16);
            System.out.println(person.getName()+","+person.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 访问JavaBean属性
public class ReflectDemo03 {
    public static void main(String[] args){
        try {
            Class clazz =Class.forName("Person");
            Person person = (Person) clazz.newInstance();

            //获取指定名称的属性
            Field nameField =clazz.getDeclaredField("name");
            //通过反射访问该属性时取消权限检查,Private,Protect,Public。
            nameField.setAccessible(true);
            //设置属性值
            nameField.set(person,"wjx");

            //获取指定名称的属性
            Field ageField =clazz.getDeclaredField("age");
            //通过反射访问该属性时取消权限检查,Private,Protect,Public。
            ageField.setAccessible(true);
            //设置属性值
            ageField.set(person,16);

            //获取所有public的成员变量的信息
            Field[] fs = person.getFields();
            //获取该类声明的所有成员变量的信息
            Field[] fs = person.getDeclaredFields();

            //打印信息
            System.out.println(person.getName()+","+person.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 访问JavaBean方法
public class ReflectDemo04 {
    public static void main(String[] args){
        try {
            Class clazz =Class.forName("Person");

            //获取public修饰的无参方法
            Method method =clazz.getMethod("toString");
            //获取该类声明的无参方法
            Method method =clazz.getDeclaredMethod("toString");
            String result = (String) method.invoke(clazz.newInstance());

            //调用有参的方法
            Method method1 =clazz.getMethod("sayHello", String.class, int.class);
            String result1 = (String) method1.invoke(clazz.newInstance(),"wjx",16);

            //获取所有public函数,包括父类继承而来
            Method[] methods = person.getMethods();
            //获取所有该类声明的方法,任何访问权限
            Method[] methods = person.geDeclaredMethods();

            //依次输出结果
            System.out.println(result);
            System.out.println(result1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 获取JavaBean属性信息
public class IntrospectorDemo01 {
    public static void main(String[] args) throws Exception{
        Person person = new Person();
        //依据Person产生一个相关的BeanInfo类
        BeanInfo beanInfo = Introspector.getBeanInfo(person.getClass(),person.getClass().getSuperclass());
        //获取该Bean中的所有属性的信息,以PropertyDescriptor数组的形式返回
        PropertyDescriptor[] descriptors =beanInfo.getPropertyDescriptors();
        String str ="内省成员属性:\n";
        for(int i=0;i<descriptors.length;i++){
            //获取属性名
            String propertyName = descriptors[i].getName();
            //获取属性方法
            Method method = descriptors[i].getReadMethod();
            //获取属性值
            Object propertyValue = method.invoke(person);
            //获取属性类型
            Class propertyType = descriptors[i].getPropertyType();
            //遍历输出
            str+=propertyName+"("+propertyType+")\n";
        }
        System.out.println(str);
    }
}
  • 设置JavaBean属性的值
public class IntrospectorDemo02 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        //使用属性描述器获取Person类name属性的描述信息
        PropertyDescriptor descriptor = new PropertyDescriptor("name", person.getClass());
        //获取name属性对应的setter方法
        Method method = descriptor.getWriteMethod();
        //调用setter方法,并设置name的属性值
        method.invoke(person, "wjx");

        int age = 16;
        descriptor = new PropertyDescriptor("age", person.getClass());
        Method method1 = descriptor.getWriteMethod();
        method1.invoke(person, age);

        System.out.println(person.getName()+","+person.getAge());
    }
}
  • 获取JavaBean属性的值
public class IntrospectorDemo03 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.setName("wjx");
        person.setAge(16);
        //使用属性描述器获取Person类name属性的描述信息
        PropertyDescriptor descriptor = new PropertyDescriptor("name", person.getClass());
        //获取name属性对应的getter方法
        Method method = descriptor.getReadMethod();
        //调用getter方法,并获取name属性值
        Object object = method.invoke(person);
        System.out.println("姓名:" + object);

        descriptor = new PropertyDescriptor("age", person.getClass());
        //获取name属性对应的getter方法
        Method method1 = descriptor.getReadMethod();
        //调用getter方法,并获取name属性值
        Object object1 = method1.invoke(person);
        System.out.println("年龄:" + object1);
    }
}
  • 对象属性非空校验
private Map<String,Object> validate(Object object, List<String> list) throws Exception {
    Map<String, Object> map = new HashMap<>();
    BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass(), object.getClass().getSuperclass());
    PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
    for (int i = 0; i < descriptors.length; i++) {
        String propertyName = descriptors[i].getName();
        Method method = descriptors[i].getReadMethod();
        Object propertyValue = method.invoke(object);
        if (list.contains(propertyName)) {
            if (StringUtils.isEmpty(propertyValue)) {
                map.put("msg",propertyName +" is null");
                return map;
            }
        } else {
            if (propertyValue == null) {
                map.put("msg",propertyName +" is null");
                return map;
            }
        }
    }
    return map;
}

User user = new User(1,"wjx",null);
List<String> columns = Arrays.asList("id", "name" , "age");
Map<String,Object> map = validate(user,columns);

三、自定义注解

1、@Retention:指定标记注释的存储方式。

  • RetentionPolicy.SOURCE:标记的注释仅保留在源级别中,并由编译器忽略。
  • RetentionPolicy.CLASS:标记的注释在编译时由编译器保留,但Java虚拟机会忽略。
  • RetentionPolicy.RUNTIME:标记的注释由JVM保留,因此运行时环境可以使用它。

2、@Target:注释标记另一个注释,以限制可以应用注释的Java元素类型。

  • ElementType.TYPE:可以应用于类或接口或枚举的任何元素。
  • ElementType.FIELD:可以应用于字段或属性。
  • ElementType.METHOD:可以应用于方法级注释。
  • ElementType.PARAMETER:可以应用于方法的参数。
  • ElementType.CONSTRUCTOR:可以应用于构造函数。
  • ElementType.LOCAL_VARIABLE:可以应用于局部变量。
  • ElementType.ANNOTATION_TYPE:可以应用于注释类型。
  • ElementType.PACKAGE:可以应用于包声明。

3、@Documented:注释表明,无论何时使用指定的注释,都应使用Javadoc工具记录这些元素。
4、@Inherited:注释表明注释类型可以从超类继承。当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型,此注释仅适用于类声明。
5、@Repeatable:注释表明标记的注释可以多次应用于相同的声明或类型使用。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Annotation { -> 定义注解
    String empty() default "";
}

public class SystemUser{ -> 添加注解
  @Annotation(empty = "wjx")
  private String username;

  public String getUsername() {
        return this.username;
    }

  public void setUsername(String username) {
        this.username = username;
    }
}

try { -> 获取注解值
    SystemUser user = new SystemUser();
    Class clazz = user.getClass();
    Field field = clazz.getDeclaredField("username");
    if(field.isAnnotationPresent(Annotation.class)){ -> 属性是否有@Annotation
      Annotation annotation = field.getAnnotation(Annotation.class);
      System.out.println(annotation.empty());
    }
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}

扫描某个包下的所有JAVA类

List<Class<?>> classList = new ArrayList<>();
ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader();
String classPath = WJX.class.getPackage().getName();
String packagePath = classPath.replace(".", "/");
try {
    Enumeration<URL> enumeration = appClassLoader.getResources(packagePath);
    while (enumeration.hasMoreElements()) {
        URL url = enumeration.nextElement();
        // 协议名称
        String protocol = url.getProtocol();
        if ("file".equals(protocol)) {
            String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
            // 判断包路径是否存在且是否目录
            File file = new File(filePath);
            if (!file.exists() || !file.isDirectory()) {
                return;
            }
            // 获取包下所有目录和文件
            File[] fileArray = file.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    // 自定义过滤条件
                    return pathname.isDirectory() || pathname.getName().endsWith(".class");
                }
            });
            if (fileArray == null) {
                return;
            }
            for (File files : fileArray) {
                int index = files.getName().lastIndexOf(".");
                String className = files.getName().substring(0, index);
                classList.add(appClassLoader.loadClass(classPath + "." + className));
            }
        }
    }
    for (Class<?> clazz : classList) {
        System.out.println(clazz.getName());
    }
} catch (Exception e) {
    e.printStackTrace();
}

6、@Override:检查该方法是否是重写方法。
7、@Deprecated:标记过时方法。
8、@SuppressWarnings:指示编译器去忽略注解中声明的警告。
9、@SafeVarargs:忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
10、@Repeatable:标识某注解可以在同一个声明上使用多次。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容