Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[java 基础]反射入门

[java 基础]反射入门

作者头像
_淡定_
发布于 2019-07-03 09:14:59
发布于 2019-07-03 09:14:59
39100
代码可运行
举报
文章被收录于专栏:dotnet & javadotnet & java
运行总次数:0
代码可运行

原文

概况

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

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

设置项目

需要做的只有导个包。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.lang.reflect.*; //根据使用的情况导特定的,比如reflect.constructor等

简单例子

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Person {
    private String name;
    private int age;
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 /**
  * 包含所有字段
  */
 @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接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Eating {
    String eats();
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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接口用来描述动物的行动方式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.lou.reflect.test;

public interface Locomotion {
    String getLocomotion();
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
    }
}

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

类名

获取类名。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 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());
}

类修饰符

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 通过获取类的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));
}

包信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 获取包信息
 */
@Test
public void givenClassThenGetPackageNameTest() {
    Goat goat = new Goat("山羊");
    Package goatPackage = goat.getClass().getPackage();
    Assert.assertEquals("com.lou.reflect.test", goatPackage.getName());
}

父类信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 获取父类信息
 */
@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());
}

实现的接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 获取实现的接口信息
 *
 * @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());

}

构造函数,方法,字段

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 构造函数,方法,字段
 */
@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")));
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**                                                                                   
 * 获取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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 通过获取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());                                                         
}                                                                                                      
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java Reflection使用指南-Java快速入门教程
在本教程中,将探索 Java 反射,它允许检索类、接口、字段和方法的运行时属性。当在编译时不知道它们的名字时,这尤其有用。
jack.yang
2025/04/05
1060
接口自动化框架脚手架-利用反射机制实现接口统一发起端
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。
互联网金融打杂
2022/08/01
2620
接口自动化框架脚手架-利用反射机制实现接口统一发起端
Java基础巩固——反射
什么是反射 ----    反射机制就是指程序运行时能够获取自身的信息。在Java中,只要给出类的名字,就可以通过反射机制来获取类的信息 哪里用的到反射机制 ----    在jdbc中就是使用的反射来实例化对象,比如:Class.forName("com.mysql.jdbc.Driver.class").newInstance();    框架都用到反射机制,spring,hibernate、struts都是用反射机制实现的。 反射机制的优点和缺点 ----   为什么要用反射机制?直接创建对象不就可以
Janti
2018/04/10
5540
Java重要知识点(继承、多态、接口,异常,工具,测试)
当父类,和子类有Static时,先初始化Static,再初始化子类的Static,再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
小爷毛毛_卓寿杰
2019/02/13
6780
Java重要知识点(继承、多态、接口,异常,工具,测试)
java 反射机制说的透彻一点
很多时候我们会遇到别人问一个问题:你给我讲一下反射,到底是什么东西?怎么实现的?我们能用反射来做什么?它有什么优缺点?下面我们会围绕着这几个问题展开:
秦怀杂货店
2020/11/22
7040
java 反射机制说的透彻一点
每天一小步:如何给Lombok Builder提供默认值
在这个教程中,我们将研究如何基于Lombok在实现 Builder模式时为属性提供默认值。
烟雨平生
2023/03/07
2.7K0
每天一小步:如何给Lombok Builder提供默认值
Java 反射机制
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/details/18777099
亦山
2019/05/25
5830
Java反射实战
  最近的项目中需要使用到Java 反射的知识,以前不怎么了解,也基本没怎么用过,抽出一片时间,来具体学习和实战下Java的反射!拿来和大家分享以及记录方便以后学习!
阿豪聊干货
2018/08/09
9350
Java Web_基础加强
反射 反射:框架设计的灵魂 * 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码 * 反射:将类的各个组成部分封装为其他对象,这就是反射机制 * 好处: 1. 可以在程序运行过程中,操作这些对象。 2. 可以解耦,提高程序的可扩展性。
全栈程序员站长
2021/05/20
6100
Java重点基础:反射机制
Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。
一个程序员的成长
2020/11/25
2940
Java重点基础:反射机制
java cloneable 用途_java中cloneable的使用「建议收藏」
浅克隆:克隆对象中的变量与之前对象的值相同,并且对象中的引用类型变量仍然指向原来对象引用类型变量的地址.
全栈程序员站长
2022/11/19
5170
Java反射(一)
1.简介  反射API可以获取程序在运行时刻的内部结构,反射API提供的动态代理是非常强大的功能,可以原生的实现AOP中的方法拦截功能,反射API就好像在看一个Java类在水中的倒影,知道Java类的内部结构,就可以和它们进行交互,包括创建对象,调用对象的方法,与直接在源代码中的交互是一样的,但又提供了额外的在运行时候的灵活性,但反射的一个最大的弊端就是性能比较差,相同的操作,用反射API所需的时间大概比直接使用慢一两个数量级,不过现在的JVM实现中,java反射的性能有很大的提升,在灵活和性能中需权衡 2
Java学习123
2018/05/16
5730
Java基础——反射
基本的数据类型,乃至于void关键字,都存在其对应的类类型(class type)
阿珍
2024/11/25
1010
Java基础——反射
Java特性组合的通用方案
一些框架的特性组合,以及开发中业务的某个字段是多个特征组合,如果直接用数字,组合较多保存非常复杂。
明明如月学长
2021/08/31
4250
Java特性组合的通用方案
Java---类反射(1)---类反射入门和基础
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
谙忆
2021/01/21
5590
Java---类反射(1)---类反射入门和基础
java学习与应用(3.6.1)--测试、反射、注解
Junit单元测试:黑盒测试(不关注内部逻辑,只关注输入输出),白盒测试(关注执行流程,需要些代码)。 测试类使用对应定义的测试类(测试用例,类名为XxxTest,包名为xxx.xxx.test等),方法名为testXxx,返回值void,参数列表为空,@Test注解使得独立运行(测试)。需要导入Junit依赖。 然后通过编译器调用测试类中的测试方法即可。测试通过为绿色(编译成功)。 断言类Assert,包含方法assertEquals方法,定义期望的值为指定值,用于判断运算是否成功。 定义好:init方法,初始化,用于资源申请,添加@Before方法。close方法,结束后执行,用于释放资源,使用@After(抛出异常仍然会执行)。
嘘、小点声
2020/02/18
4250
java学习与应用(3.6.1)--测试、反射、注解
020.Java的反射机制
JAVA反射机制是在运行状态中, 对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意方法和属性; 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
qubianzhong
2018/11/21
3740
学过框架的必看—Java反射
反射作为 Java 的高级特性,很多框架中都用到了反射的知识,如 Spring,Hibernate等,通过配置就可以动态干预程序的运行,那么什么是反射呢?
Wizey
2018/09/29
4460
反射基础之Class
Java中每个类型要么是引用类型,要么是原生类型。类,枚举,数组(他们都继承于java.lang.Object)和接口都是引用类型。例如:java.lang.String,所有原生类型的包装类java.lang.Double,接口java.io.Serializable和枚举javax.swing.Sortorder,都是引用类型。原生类型的数量是固定的:boolean,byte,short,int,long,char,float,double。 对于每个对象类型,JVM都会为其初始化一个java.lang.Class的实例,可以检查包括属性和方法在内的对象运行时的属性。Class同样也可以创建一个新的类和对象。最重要的是,他是所有反射API的入口。
代码拾遗
2018/07/24
5630
Mocktio 使用(下)
thenReturn 用来指定特定函数和参数调用的返回值。thenReturn 中可以指定多个返回值,在调用时返回值依次出现。若调用次数超过返回值的数量,再次调用时返回最后一个返回值。
HLee
2021/10/11
3.6K0
Mocktio 使用(下)
相关推荐
Java Reflection使用指南-Java快速入门教程
更多 >
LV.1
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验