重学java 82.Java反射

迟早有一天,我要拿到唯一的发问权 

                                                —— 24.6.23

一、class对象以及反射介绍

1.反射概述:

        解剖class对象的一个技术

2.问题:

        能解剖class对象的啥呢?

                a.解剖出成员变量 :赋值
                b.解剖出成员方法:调用
                c.解剖出构造方法:new对象

3.用反射的好处:

        让代码变的更通用,更灵活

4.怎么学反射:

        a.将反射看成是一套API来学

        b.通过案例,体会反射的好处

5.问题:反射第一步:

        获取Class对象

6.class对象:

        class文件对应的对象

        class类:描述class对象的类叫做class类

二、反射之获取Class对象

1.方式1:调用Object中的getClass方法

        Class <?> getClass()

2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class

3.方式3:Class类中的静态方法

        static Class<?> forName(String className)

                className:传递的是类的全限定名(包名.类名)

写类的全限定名小技巧

a、如何快速写类的全限定名

        ① 直接复制粘贴

        ② 直接写类名 然后 回车

b、如何检测类的全限定名写正确与否?

        按住ctrl不放,鼠标点击此类名,能跳到对应的类中,就证明写的全限定名是对的

public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

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

    // 私有构造
    private Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import org.junit.Test;

public class Demo333GetClass {
    @Test
    public void get1() throws Exception {
        Person person = new Person();
        Class<? extends Person> aClass = person.getClass();
        System.out.println("aClass = " + aClass);
        System.out.println("————————————————————————————————————");

        // 方式二:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
        Class<Person> aClass1 = Person.class;
        System.out.println("aClass1 = " + aClass1);
        System.out.println("————————————————————————————————————");

        // 方式三:Class类中的静态方法 static Class<?> forName(String className),传递的是类的全限定名(包名.类名)
        Class<?> aClass2 = Class.forName("S112Reflect.Person");
        System.out.println("aClass2 = " + aClass2);

        // class对象只有一个
        System.out.println(aClass==aClass1);
        System.out.println(aClass==aClass2);
        System.out.println(aClass1==aClass2);
    }
}

4.最通用获取Class对象的方式

1.方式3:class类中的静态方法:

        static Class<?> forName(String className)

                ClassName:传递的是类的全限定名(包名.类名)

2.原因:

        参数为String形式,可以和properties文件结合使用

className=AllWillBest_Java.S112Reflect.Student
import java.io.FileInputStream;
import java.util.Properties;

public class Demo334GetClass2 {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("Pro.properties");
        properties.load(in);

        String className = properties.getProperty("className");
        System.out.println(className);

        Class<?> aClass = Class.forName("Pro.properties");
        System.out.println("aClass = " + aClass);
    }
}

5.开发中最常用的是哪一种

直接类名.class -> 最方便使用

三、反射构造方法

1.获取所有public的构造方法

  Class类中的方法:

        Constructor <?>[] getConstructors() ——> 获取所有public的构造

import java.lang.reflect.Constructor;

public class Demo335GetConstructor {
    public static void main(String[] args) {
        // 获取Class对象
        Class<Person> aClass = Person.class;
        // 获取所有public的构造
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

2.获取空参构造 _public

1.Class类中的方法:

        Constructor<T> getconstructor(class<?>...parameterTypes) ——> 获取指定的public的构造

                        parameterTypes:可变参数,可以传递0个或多个参数

a、如果获取的是空参构造:参数不用写
b、如果获取的是有参构造:参数写参数类型的class对象

import java.lang.reflect.Constructor;

public class Demo335GetConstructor {
    public static void main(String[] args) {
        // 获取Class对象
        Class<Person> aClass = Person.class;
        // 获取所有public的构造
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

2.Constructor类中的方法

        T newInstance(object...initargs) ——> 创建对象
                initargs:传递的是构造方法的实参

        a.如果根据无参构造new对象,initargs不写了

        b.如果根据有参构造new对象,initargs传递实参

import java.lang.reflect.Constructor;

public class Demo336GetConstructor {
    public static void main(String[] args) throws Exception {
        // 获取class对象
        Class<Person> aClass = Person.class;
        Constructor<Person> constructor = aClass.getConstructor();
        System.out.println("Person constructor: " + constructor);

        // 空参构造,好比是Person person = new Person()
        Person person = constructor.newInstance();

        // 好比是直接输出对象名,默认调用toString
        System.out.println(person);
    }
}

3.利用空参构造创建对象的快捷方式_public

Class类中的方法:

        T newInstance() ——> 根据空参构造创造对象

        前提:被反射的类中必须有public的空参构造

public class Demo337GetConstructor {
    public static void main(String[] args)throws Exception {
        // 获取Class对象
        Class<Person> aClass = Person.class;

        Person person = aClass.newInstance();

        System.out.println(person);
    }
}

3.利用反射获取有参构造并创建对象_public

1.Class类中的方法:

        Constructor<T> getconstructor(class<?>...parameterTypes) ——> 获取指定的public的构造

                        parameterTypes:可变参数,可以传递0个或多个参数

a、如果获取的是空参构造:参数不用写
b、如果获取的是有参构造:参数写参数类型的class对象

2.Constructor类中的方法

        T newInstance(object...initargs) ——> 创建对象
                initargs:传递的是构造方法的实参

        a.如果根据无参构造new对象,initargs不写了

        b.如果根据有参构造new对象,initargs传递实参

import java.lang.reflect.Constructor;

public class Demo338GetConstructor {
    public static void main(String[] args) throws Exception{
        // 获取class对象
        Class<Person> aClass = Person.class;

        Constructor<Person> constructor = aClass.getConstructor(String.class, Integer.class);
        System.out.println("constructor: " + constructor);

        // 创建对象 好比是Person person = new Person("小明",25);
        Person person = constructor.newInstance("小明", 25);

        // 好比是直接输出Person对象,直接调用toString
        System.out.println(person);
    }
}

4.利用反射获取私有构造(暴力反射)

1.Constructor<?>[] getDeclaredconstructors() —— 获取所有构造方法,包括private

2.Constructor<T> getDeclaredConstructor(类><?>...parameterTypes) —— 获取指定构造,包括private
        parameterTypes:参数类型的class对象

3.Constructor有一个父类叫做Accessibeobject,里面有一个方法

void setAccessible(boolean fag) ——> 修改访问权限

        flag为true:解除私有权限

import java.lang.reflect.Constructor;

public class Demo339GetConstructor {
    public static void main(String[] args)throws Exception{
        Class<Person> aClass = Person.class;
        // 获取所有的class对象,包括private
        Constructor<?>[] dc = aClass.getDeclaredConstructors();
        for (Constructor<?> c : dc) {
            System.out.println(c);
        }

        // 获取指定class对象,包括private
        Constructor<Person> dC = aClass.getDeclaredConstructor(String.class);
        System.out.println(dC);

        // Constructor有一个父类叫做Accessibeobject,里面有一个方法,void setAccessible(boolean fag) ——> 修改访问权限
        Constructor<Person> DC = aClass.getDeclaredConstructor(String.class);
        DC.setAccessible(true); // 接触私有权限 ——> 暴力反射
        System.out.println(DC);
        Person person = DC.newInstance("小明");
        System.out.println(person);

    }
}


四、反射成员方法

1.利用反射获取所有成员方法_public

1.Class类中方法:
        Method[] getMethods() ——> 获取所有public的方法,包括父类中的public方法

import java.lang.reflect.Method;

public class Demo340GetConstructor {
    public static void main(String[] args)throws Exception{
        method01();
    }

    // 获取所有的public方法
    private static void method01(){
        Class<Person> aClass = Person.class;
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

2.反射之获取方法(有参,无参)_public

1.Class类中的方法:
        Method getMethod(string name, class<?>... parameterTypes) ——> 获取指定的public的成员方法

        name:传递方法名
        parameterTypes:方法参数类型的class对象

2.调用方法Method对象中的方法:

        object invoke(object obj,object...args) ——> 执行方法
                obj:根据构造new出来的对象
                args:方法实参 ——> 如果有参数,直接传递实参,否则不用传

                返回值:object ——> 接收被执行方法的返回值,如果方法没有返回值,不用接收了

import java.lang.reflect.Method;

public class Demo340GetConstructor {
    public static void main(String[] args)throws Exception{
        method02();
    }

    // 获取指定的public方法
    private static void method02() throws Exception {
        Class<Person> aClass = Person.class;
        // 创建对象
        Person person = aClass.newInstance();

        Method setName = aClass.getMethod("setName", String.class);
        System.out.println(setName);
        setName.invoke(person,"小明");
        System.out.println(person); // 好比调用同String

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

        // 反射一个get方法
        Method getName = aClass.getMethod("getName");
        // 好比是person.getName() 有返回值,用变量接收
        Object name = getName.invoke(person);
        System.out.println(name);
    }
}

3.反射之操作私有方法

1.Methodll getDecaredMethods() ——> 获取所有的成员方法,包括private 的

2.Method getDeclaredethod(string name,类<?>...parameterTypes) ——> 获取执行成员方法,包括private

        name:传递方法名
        parameterTypes:方法参数类型的class对象

3.解除私有权限:void setAccessible(boolean flag)

获取所有成员方法

import java.lang.reflect.Method;

public class Demo340GetConstructor {
    public static void main(String[] args)throws Exception{
        method03();
        System.out.println("——————————————————————————————————");
    }


    // 获取所有成员方法,包括private
    private static void method03() {
        Class<Person> aClass = Person.class;
        Method[] dm = aClass.getDeclaredMethods();
        for (Method method : dm) {
            System.out.println(method);
        }
    }

}

获取执行成员方法

import java.lang.reflect.Method;

public class Demo340GetConstructor {
    public static void main(String[] args)throws Exception{
        method04();
    }

    // 反射指定方法,包括private
    private static void method04() throws Exception {
        Class<Person> aClass = Person.class;
        Person person = aClass.newInstance();
        Method method = aClass.getDeclaredMethod("eat");
        method.setAccessible(true);
        method.invoke(person);
    }
}

五、反射成员变量

1.获取所有属性

Class类中的方法:
        1.Field[] getFields() ——> 获取所有public的属性

        2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的

import java.lang.reflect.Field;

public class Demo341GetField {
    public static void main(String[] args) {
        method01();
        System.out.println("——————————————————————————————");
        method02();
    }

    /**
     * 1.Field[] getFields() ——> 获取所有public的属性
     * 2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的
     */
    private static void method02() {
        Class<Student> studentClass = Student.class;
        Field[] df = studentClass.getDeclaredFields();
        for (Field f : df) {
            System.out.println(f);
        }

    }

    private static void method01() {
        Class<Student> studentClass = Student.class;
        Field[] fields = studentClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

2.获取指定属性

Class类中的方法:
        1.Field getField(String name) ——> 获取指定public的属性

        2.Field getDeclaredField(String name) ——> 获取指定属性,包括private的

Field类中的方法:

        3.void set(object obj,object value) ——> 为属性赋值,相当于javabean中的set方法

                obj:对象
                value:赋予的值

        4.Object get(Object obj) ——> 获取属性值

                obj:对象

import java.lang.reflect.Field;

public class Demo341GetField {
    public static void main(String[] args) throws Exception {
        method01();
        System.out.println("——————————————————————————————");
        method02();
        System.out.println("——————————————————————————————");
        method03();
        System.out.println("——————————————————————————————");
        method04();
    }

    private static void method04() throws Exception {
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();
        Field name  = studentClass.getDeclaredField("name");
        // 解除私有权限
        name.setAccessible(true);

        // 调用set方法为属性赋值
        name.set(student,"小明");
        // 调用get方法获取属性值
        Object o = name.get(student);
        System.out.println(o);
    }

    /**
     * 3.void set(object obj,object value) ——> 为属性赋值,相当于javabean中的set方法
     *     obj:对象
     *     value:赋予的值
     * 4.Object get(Object obj) ——> 获取属性值
     *     obj:对象
     */
    private static void method03() throws Exception {
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();
        Field age  = studentClass.getField("age");
        // 调用set方法为属性赋值
        age.set(student,10);
        // 调用get方法获取属性值
        Object o = age.get(student);
        System.out.println(o);
    }

    /**
     * 1.Field[] getFields() ——> 获取所有public的属性
     * 2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的
     */
    private static void method02() {
        Class<Student> studentClass = Student.class;
        Field[] df = studentClass.getDeclaredFields();
        for (Field f : df) {
            System.out.println(f);
        }

    }

    private static void method01() {
        Class<Student> studentClass = Student.class;
        Field[] fields = studentClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

        

六、反射练习(编写一个小框架)

需求:

        在配置文件中,配置类的全限定名,以及配置一个方法名,通过解析配置文件,让配置好的方法执行起来

        className=包名.Person
        methodName=eat

步骤:

        1.创建properties配置文件,配置信息

                a.问题:properties配置文件放到哪里?

                答:将来我们开发完之后给用户的是out路径下的class文件,将class文件打包, 如果将配置文件直接放到模块下那么out路径下是不会生成这个配置文件的,如果没有配置文件,程序也就运行不起来了
                解决:我们可以将配置文件放到src下,放到src下,out路径下就会出现配置文件
                b.问题:将配置文件放到src下,out路径下会自动生成配置文件,但是如果我们将来将所有的配置文件都放到src下,那么src下面会显得特别乱

                解决:我们可以单独创建一个文件夹,将所有的配置文件放到此文件夹下,将此文件夹改成资源目录,取名为resources

配置文件

className=S114ReflectExample.Person
methodName=eat

        2.读取配置文件,解析配置文件

          a.问题:如果将配置文件放到resources资源目录下,我们怎么读取?

                new FileInputstream("模块名\\resources\\properties文件名") ——> 这样不行,out路径下没有resources ——> 相当于写死了
          b.问题解决:用类加载器

                ClassLoader classLoader = 当前类.class.getclassLoader()

                Inputstream in = classLoader.getResourceAsstream("文件名")//自动扫描resources下的文件 ——> 可以简单理解为扫描out路径下的配置文件

        3.根据解析出来的className,创建Class对象

        4.根据解析出来的methodName,获取对应的方法

        5.执行方法

public class Person {
    public void eat(){
         System.out.println("人要吃饭");
    }
}
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class Demo342Reflect {
    public static void main(String[] args) throws Exception {
        // 1.创建properties集合
        Properties properties = new Properties();

        // 2.读取配置文件,解析配置文件
        InputStream in = Demo342Reflect.class.getClassLoader().getResourceAsStream("Pro.properties");
        properties.load(in);
        // System.out.println(properties);

        // 3.根据解析出来的className,创建class对象
        // 4.根据解析出来的methodName,获取相应的方法
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        Class<?> aClass = Class.forName(className);
        Object o = aClass.newInstance();

        Method method = aClass.getMethod(methodName);

        // 5.执行方法
        method.invoke(o);
    }
}

修改配置文件

className=S114ReflectExample.Person
methodName=sleep
public class Person {
    public void eat(){
         System.out.println("人要吃饭");
    }

    public void sleep(){
        System.out.println("人要睡觉");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值