JAVA基础之反射(Reflection)

获得Class类的实例的多种方法

方法:Method
字段:Field
构造器:Constructor

public class test1 {

    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是"+person.name);

        //方法一:通过对象获得
        Class a1 = person.getClass();
        System.out.println(a1.hashCode());

        //方法二:forName获得   一般都用这个方法
        Class a2 = Class.forName("com.hxz.test.Student");
        System.out.println(a2.hashCode());

        //方法三:通过类名.class获得
        Class a3 = Student.class;
        System.out.println(a3.hashCode());

        //获得父类类型
        Class a4 = a1.getSuperclass();
        System.out.println(a4);

    }
}

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student() {
        this.name="学生";
    }
}

class Teacher extends Person{
    public Teacher() {
        this.name="老师";
    }
}

ClassLoader类理解

这个涉及到JVM了
可以先看https://blog.csdn.net/u014634338/article/details/81434327

类的初始化

类的主动引用(一定会发生类的初始化)

当虚拟机启动,先初始化main方法所在的类

    public static void main(String[] args) { }

new一个类的对象

Person person = new Student();

调用类的静态成员(除了final常量)和静态方法
static

使用java.lang.reflect包的方法对类进行反射调用

  Class a2 = Class.forName("com.hxz.test.Student");

当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
B继承A调用B的方法时会先加载B再加载A

类的被动引用(不会发生类的初始化)

当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化

子类调用父类方法,只会加载父类方法
System.out.println(son.dad);

通过数组定义类引用,不会触发此类的初始化

Son[] array =new Son[5];
这样是不会加载初始化的

引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

比如在子类定义一个
static final int a = 1;
这时在main函数里 System.out.println(son.a);
只会加载main函数,并不会加载子类和父类

获取类的运行结构

这些大部分还是会被用到的

public class test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class a1 = Class.forName("com.hxz.test.User");

        System.out.println(a1.getName());
        //获得类名
        System.out.println(a1.getSimpleName());

        //获得类的属性
        System.out.println( "==================================");
        //只能找到public属性
        Field[] fields = a1.getFields();

        //找到全部的属性
        fields = a1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println( field);
        }

        //获得指定属性的值
        Field name = a1.getDeclaredField("name") ;
        System.out.println(name) ;

        //获得类的方法
        System.out.println( "==================================");
        //获得本类及其父类的所有方法,除了private
        Method[] methods = a1.getMethods();
        for (Method method : methods) {
            System.out.println("正常的 "+method);
        }
        //获得本类的所有方法,包括私有的
        methods = a1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("getDeclaredMethods  "+method);
        }


        //获得指定方法
        //重载
        Method getName = a1.getMethod("getName", null);
        Method setName = a1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得构造器
        System.out.println( "==================================");
        //只能获得public方法
        Constructor[] constructors = a1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        //能获得全类的方法
        Constructor[] declaredConstructors = a1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        //获得指定构造器
        Constructor declaredConstructor = a1.getDeclaredConstructor( int.class, String.class, int.class);
        System.out.println(declaredConstructor);


    }
}

class User {

    private int id;
    private String name;
    private int age;

    public User(){

    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    private void siyou(){

    }

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

动态创建对象执行方法

//动态创建对象,通过反射
public class test3 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        //获得class对象
        Class a1 = Class.forName("com.hxz.test.User");

        //构造一个对象
        User user = (User) a1.newInstance();
        //这个方法默认构造的是无参构造器
        System.out.println(user);

        //通过构造器创建对象
        //获取带参的构造器
        Constructor declaredConstructor = a1.getDeclaredConstructor(int.class, String.class, int.class);
        //通过获得的带参构造器创建对象,并传参
        User user2 = (User) declaredConstructor.newInstance(11, "衣衣", 18);
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User) a1.newInstance();
        //通过反射获得一个方法
        Method setName = a1.getDeclaredMethod("setName", String.class);
        //invoke:激活(对象,"方法的值")
        setName.invoke(user3,"衣衣");
        System.out.println(user3.getName());

        //通过反射操作属性
        System.out.println( "==================================");
        User user4 = (User) a1.newInstance();
        Field name = a1.getDeclaredField("name");

        //关闭安全检测,不然无法操作私有属性,没有这句话会报错,但是这样会降低程序效率
        name.setAccessible(true);
        name.set(user4,"衣衣2");
        System.out.println(user4.getName());

    }
}

性能检测

从下面知道关闭性能检测会降低性能
没关闭时,无法获取private但可以获取其他三种
这是结果
在这里插入图片描述

//分析性能问题
public class test4 {

    //普通方式调用
    public static void test1(){
        User user = new User();

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 100000000; i++) {
            user.getName();
        }

        long endTime = System.currentTimeMillis();

        System.out.println("普通执行了 " + (endTime-startTime) + "ms");
    }

    //反射方式调用
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class a1 = user.getClass();

        Method getName = a1.getDeclaredMethod("getName", null);

//    protected  Method aa = a1.getDeclaredMethod("aa", null);
//     default     Method bb = a1.getDeclaredMethod("bb", null);
//     private   Method siyou = a1.getDeclaredMethod("siyou", null);


        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 100000000; i++) {
            getName.invoke(user,null);
            //aa.invoke(user,null);
            //siyou.invoke(user,null);
        }

        long endTime = System.currentTimeMillis();

        System.out.println("反射执行了" + (endTime-startTime) + "ms");
    }



    //反射方式调用 关闭检测
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class a1 = user.getClass();

        Method getName = a1.getDeclaredMethod("getName", null);

        getName.setAccessible(true);

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 100000000; i++) {
            getName.invoke(user,null);
        }

        long endTime = System.currentTimeMillis();

        System.out.println("反射2执行了" + (endTime-startTime) + "ms");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test1();
        test2();
        test3();
    }

}

反射操作泛型

Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
.
为了通过反射操作这些类型,Java新增了ParameterizedType , GenericArrayType ,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型.
.
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType :表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable :是各种类型变量的公共父接口
WildcardType :代表一种通配符类型表达式

//通过反射获取泛型参数信息
public class test5 {

    public void test1(Map<String,User> map, List<User> list){
        System.out.println("test1");
    }

    public Map<String,User> test2(){
        System.out.println("test2");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        //获得第一个方法
        Method method = test5.class.getMethod("test1", Map.class, List.class);

        //通过方法获得参数类型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        //循环输出
        for (Type genericParameterType : genericParameterTypes) {
            //输出的是类
            System.out.println(genericParameterType);
            //便利genericParameterType获取参数类型
            if (genericParameterType instanceof ParameterizedType){
                //getActualTypeArguments获得真实参数类型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }

        System.out.println("--------------------------------------------");
        //获得第二个方法
        method = test5.class.getMethod("test2",null);
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType){
            //getActualTypeArguments获得真实参数类型
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Andrew0219

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

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

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

打赏作者

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

抵扣说明:

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

余额充值