zoukankan      html  css  js  c++  java
  • [java 基础]反射入门

    原文

    概况

    使用java的反射,可以让我们检查(或者修改)类,接口,字段,方法的特性。当你在编译期不知道他们的名字的时候非常有用。

    除此之外,可以使用反射来创建实例,调用方法或者get/set 字段值。

    设置项目

    需要做的只有导个包。

    import java.lang.reflect.*; //根据使用的情况导特定的,比如reflect.constructor等
    

    简单例子

    先加一下junit的依赖,然后添加一个Person类,两个字段。

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

    写个测试方法来获取这个类的所有字段。

     /**
      * 包含所有字段
      */
     @Test
     public void containAllFields() {
         Object p = new Person();
         Field[] declaredFields = p.getClass().getDeclaredFields();
         List<String> actualFields = Arrays.stream(declaredFields).map(field -> field.getName()).collect(Collectors.toList());
         List<String> exceptFields = new ArrayList<>();
         exceptFields.add("age");
         exceptFields.add("name");
         Assert.assertTrue(exceptFields.containsAll(actualFields));
     }
    

    使用场景

    最常用的使用场景为数据库表和实体类做字段映射。

    检查java类

    下面来做一些测试,用来获取前面提到过的比如类名,修饰符,字段,方法,实现的接口之类的东西。

    准备工作

    先创建一个Eating接口

    public interface Eating {
        String eats();
    }
    

    创建一个抽象Animal类来实现这个Eating接口

    package com.lou.reflect.test;
    
    public abstract class Animal implements Eating {
        public static String CATEGORY = "domestic";
        private String name;
    
        protected abstract String getSound();
    
        public Animal(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    

    创建一个Locomotion接口用来描述动物的行动方式。

    package com.lou.reflect.test;
    
    public interface Locomotion {
        String getLocomotion();
    }
    

    创建一个具体的Goat类,继承自Animal同时实现Locomotion接口。

    package com.lou.reflect.test;
    
    public class Goat extends Animal implements Locomotion {
        public Goat(String name) {
            super(name);
        }
    
        @Override
        protected String getSound() {
            return "山羊叫";
        }
    
        @Override
        public String eats() {
            return "吃草";
        }
    
        @Override
        public String getLocomotion() {
            return "行走";
        }
    }
    

    创建一个Bird类,继承自Animal

    public class Bird extends Animal {
        private boolean walks;
    
    
        public Bird() {
            super("鸟");
        }
    
        public Bird(String name) {
            super(name);
        }
    
        public Bird(String name, boolean walks) {
            super(name);
            this.walks = walks;
        }
    
        @Override
        protected String getSound() {
            return null;
        }
    
        @Override
        public String eats() {
            return null;
        }
    
        public boolean isWalks() {
            return walks;
        }
    
        public void setWalks(boolean walks) {
            this.walks = walks;
        }
    }
    

    做好准备工作之后开始下面的测试。

    类名

    获取类名。

    /**
     * simpleName为Goat,
     * name为com.lou.reflect.test.Goat
     * cannocalName为com.lou.reflect.test.Goat
     */
    @Test
    public void givenObjectThenGetNameTest() {
        Object goat = new Goat("山羊");
        Class<?> goatClazz = goat.getClass();
    
        Assert.assertEquals("Goat", goatClazz.getSimpleName());
        Assert.assertEquals("com.lou.reflect.test.Goat", goatClazz.getName());
        Assert.assertEquals("com.lou.reflect.test.Goat",goatClazz.getCanonicalName());
    }
    

    类修饰符

    /**
     * 通过获取类的modifier来判断类的特性
     * @throws Exception
     */
    @Test
    public void givenObjectThenGetModifiersTest() throws Exception {
        Class<?> animalClazz = Class.forName("com.lou.reflect.test.Animal");
        Class<?> goatClazz = Class.forName("com.lou.reflect.test.Goat");
        //获取两个类的修饰符
        int animalModifiers = animalClazz.getModifiers();
        int goatModifiers = goatClazz.getModifiers();
        //判断是否是公有
        Assert.assertTrue(Modifier.isPublic(goatModifiers));
        //判断是否是抽象
        Assert.assertTrue(Modifier.isAbstract(animalModifiers));
        //判断是否为公有
        Assert.assertTrue(Modifier.isPublic(animalModifiers));
    }
    

    包信息

    /**
     * 获取包信息
     */
    @Test
    public void givenClassThenGetPackageNameTest() {
        Goat goat = new Goat("山羊");
        Package goatPackage = goat.getClass().getPackage();
        Assert.assertEquals("com.lou.reflect.test", goatPackage.getName());
    }
    

    父类信息

    /**
     * 获取父类信息
     */
    @Test
    public void givenClassThenGetSupperClassTest() {
        Goat goat = new Goat("山羊");
        String str = "hello";
    
        Class<?> goatSupperClazz = goat.getClass().getSuperclass();
        Class<?> strSupperClazz = str.getClass().getSuperclass();
    
        Assert.assertEquals("com.lou.reflect.test.Animal",goatSupperClazz.getName());
        Assert.assertEquals("java.lang.Object",strSupperClazz.getName());
    }
    

    实现的接口

    /**
     * 获取实现的接口信息
     *
     * @throws Exception
     */
    @Test
    public void givenClassThenGetImpMethodsTest() throws Exception {
    
        Class<?> goatClazz = Class.forName("com.lou.reflect.test.Goat");
        Class<?> animalClazz = Class.forName("com.lou.reflect.test.Animal");
        Class<?>[] goatInterfaces = goatClazz.getInterfaces();
        Class<?>[] animalInterfaces = animalClazz.getInterfaces();
    
        //实现的接口,都是1个,虽然goat的父类实现了一个,goat自己也实现了一个。
        //只能获取用implements显式实现的接口。如果要全部就只能递归了。
        Assert.assertEquals(1, goatInterfaces.length);
        Assert.assertEquals(1, animalInterfaces.length);
    
        Assert.assertEquals("Locomotion", goatInterfaces[0].getSimpleName());
        Assert.assertEquals("Eating", animalInterfaces[0].getSimpleName());
    
    }
    

    构造函数,方法,字段

    /**
     * 构造函数,方法,字段
     */
    @Test
    public void givenClassThenGetConstructorMethodField() throws Exception {
        Class<?> goatClazz = Class.forName("com.lou.reflect.test.Goat");
        Class<?> animalClazz = Class.forName("com.lou.reflect.test.Animal");
        Constructor<?>[] goatCtors = goatClazz.getConstructors();
        Assert.assertEquals(1, goatCtors.length);
        Field[] animalFields = animalClazz.getDeclaredFields();
        //一个静态的CATEGORY,一个name,所以是2个。
        Assert.assertEquals(2, animalFields.length);
        //3个。这里获取到的是显式申明的方法,不包括那些从object继承下来的
        Method[] animalMethods = animalClazz.getDeclaredMethods();
        Assert.assertEquals(3, animalMethods.length);
        //getName,setName,getSound,
        List<String> methodNames = Arrays.stream(animalMethods).map(method -> method.getName()).collect(Collectors.toList());
        Assert.assertTrue(methodNames.containsAll(Arrays.asList("getName", "setName", "getSound")));
    }
    

    获取构造函数然后动态调用

    /**                                                                                   
     * 获取bird的3个构造函数,然后分别调用~。                                                             
     * @throws Exception                                                                  
     */                                                                                   
    @Test                                                                                 
    public void getConstructorThenCreateInstance() throws Exception {                     
        Class<?> birdClazz = Class.forName("com.lou.reflect.test.Bird");                  
        //获取无参的构造函数                                                                       
        Constructor<?> birdCtro1 = birdClazz.getConstructor();                            
        //获取有一个String类型的参数的构造函数                                                           
        Constructor<?> birdCtro2 = birdClazz.getConstructor(String.class);                
        //获取有一个String类型,一个boolean类型参数的构造函数                                                
        Constructor<?> birdCtro3 = birdClazz.getConstructor(String.class, boolean.class); 
        //调用无参的                                                                           
        Bird bird1 = (Bird) birdCtro1.newInstance();                                      
        Assert.assertEquals("鸟", bird1.getName());                                        
        //调用有一个参数的                                                                        
        Bird bird2 = (Bird) birdCtro2.newInstance("bird2");                               
        Assert.assertEquals("bird2", bird2.getName());                                    
        //调用两个参数的构造函数                                                                     
        Bird bird3 = (Bird) birdCtro3.newInstance("bird3", true);                         
        Assert.assertEquals("bird3", bird3.getName());                                    
        Assert.assertEquals(true, bird3.isWalks());                                       
    }                                                                                     
    

    运行期间修改field值,调用method

    /**
     * 通过获取name字段,然后动态修改。 
     * 通过动态调用setName方法,修改name的值 
     * @throws Exception
     */
    @Test  
    public void givenClassThenModifyFields() throws Exception {
        Class<?> birdClazz = Class.forName("com.lou.reflect.test.Bird");     
        Bird bird =(Bird) birdClazz.newInstance();   
        //定义在父类
        Field nameField = birdClazz.getSuperclass().getDeclaredField("name");                       
        //先设置为可访问                                                                              
        nameField.setAccessible(true);                                                             
        nameField.set(bird,"一只bird");                                                             
        Assert.assertEquals("一只bird",bird.getName());
        Method setNameMethod = birdClazz.getSuperclass().getDeclaredMethod("setName", String.class);       
        setNameMethod.invoke(bird,"又一只"); 
        Assert.assertEquals("又一只",bird.getName());                                                         
    }                                                                                                      
    
  • 相关阅读:
    Atitit 模板引擎总结 v4 saa 目录 1. 模板引擎 1 1.1. 构成渲染引擎+指令系统 1 1.2. 模板语法mustache语法 es6 el语法 1 2. 常见模板步骤 1 2.
    Atitit 常见项目角色与职责 目录 1.1. 常见项目角色与职责 1 1.2. 解决问题思路:一般百度,问同事,问上一级 1 1.3. 解决问题时限:与跳过法 1 1.4. 解决方法,一般实
    Atitit 法学处罚方式模式 目录 1. 申诫罚、财产罚和能力罚 1 1.1. 申诫罚 (警告和通报批评 ) 1 1.2. 财产罚是指使被处罚人的财产权利和利益受到损害的行政处罚。 2 1.2
    java DefaultMutableTreeNode 树形结构 目录 1. Tree的概念 1 1.1. treeNode接口,mutabletreenode接口 1 1.2. 104:以T
    Atitit it软件领域职称评级规定,广博方向。 目录 1. 软件工程师资格证 1 1.1. 法规规范 十大标准,三级五晋制。 1 1.2. 组织架构 域职称评级委员会 2 1.3. 人员职责流程表
    Atitit 学校工作手册attilax艾提拉总结 目录 1. 团队文化 宗旨 与使命 2 1.1. 学术教育vs 技术教育vs 技能职业教育 2 1.2. 天堂模式vs地狱模式 2 2. 组织结构
    Java项目部署目录结构与部署方法 打包方法attilax总结 目录 1.1. Java web项目部署目录结构 1 2. Springboot项目的部署结构 2 3. Java项目的开发模式下目录
    Atitit 人员级别评定法 目录 1.1. 十级评定法110 vs 年级评定法 1 1.2. 工龄评定 职级 岗位级别 1 2. 修订系数 学历*授课+绩效 1 3. 计算方法 1
    Atitit java webservice客户端v2 目录 1.1. 生成stub代码wsimport.exe 1 1.2. Wsimport 2 1.3. clienttest 3 1.1
    Atitti 类库 开发者 常用 api 目录 1.1. Meta anno注解元数据api 1 1.2. Ref 反射api 1 1.3. Database meta api 1 1.4.
  • 原文地址:https://www.cnblogs.com/sheldon-lou/p/11120980.html
Copyright © 2011-2022 走看看