初识反射

初识反射(java.lang.reflect)

什么是反射?

class是一切反射的根源,JAVA反射机制是在运行状态中,对于任和一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

反射的原理

在程序运行的时候获取到想要创造实例的类的信息,使用Class类来创建一个对应的实例。避免了使用new关键字,达到在程序运行时动态创建实例的效果。

反射提供的以下几个类,可在类中查询具体的方法

java.lang.Class;

java.lang.reflect.Constructor;

java.lang.reflect.Field;

java.lang.reflect.Method;

java.lang.reflect.Modifier;

如何实现反射

1、获得类的信息(获得到的是类的全路径信息)

获得类的信息有三种方式:

1.使用class类的forName()方法获取类的信息(比较推荐)
2.使用对象实例的getclass()方法获得类的信息
3.使用类名.class获得类的信息
Demo:

/*三种获得反射对象的方法*/
        //第一种 Class.forName("全限定类名")
        Class class1 = class1 = Class.forName("com.test.entity.One");
        //第二种类名.class
        Class class2 = One.class;
        //第三种对象.getclass
        One one = new One();
        Class class3 = one.getClass();
		System.out.println(class1);
        System.out.println(class2);
        System.out.println(class3);
//运行结果
class com.test.entity.One
class com.test.entity.One
class com.test.entity.One

当程序运行,第一次加载类时,先将硬盘上.class文件加载内存中,这时类加载器和JVM会根据.class文件生成.class对象,这个对象叫反射对象.一个类只有一 个反射对象.

 //类的反射对象只有一个,因为当前类的class字节码文件只有一个
        System.out.println(class1 == class2);
        System.out.println(class2 == class3);
        System.out.println(class1 == class3);

//运行结果
true
true
true

2、使用反射对象获得实例对象

		//使用反射对现象获得类的实例对象
		//无参构造创建实例对象
        One one1 = (One) class1.newInstance();
         //有参构造创建实例对象
        Constructor constructor = class1.getConstructor(String.class,int.class);
        One one2 = (One) constructor.newInstance("张三",20);
        System.out.println(one2);
 //有参构造方法创建实体类运行结果
 One{name='张三', age=20}

3、使用反射对象获得类的属性(Field)

 		//使用反射对象获得类的私有属性
        Field field2 = class1.getDeclaredField("name");
        //给属性设置允许访问私有
        field2.setAccessible(true);
        //给属性设置值,第一个参数是要给哪个实例对象设置当前属性的值
        field2.set(one1,"张无忌");
         //查看设置结果
        System.out.println(one1);
//运行结果
One{name='张无忌', age=0}

也可以一次性获得所有属性的数组

//获得所有私有属性
        Field[] field = class1.getDeclaredFields();
        for (Field field1 : field) {
            System.out.println("属性名称"+field1.getName()+"属性类型"+field1.getType());
            }
//运行输出结果
属性名称name属性类型class java.lang.String
属性名称age属性类型int
属性名称father属性类型class java.lang.String

获得公有属性

		 //获得公有属性
        Field field3 = class1.getField("father");
        field3.set(one,"张三丰");
        //查看设置结果
        System.out.println(field3.get(one));
//运行输出结果
张三丰

4、使用反射对象获得类的方法(Method)

/*使用反射对象获得方法*/
        //获得私有方法
        //第一个参数为方法名,第二个参数开始是参数类型,如果有多个参数,按顺序写入
        Method method = class1.getDeclaredMethod("show1");
        method.setAccessible(true);//设置允许访问私有
		//参数含义是调用哪个实例对象的当前方法
		method.invoke(one2);

调用有参方法

//获得私有有参方法
        Method method1 = class1.getDeclaredMethod("show2",String.class);
        method1.setAccessible(true);
        //调用方法,将参数填入,如果多个参数则按顺序填入
         method1.invoke(one2,"帅哥");

获得公有方法

		 //获得公有方法 无需设置访问权限
        Method method2 = class1.getMethod("show3");
        method2.invoke(one);

反射的用法举例

在这个demo中我有两个类,两个类中各有一个方法
此时如果项目中我是用的是XXX这个类的方法,但是由于业务需求需要更换成XXXX中的方法,如果使用常规方法,此时你可能需要修改代码,然后重新编译运行,才能达到效果

package com.test.entity;

public class XXX {
    public void X(){
        System.out.println("这是XXX的方法");
    }
}

package com.test.entity;

public class XXXX {
    public void X(){
        System.out.println("这是XXXX的方法");
    }
}

public static void main(String[] args){
 // XXX xxx = new XXX;
        // xxx.X();
        //重新修改代码
        XXXX xxxx = new XXXX();
        xxxx.X();
        }

但是如果使用反射,则会方便快捷许多

首先准备一个properties配置文件,里面写上两个属性,一个是类名,一个是方法名

classname=com.test.entity.XXXX
methodname=X

然后在测试类中这样写

package com.test.test;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        File configfile = new File("D:\\IDEACode\\yanjiang\\src\\com\\test\\config\\configfile.properties");
        Properties properties = new Properties();
        //加载配置文件
        properties.load(new FileInputStream(configfile));
        //读取配置文件信息
        String classname = properties.getProperty("classname");
        String methodname = properties.getProperty("methodname");
        //获得反射对象
        Class clazz = Class.forName(classname);
        //使用反射对象获得方法
        Method method = clazz.getDeclaredMethod(methodname);
        Constructor constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();
        method.invoke(obj);


    }
}
//运行结果
这是XXXX的方法

此时我们如果要更换类和方法只需要在配置文件中更改即可,无需重新new对象

其他常用方法

方法含义
getDeclaredMethods()/getMethods获取本类所有的方法(包括私有方法)/获取所有的方法(包括父类的方法)
getReturnType()获得方法的返回值类型
getParameterTypes()获得方法的传入参数类型
getDeclaredMethod(“方法名”,参数类型.class,……)获得特定的方法
构造方法关键字
getDeclaredConstructors()获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)获取特定的构造方法
父类和父接口
getSuperclass()获取当前类的父类
getInterfaces()获取其类实现的接口

PS:反射使用不当会造成很高的成本!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值