【JavaSE】Java反射技术

目录

反射概述

反射的关键:

使用反射技术获取构造器对象并使用

使用反射技术获取成员变量对象并使用

使用反射技术获取方法对象并使用

案例——反射做通用框架


反射概述

反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:constructor
在运行时,可以直接得到这个类的成员变量对象: Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

反射的关键:

反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。

package d2_reflect_class;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.Class类中的一个静态方法:forName(权限名:包名 + 类名)
        Class c = Class.forName("d2_reflect_class.Student");
        System.out.println(c);

        //2.类名.class
        Class c1 = Student.class;
        System.out.println(c1);

        //3.对象.getClass() 获取对象对应类的Class对象
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    }
}

使用反射技术获取构造器对象并使用

·反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
·Class类中用于获取构造器的方法

方法说明
Constructor<?>[] getConstructors()返回所有构造器对象的数组(只能拿public的)
Constructcr<?>[] getDeclaredConstructors()返回所有构造器对象的数组。存在就能拿到
constructor<T getconstructor(Class<?>... parameterTypes)返回单个构造器对象《只能拿public的)
Constructor<T> getDeclaredConstructor(class<?>... parameterTypes)返回单个构造嚣对象,存在就能拿到
package d3_reflect_constructor;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class TestStudent1 {
    //1.getConstructors:
    //获取全部的构造器:只能或取public修饰的构造器
    //Constructor[] getConstructors()
    @Test
    public void getConstructors(){
        //a.第一步:获取类对象
        Class c = Student.class;
        //b.第二步:提取类中的全部的构造器对象
        Constructor[] constructors = c.getConstructors();
        //c.遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }

    //2.getDeclaredConstructors():
    //获取全部的构造器:只要你敢写,这里就能拿到,无所谓权限是否可及
    @Test
    public void getDeclaredConstructors(){
        //a.第一步:获取类对象
        Class c = Student.class;
        //b.第二步:提取类中的全部的构造器对象
        Constructor[] constructors = c.getDeclaredConstructors();
        //c.遍历构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }

    //3.getCongstructor(Class... parameterTypes)
    //获取某个构造器:只能拿public修饰的某个构造器
    @Test
    public void getCongstructor() throws Exception {
        //a.第一步:获取类对象
        Class c = Student.class;
        //b.定位单个构造器对象(按照参数定位无参数构造器)
        Constructor cons = c.getConstructor();
        System.out.println(cons.getName() + "===>" + cons.getParameterCount());
    }

    //4.getDeclaredConstructor(Class... parameterTypes)
    //获取某个构造器:只要你敢写,这里就能拿到,无所谓权限是否可及
    @Test
    public void getDeclaredConstructor() throws Exception {
        //a.第一步:获取类对象
        Class c = Student.class;
        //b.定位单个构造器对象(按照参数定位无参数构造器)
        Constructor cons = c.getDeclaredConstructor();
        System.out.println(cons.getName() + "===>" + cons.getParameterCount());

        //c.定位某个有参数构造器
        Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
        System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());
    }
}

获取构造器的作用依然是初始化一个对象返回。

符号说明
T newlnstance(Object.. initargs)根据指定的构造器创建对象
public void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射
package d3_reflect_constructor;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class TestStudent2 {
    //1.调用构造器得到一个类的对象返回
    @Test
    public void getDeclaredConstructor() throws Exception {
        //a.第一步:获取类对象
        Class c = Student.class;
        //b.定位单个构造器对象(按照参数定位无参数构造器)
        Constructor cons = c.getDeclaredConstructor();
        System.out.println(cons.getName() + "===>" + cons.getParameterCount());

        //如果遇到了私有的构造器,可以暴力反射
        cons.setAccessible(true);//权限被打开

        Student s = (Student) cons.newInstance();
        System.out.println(s);

        //c.定位某个有参数构造器
        Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
        System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());

        Student s1 = (Student) cons1.newInstance("孙悟空",501);
        System.out.println(s1);
    }
}

使用反射技术获取成员变量对象并使用

·反射的第一步是先得到类对象。然后从类对象中获取类的成分对象。

·Class类中用于获取成员变量的方法

方法说明
Field getFields()返回所有成员变量对象的数组(只能拿public的)
Field getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
Field getField(String name)返回单个成员变量对象〔只能拿public的)
Field getDeclaredField(String name)返回单个或员变量对象,存在就能拿到
package d4_reflect_field;

import org.junit.Test;

import java.lang.reflect.Field;

public class FieldDemo1 {
    /*
    1.获取全部的成员变量
    Field[] getDeclaredFields();
    获得所有的成员变量对应的Field对象,只要申明了就可以得到
     */
    @Test
    public void getDeclaredFields(){
        //a.定位Class对象
        Class c = Student.class;
        //b.定位全部成员变量
        Field[] fields = c.getDeclaredFields();
        //c.遍历一下
        for (Field field : fields) {
            System.out.println(field.getName() + "===>" +field.getType());
        }
    }

    /*
    2.获取某个成员变量对象
     */
    @Test
    public void getDeclaredField() throws Exception {
        //a.定位Class对象
        Class c = Student.class;
        //b.根据名称定位某个成员变量
        Field f = c.getDeclaredField("age");
        System.out.println(f.getName() + "===>" +f.getType());
    }


}

获取成员变量的作用依然是在某个对象中取值、赋值

Field类中用于取值、赋值的方法

符号说明
void set(Object obj, Object value)赋值
Object get(Object obj)获取值
package d4_reflect_field;

import org.junit.Test;

import java.lang.reflect.Field;

public class FieldDemo2 {
    @Test
    public void setField() throws Exception {
        //a.反射第一步,获取类对象
        Class c = Student.class;
        //b.提取某个成员变量
        Field ageF = c.getDeclaredField("age");

        ageF.setAccessible(true);//暴力打开权限

        //c.赋值
        Student s = new Student();
        ageF.set(s,18);//s.setAge(18);
        System.out.println(s);

        //d.取值
        int age = (int) ageF.get(s);
        System.out.println(age);
    }
}

使用反射技术获取方法对象并使用

反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

Class类中用于获取成员方法的方法

方法说明
Netho[ ]getMathods()反回所有成是方法对象的数组(只缕拿public的
Method[ ] getDeclarecMethods()返回所有成员方法对象的数组,存在就能拿到
Nethod getMethod(String name,Class<?>... parameterTypes)反同单个成员方法对象(只能拿public的)
Nethod getDeclaredMethod(String name,class<?>... parareterTypes)返回单个成是方法对象,存在就能拿到

获取成员方法的作用依然是在某个对象中进行执行此方法

Method类中用于触发执行的方法

符号说明
object invoke(0bject obj,0bject. . . args)

运行方法

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

package d5_reflect_method;

import org.junit.Test;

import java.lang.reflect.Method;

public class MethodDemo1 {
    /*
    1.获取类中的所有成员变量
     */
    @Test
    public void getDeclaredMethods(){
        //a.获取类对象
        Class c = Dog.class;
        //b.提取全部方法
        Method[] methods = c.getDeclaredMethods();
        //c.遍历全部方法
        for (Method method : methods) {
            System.out.println(method.getName() + "返回值类型:" + method.getReturnType() + "参数名称:" + method.getParameterCount());
        }
    }

    /*
    2.获取某个方法对象
     */
    @Test
    public void getDeclaredMethod() throws Exception {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取单个方法对象
        Method m = c.getDeclaredMethod("eat");
        Method m2 = c.getDeclaredMethod("eat",String.class);

        //暴力打开权限了
        m.setAccessible(true);
        m2.setAccessible(true);

        //c.触发方法的执行
        Dog d = new Dog();
        //注意:方法如果是没有结果回来的,那么返回的是null
        Object result = m.invoke(d);
        System.out.println(result);

        Object result2 = m2.invoke(d,"骨头");
        System.out.println(result2);
    }
}

反射的作用-绕过编译阶段为集合添加数据

反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。

泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
 

package d6_reflect_genericity;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //需求:反射实现泛型擦除后,加入其他类型的元素
        ArrayList<String> lists1 = new ArrayList<>();
        ArrayList<Integer> lists2 = new ArrayList<>();

        System.out.println(lists1.getClass());
        System.out.println(lists2.getClass());

        System.out.println(lists1.getClass() == lists2.getClass());

        System.out.println("------------------------------");
        ArrayList<Integer> lists3 = new ArrayList<>();
        lists2.add(23);
        lists2.add(22);
//        lists3.add("hh");

        Class c = lists3.getClass();
        //定位c类中的add方法
        Method add = c.getDeclaredMethod("add",Object.class);
        boolean rs = (boolean) add.invoke(lists3,"hh");
        System.out.println(rs);

        System.out.println(lists3);
    }
}

案例——反射做通用框架

需求
给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。
分析
1、定义一个方法,可以接收任意类的对象。
2、每次收到一个对象后,需要解析这个对象的全部成员变量名称。
3、这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
4、使用反射获取对象的Class类对象,然后获取全部成员变量信息。
5、遍历成员变量信息,然后提取本成员变量在对象中的具体值
6、存入成员变量名称和值到文件中去即可。
 

package d7_reflect_framework;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class MybatisUtil {
    /*
    保存任意类型对象
     */
    public static void save(Object obj) throws Exception {
        try (PrintStream ps = new PrintStream(new FileOutputStream("src/data",true));
        ){
            //1、提取这个对象的全部成员变量:只有反射可以解决
            Class c = obj.getClass(); //c.getSimpleName()获取当前类名 c.getName获取全限名:包名+类名
            ps.println("===" + c.getSimpleName() +"===");

            //2.提取它的全部成员变量
            Field[] fields = c.getDeclaredFields();
            //3.获取成员变量的信息
            for (Field field : fields) {
                String name = field.getName();
                //提取本成员变量在obj对象的值(取值)
                field.setAccessible(true);
                String value = field.get(obj) + "";
                ps.println(name + "=" + value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

反射的作用

可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iknow181

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值