java反射机制


参考: 狂神说java

1.什么是java反射

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制(java是静态语言)。反射被视为动态语言的关键。

2.Class类常用方法

常用方法举例

Class.forName("类"); //1.获取Class对象
getClass(); //2.获取Class对象
对象.class; //3.获取Class对象
newInstance(); //创建Class对象的一个实例
getName(); //Class对象对应的类名
getClassLoader(); //获取类加载器
getInterfaces(); //获取Class对象的接口
getSuperclass(); //获取Class对象父类Class对象
getConstructor(); //获取Constructor对象的数组
getMethods();//获取Class对象里的方法
getDeclaredFields(); //获取Class对象里的属性

3.类加载到初始化过程

在这里插入图片描述
在这里插入图片描述

双亲委派机制

类初始化的6种情况
(1)为一个类型创建一个新的对象实例时(比如new、反射、序列化)
(2)调用一个类型的静态方法时(即在字节码中执行invokestatic指令)
(3)调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时(即在字节码中,执行getstatic或者putstatic指令),不过用final修饰的静态字段除外,它被初始化为一个编译时常量表达式
(4)调用JavaAPI中的反射方法时(比如调用java.lang.Class中的方法,或者java.lang.reflect包中其他类的方法)
(5)初始化一个类的子类时(Java虚拟机规范明确要求初始化一个类时,它的超类必须提前完成初始化操作,接口例外)
(6)JVM启动包含main方法的启动类时。
数组本身并不是由类加载器负责创建,而是由JVM在运行时根据需要而直接创建的,但数组的元素类型仍然需要依靠类加载器去创建。

不进行类信息的初始化情况
1、通过类引用静态常量
在编译的时候,常量(static final 修饰的)会存入调用类的常量池【这里说的是main函数所在的类的常量池】,调用的时候本质上没有引 用到定义常量的类,而是直接访问了自己的常量池。

2、类引用静态变量的情况

  • 子类引用父类的静态变量会导致父类的类信息初始化,但是子类的类信息不进行初始化;
  • 子类引用自己的静态变量,会导致自己和父类的类信息都进行初始化

3、通过数组定义来引用类,不会触发此类的初始化
SubClass[] sca = new SubClass[10];

初始化情况参考:https://blog.csdn.net/l1394049664/article/details/81235456

4.动态创建对象

本案例在常用方法举例基础上创建

public class CreateUser  {
    public static void main(String[] args) throws Exception {
        //获得Class对象
        Class<?> c = Class.forName("com.cp.test.User");

        //构造一个对象
        System.out.println("========================构造一个对象==========================");
        User user1 = (User) c.newInstance(); //本质是调用了类的无参构造器
        System.out.println(user1.toString());

        //调用构造器创建对象
        System.out.println("=====================调用构造器创建对象========================");
        Constructor<?> constructor = c.getDeclaredConstructor(String.class, int.class, String.class, int.class);
        User user2 = (User) constructor.newInstance("chen", 12, "男", 1998);
        System.out.println(user2.toString());

        //通过反射调用普通方法
        System.out.println("=====================通过反射调用普通方法=======================");
        User user3 = (User) c.newInstance();
        Method setName = c.getDeclaredMethod("setName", String.class);
        setName.invoke(user3,"chen");
        System.out.println(user3.toString());

        //通过反射操作属性
        System.out.println("=======================通过反射操作属性=========================");
        User user4 = (User) c.newInstance();
        Field birthday = c.getDeclaredField("birthday");
        //不能直接操作私有属性,Accessible表示是否禁用安全检查
        birthday.setAccessible(true);
        birthday.set(user4,1995);
        System.out.println(user4.toString());
    }
}

控制台输出结果为:

========================构造一个对象==========================
User{name='null', age=0, sex='null', birthday=0}
=====================调用构造器创建对象========================
User{name='chen', age=12, sex='男', birthday=1998}
=====================通过反射调用普通方法=======================
User{name='chen', age=0, sex='null', birthday=0}
=======================通过反射操作属性=========================
User{name='null', age=0, sex='null', birthday=1995}

5.反射操作泛型

在这里插入图片描述

//通过反射操作泛型
public class Test2 {

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

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

    public static void main(String[] args) throws NoSuchMethodException {
        System.out.println("=======================================参数泛型======================================");
        Method method = Test2.class.getMethod("test01", Map.class, List.class);
        //获取方法参数中的所有泛型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("=============获取泛型=============");
            System.out.println(genericParameterType);
            //判断是否是参数化类型
            if (genericParameterType instanceof ParameterizedType) {
                //如果是参数化类型则强转成该类型,并获取真实类型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                System.out.println("真实类型:");
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }

        System.out.println("=======================================返回值泛型======================================");
        method = Test2.class.getMethod("test02", null);
        //获取方法返回值中的所有泛型
        Type genericParameterType = method.getGenericReturnType();
        System.out.println(genericParameterType);
        if (genericParameterType instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            System.out.println("真实类型:");
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}

控制台输出:

=======================================参数泛型======================================
=============获取泛型=============
java.util.Map<java.lang.String, com.cp.test.User>
真实类型:
class java.lang.String
class com.cp.test.User
=============获取泛型=============
java.util.List<com.cp.test.User>
真实类型:
class com.cp.test.User
=======================================返回值泛型======================================
java.util.Map<java.lang.String, com.cp.test.User>
真实类型:
class java.lang.String
class com.cp.test.User

6.反射操作注解

定义2个注解

@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TableName {
    String value();
}

@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface FieldName{
    String columnName();
    String type();
    int length();
}

定义实体类,使用上面定义的注解

@TableName("db_student")
public class Student {

    @FieldName(columnName = "db_id",type = "int", length = 10)
    private int id;
    @FieldName(columnName = "db_age",type = "int", length = 10)
    private int age;
    @FieldName(columnName = "db_name",type = "String", length = 5)
    private String name;

    public Student() {
    }

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

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

    public int getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

通过反射获取注解

public class Test3 { 
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> c = Class.forName("com.cp.test.Student");

        //通过反射获得注解
        System.out.println("=======================通过反射获得注解======================");
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的value
        System.out.println("=======================获得注解的value======================");
        TableName annotation = c.getAnnotation(TableName.class);
        String value = annotation.value();
        System.out.println(value);

        //获得类指定的注解
        System.out.println("=======================获得指定注解======================");
        Field name = c.getDeclaredField("name");
        FieldName annotation1 = name.getAnnotation(FieldName.class);
        System.out.println(annotation1.columnName());
        System.out.println(annotation1.type());
        System.out.println(annotation1.length());
    }
}

控制台输出结果

=======================通过反射获得注解======================
@com.cp.test.TableName(value=db_student)
=======================获得注解的value======================
db_student
=======================获得指定注解======================
db_name
String
5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值