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 编写测试方法

/**
 * 一个小案例,从配置文件读取class和method,实现方法的执行
 */
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");
    }
}

打印结果:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我来回答你的问题。 首先,我们需要定义一个一个: ```java public class ParentClass { private String privateField; public String publicField; public ParentClass() { this.privateField = "privateField"; this.publicField = "publicField"; } private void privateMethod() { System.out.println("This is a private method in ParentClass"); } public void publicMethod() { System.out.println("This is a public method in ParentClass"); } } public class ChildClass extends ParentClass implements MyInterface { private String childField; public ChildClass() { super(); this.childField = "childField"; } private void childMethod() { System.out.println("This is a private method in ChildClass"); } public void myMethod() { System.out.println("This is a method in MyInterface implemented by ChildClass"); } } ``` 然后,我们可以使用反射获取的属性和方法,并调用它们: ```java public class ReflectionDemo { public static void main(String[] args) throws Exception { // 获取的Class对象 Class childClass = ChildClass.class; // 获取的私有属性 Field privateField = childClass.getSuperclass().getDeclaredField("privateField"); privateField.setAccessible(true); System.out.println("ParentClass's privateField value: " + privateField.get(new ChildClass())); // 获取的公有属性 Field publicField = childClass.getSuperclass().getField("publicField"); System.out.println("ParentClass's publicField value: " + publicField.get(new ChildClass())); // 调用父的私有方法 Method privateMethod = childClass.getSuperclass().getDeclaredMethod("privateMethod"); privateMethod.setAccessible(true); privateMethod.invoke(new ChildClass()); // 调用父的公有方法 Method publicMethod = childClass.getSuperclass().getMethod("publicMethod"); publicMethod.invoke(new ChildClass()); // 获取的私有属性 Field childField = childClass.getDeclaredField("childField"); childField.setAccessible(true); System.out.println("ChildClass's childField value: " + childField.get(new ChildClass())); // 调用子的私有方法 Method childMethod = childClass.getDeclaredMethod("childMethod"); childMethod.setAccessible(true); childMethod.invoke(new ChildClass()); // 调用实现接口的方法 Method myMethod = childClass.getMethod("myMethod"); myMethod.invoke(new ChildClass()); } } ``` 最后,我们需要实现一个接口: ```java public interface MyInterface { void myMethod(); } ``` 上面的代码演示了如何使用反射获取继承的属性和方法,并调用它们,以及如何实现接口的方法。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值