Java反射技术

1、什么是反射?

Java的反射(reflection)机制是在运行状态中,对任意一个类,都能知道这个类的所有属性和方法。

2、反射的使用

反射的使用简单来说就是几个步骤:
1、获取字节码文件对象
2、获取构造器对象
3、通过构造器实例化对象
4、反射属性和方法

本文的代码都是反射笔者自己实现的Student类中的属性和方法:

public class Student {
    private String name;
    private String gender;
    private int age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }

    public String getGender(){
        return gender;
    }
    public Student(String name, String gender, int age){
        this.name=name;
        this.gender=gender;
        this.age=age;
    }
    public Student(){}

    private Student(String name){
        this.name=name;
    }

    public void setAge(int age){
        this.age=age;
    }
    private int getAge(){
        return age;
    }
}

2.1获取字节码文件对象

.java源文件在编译后形成.class的字节码文件,然后通过双亲委派模式被类加载器加载之后形成字节码文件对象
字节码文件对象(Class对象)是Java反射的基石,想要进行反射的相关操作,必须要先获得字节码文件对象
       
Class对象:在Java中,一切皆对象,当字节码文件加载到JVM后,会形成一个Class类对象

获取字节码文件对象的方法有三种:
1、使用.class方法
2、使用对象的getClass()方法
3、使用Class.forName(“类的全路径名”)静态方法

 public static void test1() throws ClassNotFoundException {
        //1、每个类中有一个class静态属性
        Class<?> stuClass1=Student.class;
        System.out.println(stuClass1);
        
        //2、通过对象调用getClass()
        Student stu=new Student("lwl","男",12);
        Class<?> stuClass2=stu.getClass();
        System.out.println(stuClass2);
        
        //3、通过Class静态方法forName()
        Class<?> stuClass3=Class.forName("Student");//如果找不到类会抛异常,我们直接往出抛
        System.out.println(stuClass3);

        //三个stuClass是相同的,即:一个类最多会加载一次
        System.out.println(stuClass1==stuClass2);
        System.out.println(stuClass2==stuClass3);
    }

2.2获取构造器对象

在这里插入图片描述
注意:方法名中有s表示获取所有构造器对象,带Declared表示获取声明的构造器对象,未带Declared时只能获取公有的构造器对象

    public static void test2(){
        try {
            Class<?> stuClass=Class.forName("Student");

            //获取构造器对象
            Constructor<?> con=stuClass.getConstructor();//获取公有无参构造
            System.out.println(con);
            获取公有含参构造
            Constructor<?> con1=stuClass.getConstructor(String.class,String.class,int.class);
            System.out.println(con1);
            //获取所有构造
            Constructor<?>[] con2=stuClass.getDeclaredConstructors();
            System.out.println(con2.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

2.3通过构造器实例化对象

//3、通过构造器实例化对象
    public static void test3(){
        try {
            Class<?> stu=Class.forName("Student");
            Constructor<?> con=stu.getDeclaredConstructor(String.class);
            //如果构造器是私有的,不能直接用来实例化对象
            con.setAccessible(true);//将构造器访问权限设置为公有的
            // 调用newInstance实例化对象
            Student s=(Student)con.newInstance("jack");
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

2.4反射属性和方法

 public static void test5(){
        try {
            Class<?> stu=Class.forName("Student");
            Constructor<?> con=stu.getDeclaredConstructor(String.class);

            //如果构造器是私有的,不能直接用来实例化对象
            con.setAccessible(true);//将构造器访问权限设置为公有的
            Student s=(Student)con.newInstance("jack");

            Field gender=stu.getDeclaredField("gender");
            System.out.println(gender);//私有属性

            //反射属性
            //修改gender属性-->修改哪个实例的属性:s
            gender.setAccessible(true);
            gender.set(s,"人妖");
            System.out.println(s.getGender());
            System.out.println(s);

            Field age=stu.getDeclaredField("age");
            age.setAccessible(true);
            age.set(s,99);//set第一个参数是对象
            System.out.println(s);

            //反射方法
            Method setAge=stu.getDeclaredMethod("setAge",int.class);
            setAge.invoke(s,200);
            Method getAge=stu.getDeclaredMethod("getAge");
            getAge.setAccessible(true);
            System.out.println(getAge.invoke(s));
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

3、反射的优缺点

优点:
1、对于任意一个类,都可以知道该类的所有属性和方法
2、增加了程序的灵活性和扩展性
缺点:
1、使用反射会使程序的效率降低
2、反射绕过了源代码,会带来维护问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在向学生讲解Class.forName()方法的使用时,有时需要扩展讲解为什么这样书写的原理,于是,扩展讲解Java反射技术可以查看被监视类的方法(构造方法和普通方法)、公有属性的功能,以达到封闭功能的效果。该例子使用MyEclipse 5.5完成demo示例。其中,com.jb.arklis.app.DemoApplication类利用反射技术可以观察任何非静态类(比如java.lang.String, javax.swing.JFrame等类和自定义的类,比如com.jb.arklis.dao.BaseDAO)的普通方法、构造方法以公有属性,是一个非常有实用意义的显示类。 该示例没有使用泛型技术,所以不是很完美。不过只要你稍微修改一下,就可作为自己工程中比较好的封装工具类使用! 下载解压之后,使用MyEclipse 5.5导入,打开该工程,找到DemoApplication类,然后点击run菜单-->找到(x)Arguments,然后在Program arguments中输入: com.jb.arklis.dao.BaseDAO, 然后点击run按钮,如果一切正常,那么你会看到使用反射在DemoApplication类中呼叫了BaseDAO的returnTestValue(String name)方法。 我的代码注释非常详细,相信当你看完之后,一般来说,如果不是新手(非常菜的人),那么你应该学会使用反射技术来实现封装的动作了--也就是说,你的技术有了一个非常大的提高--如果你看完之后,参见该示例中另外的JDBC代码,然后能够实现对JDBC进一步的封装,使JDBC连接的使用步骤更简单的话! OK,Good luck!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值