JAVA进阶学习-反射机制

我自己搭建了个人主页,博客会先在这里更新哦!点这里–>我的个人主页

JAVA 反射机制

       Java Reflaction in Action中有这么一句话,反射是运行中的程序检查自己和软件运行环境的能力,它可以根据它发现的进行改变。通俗的讲就是反射可以在运行时根据指定的类名获得类的信息。

       平时开发中我们实例化一个类的过程一般是这样的:引入需要的“包类”的名称–>通过new实例化–>取得实例化对象

       而JAVA得反射机制允许我们将这个过程反过来:实例化对象–>getClass()方法–>得到完整的“包类”名称

JAVA反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

反射机制的使用

       我们通过一个简单的例子来说明反射机制的使用:

       创建一个Creature类,如下:

public class Creature<T> {

    public double weight;
    public void breath(){
        System.out.println("呼吸!");
    }

}

       创建一个Person类继承Creature类,为了让该类复杂一点,我们实现Comparable接口,声明一些简单的属性和方法,如下:

public class Person extends Creature<String> implements Comparable {

    public String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Person() {
        super();
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public Person(int age) {
        super();
        this.age = age;
    }

    public void show() {
        System.out.println("我是一个人");
    }

    public void display(String nation) {
        System.out.println("我来自:" + nation);
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int compareTo(Object o) {

        return 0;
    }

}

       在Java中java.lang.Class是反射的源头,我们创建了一个类,通过编译(javac.exe),生成对应的.class文件,之后使用JVM的类加载器加载此.class文件,此.class文件加载到内存之后,就是一个运行时类,会被存放在缓存区,那么这个运行时类本身就是一个Class的实例!

       如果类的实现没有发生改变,那么该类的.class文件只会被生成和加载一次,并且一个类在JVM中只会有一个Class实例。

       我们创建一个测试类TestReflection来使用JAVA反射机制中的常用方法。

获取Class的实例

@Test
public void test() throws ClassNotFoundException {

        // 1.调用运行时类本身的.class属性
        Class myClass = Person.class;
        System.out.println(myClass.getName());

        // 2.通过运行时类的对象获取
        Person p = new Person();
        Class myClass1 = p.getClass();
        System.out.println(myClass1.getName());

        // 3.通过Class的静态方法获取
        Class myClass2 = Class.forName("test.Person");
        System.out.println(myClass2.getName());

        // 4.通过类的加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class myClass3 = classLoader.loadClass("test.Person");
        System.out.println(myClass3.getName());


    }

       四条输出语句输出的结果都是test.Person(包名.类名),这四种方法在使用上并没有优劣之分。

创建运行时类的对象

@Test
    public void test4() throws ClassNotFoundException, InstantiationException, IllegalAccessException{


        String className = "test.Person";
        Class myClass = Class.forName(className);
        Person p = (Person) myClass.newInstance();//调用无参的构造方法
        p.setAge(10);
        p.setName("Tom");
        System.out.println(p);


    }

       输出:

Person [name=Tom, age=10]

获取运行时类的属性

@Test
    public void test5(){

        Class myClass = Person.class;
        //1.获取对应的运行时类的属性
        //(1)getFields()只能获取到运行时类中及其父类中声明为public的属性
        Field[] fields = myClass.getFields();
        for(Field f : fields){
            System.out.println(f);
        }

        System.out.println();

        //(2)getDeclaredFields() 获取运行时类本身声明的所有属性
        Field[] fields1 = myClass.getDeclaredFields();
        for(Field f : fields1){
            System.out.println(f);
        }

        System.out.println();

        //2.获取属性的各个部分的内容
        Field[] fields2 = myClass.getDeclaredFields();
        for(Field f : fields2){
            //变量名
            System.out.print("属性名:"+f.getName());
            //权限修饰符
            int i = f.getModifiers();
            String modifer = Modifier.toString(i);
            System.out.print(" 权限修饰符:"+modifer);
            //变量类型
            System.out.print(" 属性类型:"+f.getType());


            System.out.println();
        }

    }

       输出:

public java.lang.String test.Person.name

public double test.Creature.weight

public java.lang.String test.Person.name

private int test.Person.age

属性名:name 权限修饰符:public 属性类型:class java.lang.String

属性名:age 权限修饰符:private 属性类型:int

获取父类和接口

@Test
    public void test6(){

        Class myClass = Person.class;
        Class parentClass = myClass.getSuperclass();
        System.out.println("Person的父类是:"+parentClass.getName());

        Class inters[] = myClass.getInterfaces();
        System.out.print("Person 实现的接口:");
        for(Class c : inters){
            System.out.println(c.getName());
        }

    }

       输出:

Person的父类是:test.Creature

Person 实现的接口:java.lang.Comparable

调用运行时类的指定方法

@Test
    public void test7() throws Exception{

        Class myClass = Person.class;

        // 1.创建myClass对应的运行时类Person的对象
        Person p = (Person) myClass.newInstance();

        // 2.通过反射调用运行时类的属性
        // public
        Field f1 = myClass.getField("name");
        f1.set(p, "Tom");

        // 非public
        Field f2 = myClass.getDeclaredField("age");
        f2.setAccessible(true);
        f2.set(p, 10);

        // 3.通过反射调用运行时类的指定方法
        Method m1 = myClass.getMethod("show");
        m1.invoke(p);
        Method m2 = myClass.getMethod("display", String.class);
        m2.invoke(p, "US");

        System.out.println(p);

    }

       输出:

我是一个人

我来自:US

Person [name=Tom, age=10]

动态代理

       在JAVA中要实现动态代理就要用到反射机制的特性,代码如下:

//业务接口
interface Subject {
    void action();
}

// 业务接口实现类
class RealSubject implements Subject {

    public void action() {
        System.out.println("我是被代理类");
    }

}

// 动态的代理类
class MyInvocationHandler implements InvocationHandler {

    Object obj;

    // 给被代理类的对象实例化,返回一个代理类的对象
    public Object blind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    obj.getClass().getInterfaces(), this);
    }

    // 当通过代理类的对象发起对被重写的方法的调用时,都会转化为对如下的invoke方法的调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object returnVal = method.invoke(obj, args);
        return returnVal;
    }

}

public class TestProxy {

    public static void main(String[] args) {

        // 被代理对象
        RealSubject real = new RealSubject();
        // 创建一个实现了InvocationHandler接口的对象
        MyInvocationHandler handler = new MyInvocationHandler();
        // 调用blind方法,动态的返回一个同样实现了real所在类实现的接口的代理类的对象
        Object obj = handler.blind(real);
        Subject sub = (Subject) obj;// 此时sub就是代理类对象
        sub.action();// 调用的是MyInvocationHandler类的invoke方法

    }

}

笔者水平有限,若有错漏,欢迎指正,如果转载以及CV操作,请务必注明出处,谢谢!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值