JavaDay5——注解和反射

本文深入探讨了Java中的类加载过程,包括加载、连接和初始化,并详细介绍了类加载器的层级结构。接着,文章阐述了反射机制的概念,展示了如何获取和操作类、对象的构造方法、成员变量和方法。通过实际代码示例,演示了如何利用反射创建对象、调用私有构造器和成员变量,以及越过泛型检查。最后,文章通过读取配置文件动态执行指定类的方法,展示了反射在实际应用中的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、类加载器
1.1类加载
当你需要使用某个类的时候,但是这个类还没有被加载到内存中,系统会通过类的加载,连接,初始化三个步骤对要加载的类进行初始化,这三个步骤也被统称为类加载或类的初始化
1.2类加载器
作用:负责将.class文件加载到内存中,并与之生成对应的java.lang.class对象
三种类加载器关系:Bootstrap class loader>Platform class loader>System class loader

public static void main(String[] args) {
        //getSystemClassLoader();Returns the system class loader.
        ClassLoader c=ClassLoader.getSystemClassLoader();
        System.out.println(c);//AppClassLoader
        //getPlatformClassLoader();Returns the platform class loader.
        ClassLoader c1 = ClassLoader.getPlatformClassLoader();
        System.out.println(c1);//PlatformClassLoader
        //	getParent();Returns the parent class loader for delegation.
        ClassLoader c2 = c1.getParent();
        System.out.println(c2);//null c2的类加载器是BootStrap。
        // It is the virtual machine's built-in class loader, typically represented as null, and does not have a parent.


    }

2、反射
什么是反射?
反射是可以获得任意一个类中的所有属性和方法,对于任意一个对象都能调用它的属性和方法。这种动态获取信息以及动态的获取类的属性和方法被称为Java的反射机制。
怎么反射?
对于要获取的字节码文件对象(.class)使用Class类中的方法,所以要获取每一个字节码文件的class对象。
怎么获取字节码文件对象?
有三种方法:1、直接.class获取该类的Class对象。
2、调用类的.getClass()方法获取Class对象
3、使用Class类中的静态方法forName(String className) 其中className是全限定名。

public static void main(String[] args) throws ClassNotFoundException {
        /*
        * 三种获取字节码文件对象
        * */
        //1、直接.class获取该类的Class对象。
        Class<student> c1 = student.class;
        System.out.println(c1);
        //2、调用类的.getClass()方法获取Class对象
        student s = new student();
        Class<? extends student> c2 = s.getClass();
        System.out.println(c2);
        //3、使用Class类中的静态方法forName(String className) 其中className是全限定名。
        Class<?> c3 = Class.forName("com.jackly.main.ch14.student");
        System.out.println(c3);
    }

从字节码文件获取构造方法的几个方法

 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        /*
        * 几个获取构造方法的方法
        * */
        Class<?> c = Class.forName("com.jackly.main.ch14.student");
        //Constructor<?>[]	getConstructors()返回一个数组,该数组包含Constructor反映此Class对象表示的类的所有公共构造函数的 对象。
//        Constructor<?>[] cons = c.getConstructors();
        //Constructor<?>[]	getDeclaredConstructors()返回一个Constructor对象数组,反映由该Class对象表示的类声明的所有构造 函数。
//        Constructor<?>[] cons = c.getDeclaredConstructors();
//        for (Constructor con:cons){
//            System.out.println(con);
//        }
        //Constructor<T>	getConstructor​(Class<?>... parameterTypes)返回一个Constructor对象,该对象反映此Class 对象表示的类的指定公共构造函数。
//        Constructor<?> cons = c.getConstructor();
        //Constructor<T>	getDeclaredConstructor​(Class<?>... parameterTypes)
        //返回一个Constructor对象,该对象反映此Class对象表示的类或接口的指定构造 函数。
//        Constructor<?> cons = c.getDeclaredConstructor();
//        System.out.println(cons);
    }

反射练习 1:student s = new student(“张三”,20,“西安”); System.out.println(s); 转换为反射机制输出

/*
        *   student s = new student("张三",20,"西安");
            System.out.println(s);
          转换为反射机制
        * */
        //获取student类的字节码文件对象
        Class<?> c = Class.forName("com.jackly.main.ch14.student");
        //获取带参构造函数
        Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
        //传入数据
        Object obj = con.newInstance("张三", 20, "西安");
        System.out.println(obj);

反射练习2:student s = new student(“张三”); System.out.println(s); 使用反射机制

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        /*
        student s = new student("张三");
        System.out.println(s);
        使用反射机制
        */
        Class<?> c = Class.forName("com.jackly.main.ch14.student");
        Constructor<?> con = c.getDeclaredConstructor(String.class);
        //私有成员变量不能直接被访问,但是可以通过暴力反射
        //public void setAccessible​(boolean flag):值为true的时候取消访问检查
        con.setAccessible(true);
        Object obj = con.newInstance("张三");
        System.out.println(obj);
    }

成员变量的反射4种方法:
1、Field[] getFields()
返回一个数组,该数组包含Field反映此Class对象表示的类或接口的所有可访问公共字段的对象。
2、Field getField​(String name)
返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定公共成员字段。
3、Field[] getDeclaredFields()
返回一个Field对象数组,反映由该Class对象表示的类或接口声明的所有字段 。
4、Field getDeclaredField​(String name)
返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定声明字段。

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        /*
        * 获取类文件内的成员变量4种方法
        * */
        //获取字节码文件对象
        Class<?> c = Class.forName("com.jackly.main.ch14.student");
        //Field[]	getFields()
        //返回一个数组,该数组包含Field反映此Class对象表示的类或接口的所有可访问公共字段的对象。
//        Field[] fields = c.getFields();
        //Field[]	getDeclaredFields()
        //返回一个Field对象数组,反映由该Class对象表示的类或接口声明的所有字段 。
        Field[] fields = c.getDeclaredFields();
        for (Field field:fields){
        System.out.println(field);}
        System.out.println("--------");
        //Field	getField​(String name)
        //返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定公共成员字段。
        Field af = c.getField("address");
        System.out.println(af);
        //Field	getDeclaredField​(String name)
        //返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定声明字段。
        Field nf = c.getDeclaredField("name");
        System.out.println(nf);
        //获取无参构造函数
        Constructor<?> con = c.getDeclaredConstructor();
        con.setAccessible(true);
        Object obj = con.newInstance();
        //AField提供有关类或接口的单个​​字段的信息和对其的动态访问。反射字段可以是类(静态)字段或实例字段。
        //void	set​(Object obj, Object value)
        //Field将指定对象参数上此对象表示的字段设置为指定的新值。
        af.set(obj,"西安");
        nf.setAccessible(true);//暴力反射
        nf.set(obj,"李四");
        System.out.println(obj);
    }

反射类中的4种方法:
1、Method[] getMethods()
返回一个数组,该数组包含Method反映此 Class对象表示的类或接口的所有公共方法的对象,包括由类或接口声明的方法以及从超类和超接口继承的方法。(返回的不仅仅是自己定义的公共方法)
2、Method[] getDeclaredMethods()
返回一个数组,其中包含Method反映此 Class对象表示的类或接口的所有声明方法的对象,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。
3、Method getMethod​(String name, Class<?>… parameterTypes)
返回一个Method对象,该对象反映此Class对象表示的类或接口的指定公共成员方法 。
4、Method getDeclaredMethod​(String name, Class<?>… parameterTypes)
返回一个Method对象,该对象反映此Class对象表示的类或接口的指定声明方法 。

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        /*
        * 获取成员变量中的方法
        * */
        Class<?> c = Class.forName("com.jackly.main.ch14.student");
        //Method[]	getMethods()
        //返回一个数组,该数组包含Method反映此 Class对象表示的类或接口的所有公共方法的对象,包括由类或接口声明的方法以及从超类和超接口继承的方法。
//        Method[] methods = c.getMethods();
        //Method[]	getDeclaredMethods()
        //返回一个数组,其中包含Method反映此 Class对象表示的类或接口的所有声明方法的对象,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。
        Method[] methods = c.getDeclaredMethods();
        for (Method method:methods){
            System.out.println(method);
        }
        System.out.println("------");
        //Method	getMethod​(String name, Class<?>... parameterTypes)
        //返回一个Method对象,该对象反映此Class对象表示的类或接口的指定公共成员方法 。
        Constructor<?> cons = c.getDeclaredConstructor();
        Method method1 = c.getMethod("method2", String.class);
        Object obj = cons.newInstance();
        //Object invoke​(Object obj, Object... args)
        //在Method 具有指定参数的指定对象上调用此对象表示的基础方法。
        //Obj:返回类型
        //obj:指定对象
        //args:方法参数
        //public void method1()
        method1.invoke(obj,"李四");
        System.out.println(obj);
        //Method	getDeclaredMethod​(String name, Class<?>... parameterTypes)
        //返回一个Method对象,该对象反映此Class对象表示的类或接口的指定声明方法 。
//        Method m = c.getDeclaredMethod("function");
//        Object obj = cons.newInstance();
//        m.setAccessible(true);//暴力反射
//        m.invoke(obj);
//        System.out.println(obj);
    }

反射练习1、越过泛型检查
* 题目:ArrayList 泛型集合添加字符串,如何实现?
* 思路:使用反射机制实现 获取

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        /*
        * 反射练习1、越过泛型检查
        * 题目:ArrayList<Integer> 泛型集合添加字符串,如何实现?
        * 思路:使用反射机制实现 获取
        * */
        ArrayList<Integer> array=new ArrayList<Integer>();
        array.add(10);
        Class<? extends ArrayList> c = array.getClass();
        Method m = c.getDeclaredMethod("add", Object.class);
        m.invoke(array,"hello");
        m.invoke(array,"world");
        System.out.println(array);
    }

反射练习2:运行配置文件指定内容
配置文件内容如下:

className=com.jackly.main.ch14.Student
methodName=study
 public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Properties prop = new Properties();
        FileReader fr = new FileReader("javaSEStudy_01\\src\\com\\jackly\\main\\ch14\\class.txt");
        prop.load(fr);
        fr.close();
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");
        Class<?> c = Class.forName(className);
        Constructor<?> cons = c.getDeclaredConstructor();
        Object obj = cons.newInstance();
        Method m = c.getMethod(methodName);
        m.invoke(obj);
    }
}
class Student{
    public void study(){
        System.out.println("好好学习天天向上");
    }
}
class Teacher{
    public void teach(){
        System.out.println("要好好学习呀");
    }
}

在写这段代码中遇到过一个问题:因为是在一个类里面写的Student和Teacher类,用的是默认修饰。在获取无参构造函数用的是getConstructor()获取的是公共的。报NoSuchMethodException异常,仔细看了代码才发现这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值