JavaSE 反射

反射

框架设计的灵魂: 反射。
<链接:https://pan.baidu.com/s/1BTbpEghJ1XT53duNvkmiQg
提取码:1234
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V3的分享>
框架: 半成品软件。可以在框架的基础进行软件开发,简化编码。

概念: 将类的各个组成部分封装为其他对象,这就是反射机制。

好处: 1. 可以在程序运行过程中,操作这些对象。 获取、操作

​ 2.可以解耦,提高程序的可扩展性。

获取class 对象的方式:

1.Class.forName("全类名") ,将字节码文件加入到内存

​ 多用于配置文件,将类名定义在配置文件中,读取文件,加载类

2.类名.class : 通过类名的属性class 获取

多用于参数的传递

3.对象.getClass() :getClass 方法在object 类中定义的。

多用于对象的获取字节码的方式

结论:

同一个字节码文件(*.class) 在一次程序运行过程中,只会被加载一次,相对应的对象也会只会创建一个,不论通过哪一种方式
反射:就是通过class文件对象,去使用该文件中的成员变量、构造方法和成员方法。

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

​ 想要解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。


Class类:

​ 成员变量 Field

​ 构造方法 Constructor

​ 成员方法 Method

得到这个类的对象,通过这个类的对象去调用方法,使用该方法

获取class文件对象的三种方式

  • Object类的getClass()方法

  • 数据类型的静态属性class

  • Class中的静态方法

    ​ API格式: public static Class forName(String className)

一般使用过程中选择:

​ 自己使用时,可以任意选择,推荐第二种更方便。

​ 做开发工作时,通常选择使用第三种。

通过反射获取构造方法并使用

Person类:

package com.demo06;

public class Person {
    private String name;
    int age;
    public String hobby;

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

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

   public void show(){
        System.out.println("show");
    }
    public Person(){}

    public void Person(int age, String hobby) {
        this.age = age;
        this.hobby = hobby;
    }
    private Person(String name,String hobby){
        this.name = name;
        this.hobby = hobby;
    }

    public String getName() {
        return name;
    }

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

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

通过反射获取构造方法并使用

package com.demo06;

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

public class Test01 {

    ////////通过反射获取构造方法并使用
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件对象
        Class c = Class.forName("com.demo06.Person");

        //获取构造方法
//        public Constructor[] getConstructors();    //获取所有的公共(public)构造方法
        //public Constructor[] getDeclaredConstructors();   获取所有的构造方法
//        Constructor[] cons = c.getDeclaredConstructors();
//        Constructor[] cons2 = c.getConstructors();
//        for (Constructor con : cons2) {
//            System.out.println(con);
//        }

        //获取单个构造方法
        //public Constructor<T> getConstructor(Class<?>...parameterTypes)
        //这里参数所表示的是:   想要获取的构造方法的构造参数个数以及数据类型的class字节码文件对象
        Constructor con = c. getConstructor();   //    返回的是构造方法对象
//        System.out.println(con);

//        Person p = new Person;
//        System.out.println(p);
//        public T newInstance(Object...initargs)
//        使用此Constructor 对象表示的方法来创建该构造方法的声明类的辛实例,并用指定的初始化参数初始化该实例。
        Object o = con.newInstance();
        System.out.println(o);
        //////

//        Person p = (Person)o;
//        System.out.println(p);
//        p.show();
    }
}

示例1:

package com.demo06;

import java.lang.reflect.Constructor;

public class Test02 {
    public static void main(String[] args) throws  Exception{
//       需求:   通过反射去获取该构造方法并使用
//       public Person(String name, int age, String hobby)

//        Person p = new Person("22",22,"22");
//        System.out.println(p);

//      获取字节码文件对象
        Class c = Class.forName("com.demo06.Person");

//        获取带参构造方法对象
//        public Constructor<T> getConstructor(Class<?>...parameterTypes)
        Constructor con = c.getConstructor(String.class,int.class,String.class);

//        通过带参构造方法创建对象
//        public T newInstance(Object...initargs)
        Object o = con.newInstance("22",22,"22");
        System.out.println(o);
    }
}

示例2:

package com.demo06;

import java.lang.reflect.Constructor;

public class Test03 {

//    需求: 通过反射获取私有构造方法并使用
//private Person(String name,String hobby)
//    Person p = new Person("小明","运动");
//    System.out.println(p)

    public static void main(String[] args) throws Exception{
        //获取字节码对象
        Class c = Class.forName("com.demo06.Person");

        //获取私有构造方法对象
//        NoSuchMethodException   找不到这个对应的方法异常
//        原因是使用的方法只能获取公共方法  Constructor con = c.getConstructor(String.class,String.class);
//        使用下面这种方法即可
        Constructor con = c.getDeclaredConstructor(String.class,String.class);

        //用该私有构造方法创建对象
//        IllegalAccessException   非法的访问异常 没有访问pravate的权限
//        暴力访问即可
        con.setAccessible(true);   //  使用boolean值
        Object o = con.newInstance("小明", "运动");
        System.out.println(o);
    }
}

示例3:

package com.demo06;

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

public class Test04 {


//      需求 :   通过反射获取成员变量并使用
//   public Person(String name, int age, String hobby)
    public static void main(String[] args) throws Exception{
//        获取字节码文件对象
        Class c = Class.forName("com.demo06.Person");

        //获取所有的成员变量
        //Field[] fields = c.getFields();
//        Field[] fields = c.getDeclaredFields();
//        for (Field field:fields){
//            System.out.println(field);
//        }

        //通过无参构造物方法创建对象
        Constructor con = c.getConstructor();
        Object o = con.newInstance();
        System.out.println(o);

        //获取单个成员变量
        //获取name并对其赋值
        Field nameField = c.getDeclaredField("name");
        nameField.setAccessible(true);
        //public void set(Object obj,Object value)
        //将指定对象变量上此Field对象表示的字段设置为指定的新值
        nameField.set(o,"小明");
        System.out.println(o);

        //获取age并对其赋值
        Field ageField = c.getDeclaredField("age");
        ageField.set(o,12);
        System.out.println(o);

        //获取hobby并对其赋值
        Field hobbyField = c.getDeclaredField("hobby");
        hobbyField.set(o,"运动");     ///表达的意义为,调用set给o的Field字段赋值“运动”
        System.out.println(o);
    }
}

通过反射获取成员方法并使用

示例1:

package com.demo06;
////无参返回
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Test05 {
    public static void main(String[] args) throws Exception{
        //获取字节码文件对象
        Class c = Class.forName("com.demo06.Person");

        //获取所有的方法
//        Method[] methods = c.getMethods(); //  获取本类以及父类的public方法
//        Method[] me = c.getDeclaredMethods();  //获取自己的所有方法
//        for (Method method: me){
//            System.out.println(method);
//        }

        Constructor con = c.getConstructor();
        Object o = con.newInstance();

        //获取单个方法并使用
        //public void show()
        //public Method getMethod(String name,Class<?>...parameterTypes)
        //第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
        Method m1 = c.getMethod("show");
        //o.mi();   //错误
        //public Object invoke(Object obj,Object...args)
        //返回值是Object接收,第一个参数表示对象是谁,第二个参数表示调用该方法的实际参数
        m1.invoke(o);
    }
}

示例2:

//带参返回    接在示例1后

//         private Person(String name,String hobby)
        Method person = c.getMethod("Person", int.class, String.class);
        person.setAccessible(true);
        person.invoke(o,12,"运动");
posted @ 2020-12-09 20:56  简于乐。  阅读(129)  评论(0)    收藏  举报