JAVA的反射,--框架的承前启后

java的反射是属于javase的部分,但是建议是在对javaweb学习的时候再学习一下反射。

反射也可以叫做反射机制。是一种机制,只要获得类的Class对象,它就可以动态的获得这个类里面的信息,获取到后就可以创建对象,就可以对这个对象中的属性和方法进行调用


反射

在之前的时候,我们是如何创建使用对象的?
1、设计类(这种就是在哪用就在那new出一个对象来用)
类只是一个感念,里面会定义一些抽象的属性
在用的时候我们就要new一个构造方法(构造方法的名字是和类的名字一样的)

2、IO的反序列化
将对象通过输出流输出到一个文件当中,再把文件中的信息读入进来,于是在内存中就还原出现了一个对象。

3、加载MySQL的驱动时,本质上就是创建出了一个Driver类的这么一个对象
Class.forName(com.mysql.cj.jdbc.Driver);

4、在javaweb中将servlet配置到web.xml文件Tomcar启动时,就会读取配置,然后就会创建出了一个servlet对象(这其实就是反射机制)。

<sevlet-class>com.demo.demoweb.servlet.DemoServlet</servlet-class>

但是现在就是有了一个实际问题,如果我们事先还没有这么一个类,但是现在就要体现调用出这么一个类的对象存在(就比如上面的web和MySQL配置,在服务器运行的时候就会对这个配置的信息进行读取,根据这个类的地址,去反向找到类的字节码文件的地址,然后动态的去创建类的对象)

什么是反射?

反射就是在仅仅知道一个类的类名,动态的得到类的定义信息,包括这个得到类的方法和属性。

Java反射的感念
java反射机制就是在运行的状态中,对于任意一个类,仅仅在只通过类的地址就能够知道这个类的所有属性和方法;
还可以通过此类的对象,能够调用它的任意一个方法和属性;
这种动态获取信息以及动态调用对象的方法的功能我们就称为java的反射机制。

反射的厉害之处就在于,只用写一套代码,就可以获得任意类的信息,并为其创建出对象。

java反射的作用
动态获取类的信息,进一步实现需要的功能。

怎么实现反射机制?

java反射的相关API

java反射相关的类主要就是包括以下这四个类:
● Class 类型
● Constructor 构造方法
● Method 方法
● Field 属性
▲ 除了Class外,其他的类都是位于java.long.reflect包中

就由此可以看出,从反射的API不难看出,是将类的类型,方法,属性都封装成了类,其中最重要的类就是Class类,可以说,一切的反射都是从Class开始的。

在API中主要有以下几点:
1、获得构造方法。
2、获得属性。
3、获得父类、接口。
4、获得注解标签。

Class类

Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释是一种界面。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。
——来自jdk1.8的api(机译)
可以理解为Class类的对象表示正在运行的Java应用程序中的类和接口

请添加图片描述

一旦Class文件被加载到内存中,就会为其创建一个Class对象,任何类被使用的时候都会创建一个Class对象的。

Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。

如何获得一个类的Class对象?

获得方式有三种:
1、类名.class
2、对象名.getClass()
3、Class.forName(“类的地址”)(这里也发生了类加载)

package com.demo.reflect;

public class Car {
    public String name;
    private String color;

    public Car() {
        System.out.println("这是一个无参构造");
    }

    public Car(String name, String color) {
        System.out.println("这是一个有参构造");
        this.name = name;
        this.color = color;
    }

    public void run() {
        System.out.println("车能跑");
    }

    public void run(int speed) {
        System.out.println("车跑的速度是" + speed);
    }
}

package com.demo.reflect;

public class Test1 {
    public static void main(String[] args) {
        //反射机制是在运行时获得类的信息,并创建出对象
        //前提是要获得类对应的Class对象。
        //获得方式一:
        Class car1 = Car.class;
        System.out.println(car1);
        System.out.println("-------------------");

        //方式二:      public final native(调用的是本地方法 C++) Class<?> getClass();
        Class car2 = new Car().getClass();//getClass指的是Car对象对应的Class类的对象
        System.out.println(car2);
        System.out.println(car1 == car2);//true  获得的是同一个类的Class对象
        System.out.println("-------------------");

        //方式三:      经常使用的
        String classpath = "com.demo.reflect.Car";
        try {
            Class car3 = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
            //需要抛出一个异常
            System.out.println(car3);
        } catch (ClassNotFoundException e) {    //类找不到异常
            e.printStackTrace();
        }
    }
}

在这里插入图片描述方式三是一种动态获取的方式,所以在动态的创建一个此类的对象

package com.demo.reflect;

public class Test1 {
    public static void main(String[] args) {
        //反射机制是在运行时获得类的信息,并创建出对象
        //前提是要获得类对应的Class对象。

        //方式三:    动态获取,动态操作
        String classpath = "com.demo.reflect.Car";
        try {
            Class car3 = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
            //需要抛出一个异常
            System.out.println(car3);
            try {
                //反射创建对象的方式一:
                Car t = (Car) car3.newInstance();//表示此类对象 表示的类的 新实例 采用了一个向下转型的模式
                // 就是由Class car3表示的com.demo.reflect.Car这个类的对象
            } catch (InstantiationException e) {//实例化异常
                e.printStackTrace();
            } catch (IllegalAccessException e) {//非法访问就是类型不匹配异常
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {    //类找不到异常
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

一旦class文件被加载到内存中,就会为其创建一个Class对象。任何类被使用时都会创建一个Class的对象。

Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。

Constructor类(创建构造方法)

Constructor提供了一个类的单个构造函数的信息和访问。Constructor允许在将实际参数与newInstance()与底层构造函数的形式参数进行匹配时进行扩展转换,但如果发生缩小转换,则抛出IllegalArgumentException 。
——来自jdk1.8的api(机译)

Constructor类的对象表示一个构造方法信息

Constructor类是可以通过getXXX的方法获得构造方法的基本信息。(构造方法是可以初始化我们的一个对象)
例如:
● getName:返回构造方法的名字
除了获得构造方法的基本信息,还可以创建实例
● newInstance(Object…initargs):创建一个实例

如何获得Constructor类的实例?

● Constructor实例通过Class实例获得,Class类中定义 了如下方法:
Constructor getConstructor(Class… parameterTypes) :通过指定参数类型,返回构造方法实例。
创建对象 constructor.newInstance(“zhangsan", 20);

● getConstructor()获得指定的公共构造方法
● getDeclaredConstructor()获得任意(包含私有的)指定的构造方法
● getConstructors() 返回所有公共的构造方法,返回值是数组
● getDeclaredConstructors() 获得所有的构造方法,返回值是数组

package com.demo.reflect;

public class Car {
    public String name;
    private String color;
    private int price;

    public Car() {
        System.out.println("这是一个无参构造");
    }

    public Car(String name, String color) {
        System.out.println("这是一个String,String的公共的有参构造");
        this.name = name;
        this.color = color;
    }

    private Car(String name, int price) {
        System.out.println("这是一个String,int的私有的有参构造");
        this.name = name;
        this.price = price;
    }

    public void run() {
        System.out.println("车能跑");
    }

    public void run(int speed) {
        System.out.println("车跑的速度是" + speed);
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
}
package com.demo.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        String classpath = "com.demo.reflect.Car";
        Class aClass = Class.forName(classpath);//根据类的地址将类信息加载到内存中,并创建类的Class对象
        System.out.println(aClass);
        System.out.println("---------------------------");

        //反射创建对象的方式一:
        Car car = (Car) aClass.newInstance();//表示此类对象 表示的类的 新实例 采用了一个向下转型的模式
        // 就是由Class car3表示的com.demo.reflect.Car这个类的对象
        System.out.println(car);
        System.out.println("---------------------------");
        //获得类的构造方法信息
        try {
            //反射创建对象的方式二:
            //getConstructor()获得指定的公共构造方法,需要传参的时候,传递的是参数的类型,只是意为拿到的意思
            Constructor constructor = aClass.getConstructor();//获得无参的构造方法
            // 就是将无参的构造方法信息封装到一个Construct的对象中去
            Car car1 = (Car) constructor.newInstance();
            //通过Constructor类中的newInstance()创建对应类的对象
            System.out.println(car1);
            System.out.println("---------------------------");


            Constructor constructor1 = aClass.getConstructor(String.class, String.class);
            //获得有参的构造方法,它里面传的也应该是参数的class的对象

            Car car2 = (Car) constructor1.newInstance("五菱", "五彩斑斓");
            //这里创建对象时,必须写入参数,不然它意为调用的是一个无参的构造方法,会报错的
            // 且它获得不了私有的构造方法
            System.out.println(car2);
            System.out.println("---------------------------");


            //反射创建对象的方式三:
            //getDeclaredConstructor()获得任意(包含私有的)指定的构造方法
            Constructor constructor2 = aClass.getDeclaredConstructor(String.class, int.class);
            constructor2.setAccessible(true);//手动设置可以允许操作私有权限,不设置的话会报错不能创建私有的构造方法
            Car car3 = (Car) constructor2.newInstance("五菱", 20000);
            System.out.println(car3);
            System.out.println("---------------------------");


            //反射创建对象的方式四:
            //getConstructors() 返回所有公共的构造方法,返回值是数组
            Constructor[] constructors = aClass.getConstructors();//返回所有公共的构造方法,返回值是数组

            //反射创建对象的方式四:
            //getDeclaredConstructors() 获得所有的构造方法,返回值是数组
            Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
            for (Constructor con : declaredConstructors) {
                System.out.println(con.getName());
                System.out.println(con.getParameterCount());//获得构造方法传入的参数数量
                System.out.println("--------------");
            }
            System.out.println("---------------------------");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            /*没有这种方法例外,异常意思就是说,可能没有这个构造方法
             * 为什么会没有呢?有一点就是在创建了一个有参的构造方法,那么无参的构造方法就没有了
             * 所以一般情况下,当我们在写有有参的构造方法时,会将无参的构造方法再次书写一遍*/
        }
    }
}

在这里插入图片描述

Field 属性

Field类是将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值。

● getName:返回属性的名字
● Set:设置属性值

获得Field实例

想要获得Field实例,都是通过Class中的方法实现

● public Field getField(String name)
● 通过指定Field名字,返回Field实例
● 注意Field的访问权限

package com.demo.reflect;

public class Car {
    public String name;
    private String color;
    private int price;

    public Car() {
        System.out.println("这是一个无参构造");
    }
    
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
}
package com.demo.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.demo.reflect.Car");

        Constructor<?> constructor = aClass.getConstructor();

        Object o = constructor.newInstance();//创建出一个对象来

        Field name = aClass.getField("name");
        //拿到类中name的这个属性,封装到Field name的这个对象中
        name.set(o, "五菱");//给Car这个类中的name属性赋一个值

        Field[] fields = aClass.getFields();
        //拿到类中name的所有(公共)的属性,封装到Field name的这个对象中

        Field[] declaredFields = aClass.getDeclaredFields();
        //拿到类中name的所有的属性,封装到Field name的这个对象中

        for (Field field : declaredFields) {
            field.setAccessible(true);//设置为true就可以设置私有可操作性
            if (field.getName().equals("name")) {//这里的name就相当于数据库当中的列名
                field.set(o, "极狐");//拿到了属性,给set到所选择对应的属性中去
            }
            if (field.getName().equals("color")) {
                field.set(o, "银色");
            }
            if (field.getName().equals("price")) {
                field.set(o, 12300);
            }
        }
        System.out.println(o);
    }
}

在这里插入图片描述

Method 方法

Method类将类中的方法进行封装,可以动态获得方法的信息。
例如:
● getName:获得方法名字
● getParameterTypes:获得方法参数类型

除了动态获得方法信息外,Method还能动态调用某一个对象的 具体方法

● invoke(Object obj, Object… args) :使用obj调用该方法,参数为args

如何获得Method实例?

Method实例都是通过Class类的方法获得

● Method getMethod(String name, Class… parameterTypes) :通过指定方法名,参数类型,返回一个 Method实例

package com.demo.reflect;

public class Car {
    public String name;
    private String color;
    private int price;

    public Car() {
        System.out.println("这是一个无参构造");
    }

    public void run() {
        System.out.println("车能跑");
    }

    public void run(int speed) {
        System.out.println("车跑的速度是" + speed);
    }

    public String getName() {
        System.out.println("这是属性值的get方法(getName方法)");
        return name;
    }

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

    public String getColor() {
        System.out.println("这是属性值的get方法(getColor方法)");
        ;
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getPrice() {
        System.out.println("这是属性值的get方法(getPrice方法)");
        ;
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}
package com.demo.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.demo.reflect.Car");

        //Constructor<?> constructor = aClass.getConstructor();

        Object o = aClass.newInstance();//创建出一个对象来

        Method met = aClass.getMethod("run");//这里获得找到的是一个无参的成员方法

        met.invoke(o); //调用方法
        //方法都是成员方法,是属于对象的,所以在调用方法时,都需要绑定在Class对象上

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

        Method met1 = aClass.getMethod("run", int.class);
        //这里获得的是一个有参的成员方法,要注明参数的类型,且类型也是要拿到对应的class对象中的
        met1.invoke(o, 80);
        System.out.println("-----------------------------");

        Field[] fields = aClass.getDeclaredFields();//获得到类中的所有属性
        for (Field field : fields) {
            Method method = aClass.getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
            //field.getName().substring(0,1).toUpperCase()获得name中的第一个字母,并将其大写,
            // 就这样通过知道属性名,就能拼成了一个私有属性获得数据的方法名,所以起名也是应该注意的一个东西

            method.invoke(o);
            System.out.println("------------");


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

在这里插入图片描述


反射机制多用于框架部分,框架为我们封装好,我们只需要写我们的业务代码,就产生看许多的类,框架就是通过反射来对我们创建的类进行管理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值