栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java反射的学习,并实现一个小案例:从配置文件获取类和方法,并执行方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java反射的学习,并实现一个小案例:从配置文件获取类和方法,并执行方法

从B站上学习了java反射的相关知识,做个笔记记录一下,基础概念不再赘述,只记录一些重点

一、获取Class对象的方式 1、获取Class对象的三种方式对应着java代码在计算机中的三个阶段

(1)【Source源代码阶段】 Class.forName("全类名"):将字节码文件加载进内存,返回Class对象 。多用于配置文件,将类名定义在配置文件中。读取文件,加载类。

(2)【Class类对象阶段】 类名.class:通过类名的属性class获取。 多用于参数的传递

(3)【Runtime运行时阶段】对象.getClass():getClass()方法是定义在Objec类中的方法 。 多用于对象的获取字节码的方式

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。

2、测试三种获取方法
@Test
public void reflect1() throws ClassNotFoundException {
    //方式一:Class.forName("全类名");
    Class cls1 = Class.forName("com.test.domain.User");   //自定义实体类
    System.out.println("cls1 = " + cls1);

    //方式二:类名.class
    Class cls2 = User.class;
    System.out.println("cls2 = " + cls2);

    //方式三:对象.getClass();
    User user= new User();        
    Class cls3 = user.getClass();
    System.out.println("cls3 = " + cls3);

    // == 比较三个对象
    System.out.println("cls1 == cls2 : " + (cls1 == cls2));    //true
    System.out.println("cls1 == cls3 : " + (cls1 == cls3));    //true
    //结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。
}
 二、Class对象功能 1、获取功能,只列举一些常用的 1、获取成员变量

Field[] getFields() :获取所有public修饰的成员变量

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getDeclaredField(String name)

2、获取成员方法 

Method[] getMethods()

Method getMethod(String name, 类... parameterTypes)

Method[] getDeclaredMethods()

Method getDeclaredMethod(String name, 类... parameterTypes)  

3、获取构造方法 

Constructor[] getConstructors()

Constructor getConstructor(类... parameterTypes)

Constructor[] getDeclaredConstructors()

Constructor getDeclaredConstructor(类... parameterTypes)

4、获取全类名

String getName()

 2、Field,成员变量
  • (1)设置值 void set(Object obj, Object value)
  • (2)获取值 get(Object obj)
  • (3)忽略访问权限修饰符的安全检查 setAccessible(true):暴力反射

注意:操作private修饰的变量,需要添加下面代码,否则set和get会报错

代码示例:公共代码User类

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
    public String name;
    private String sex;
    private int age;
    public String desc;
    
    public void eat(){
        System.out.println("eat...");
    }
    
    public void eat(String food){
        System.out.println("eat"+food);
    }
}
 2.1 获取类的成员变量
public void test01() throws Exception{
    Class clazz = Class.forName("com.ang.reflection.domain.User");

    //获取到public的字段
    Field[] fieldsPublic = clazz.getFields();
    Arrays.stream(fieldsPublic).forEach(f->{
        System.out.println(f);
    });

    //获取指定的public字段
    Field fieldPublic = clazz.getField("name");
    System.out.println("-----------------------------");
    System.out.println(fieldPublic);

    //获取所有的任意修饰符的字段
    Field[] fieldAll = clazz.getDeclaredFields();
    System.out.println("-----------------------------");
    Arrays.stream(fieldAll).forEach(f->{
        System.out.println(f.toString());
    });

    //获取指定的任意修饰符的字段
    Field fieldAny = clazz.getDeclaredField("age");
    System.out.println("-----------------------------");
    System.out.println(fieldAny);
}

打印结果: 

2.2 操作类的成员变量
public void test02() throws Exception {
    User user = getUser();
    Class clazz = User.class;

    //获取user对象中name的值
    Field name = clazz.getDeclaredField("sex");

    //sex是私有变量,直接get/set会报错,需要下面一行代码
    name.setAccessible(false);

    //get
    Object value1 = name.get(user);
    System.out.println(value1.toString());
    //set
    name.set(user,"女");
    System.out.println(user.getName());
}

 打印结果:

3、Constructor,构造方法

创建对象:T newInstance(Object... initargs)

注意:如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

3.1 无参构造
public void test01() throws Exception {
    Class clazz = Class.forName("com.ang.reflection.domain.User");

    //获取无参构造
    Constructor constructor = clazz.getConstructor();
    System.out.println(constructor);
    System.out.println("---------------------");

    //使用无参构造创建对象
    Object user = constructor.newInstance();
    System.out.println(user);

    //也可以直接使用反射的对象来创建实例
    Object user1 = clazz.newInstance();
    System.out.println(user1);
}

 打印结果:

 3.2 有参构造
public void test02() throws Exception{
    Class clazz = Class.forName("com.ang.reflection.domain.User");

    Constructor[] constructors = clazz.getConstructors();
    Arrays.stream(constructors).forEach(c->{
        System.out.println(c);
    });

    System.out.println("------------------------");

    //获取有参构造方法
    Constructor constructor = clazz.getConstructor(String.class,String.class,int.class,String.class);
    System.out.println(constructor);

    //构造对象
    Object user = constructor.newInstance("李四","男",20,"喜欢打游戏");
    System.out.println(user);
}

打印结果:

3.3 对于getDeclaredConstructor方法和getDeclaredConstructors方法

对于多出个Declared关键词的两个方法,与不带这个词的两个方法的对比。与之前3.2叙述的一样,getDeclaredConstructor方法可以获取到任何访问权限的构造器,而getConstructor方法只能获取public修饰的构造器。具体不再测试。此外在构造器的对象内也有setAccessible(true);方法,并设置成true就可以操作了。

4、Method,成员方法 
  • 执行方法:Object invoke(Object obj, Object... args)
  • 获取方法名称:String getName();
 4.1 获取所有public成员方法
public void test01() throws Exception {
    Class clazz = Class.forName("com.ang.reflection.domain.User");

    Method[] methods = clazz.getMethods();
    Arrays.stream(methods).forEach(m->{
        System.out.println(m);
        System.out.println(m.getName());
        System.out.println("--------------------------");
    });
}
4.2 无参方法 
public void test02() throws Exception{
    Class clazz = Class.forName("com.ang.reflection.domain.User");
    Object user = new User();

    Method method = clazz.getMethod("eat");
    method.invoke(user);
}

打印结果: 

4.3 有参方法 
public void test03() throws Exception{
    Class clazz = Class.forName("com.ang.reflection.domain.User");
    Object user = new User();

    Method method = clazz.getMethod("eat", String.class);
    method.invoke(user, " Apple");
}

打印结果:

三、小案例

实现一个功能,从配置文件中,根据配置的不同类名和方法名,通过反射来运行类中的方法 

 1、步骤

(1)将需要创建的对象的全类名和需要执行的方法定义在配置文件中

(2)在程序中加载读取配置文件

(3)使用反射技术来加载类文件进内存

(4)创建对象

(5)执行方法

 2、代码实现 2.1 实体类User,可以有其他的类
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
    public String name;
    private String sex;
    private int age;
    public String desc;

    public void eat(){
        System.out.println("eat...");
    }
    public void eat(String food){
        System.out.println("eat"+food);
    }
}
2.2 配置文件:reflection.properties,可以配置其他的类和方法 
className = com.ang.reflection.domain.User
methodName = eat
2.3 编写测试方法
public class DemoTest {
    public static void main(String[] args) throws Exception{
        //获取类加载器
        ClassLoader classLoader = DemoTest.class.getClassLoader();
        //加载文件
        InputStream is = classLoader.getResourceAsStream("reflection.properties");
        //获取值
        Properties properties = new Properties();
        properties.load(is);

        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        //反射获取class
        Class clazz = Class.forName(className);
        //反射获取实例
        Object object = clazz.newInstance();
        //反射获取无参方法
        Method method1 = clazz.getDeclaredMethod(methodName);
        method1.invoke(object);

        //反射获取有参方法
        Method method2 = clazz.getDeclaredMethod(methodName, String.class);
        method2.invoke(object, " orange");
    }
}

打印结果:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/885268.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号