关闭

黑马程序员_反射

标签: 程序员动态
123人阅读 评论(0) 收藏 举报
分类:

——- android培训java培训、期待与您交流! ———-

简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,
那么就可以通过反射机制来获得类的所有信息。

一、
1. JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。

2.动态获取类中信息,就是java反射。可以理解为对类的解剖。

应用:如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。

二、所谓的框架就是对外提供一些接口,由实现类按照这个接口标准去实现。框架内部如果需要操纵这些实现类的对象完成某些操作,那么只需要把这些实现类的全名(包名+类名)写在某个配置文件中,框架代码只需要读取这个配置文件,就可以获取这个实现类的字节码文件,然后利用反射技术创建这个实现类的对象并且调用相应的方法完成一些操作。
用于描述字节码的类就是Class类,创建对象,可以提取字节码文件中的内容,如字段、构造函数、一般函数。该类就可以获取字节码文件中的所有内容,那么反射就是依靠该类完成的。想要对一个类文件进行解剖,只要获取到该类的字节码文件对象即可。

示例:
一、获取字节码文件对象的3种方式

package cn.itcast.bean;

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

    public Person(int age,String name){
                super();
                this.age = age;
                this.name = name;

                System.out.println("Person param run..." + this.name + ":" + this.age);
        }

        public Person(){
                super();

                System.out.println("person run");
        }

        public void show(){
                System.out.println(name + "...show run..." + age);
        }

        private void privateMethod(){
                System.out.println("method run");
        }

        public void paramMethod(String str,int num){
                System.out.println("paramMethod run..." + str + ":" + num);
        }

        public static void staticMethod(){
                System.out.println("static method run...");
        }
}
import cn.itcast.bean.Person;

//要想要对字节码文件进行解剖,必须要有字节码文件对象。
public class ReflectDemo
{
        public static void main(String[] args) throws ClassNotFoundException {
                getClassObject_1();
                System.out.println("--------------------");
                getClassObject_2();
                System.out.println("--------------------");
                getClassObject_3();
        }

   /*
        * 获取字节码对象的方式:
        * 方式一:Object类中的getClass()方法的。
        * 想要用这种方式,必须要明确具体的类,并创建对象。
        * 麻烦。
        */
        public static void getClassObject_1(){

                Person p = new Person();
                Class clazz = p.getClass();

                Person p1 = new Person();
                Class clazz1 = p1.getClass();

                System.out.println(clazz == clazz1);
        }

        /*
        * 方式二:任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。
        * 相对简单,但是还是要明确用到类中的静态成员。
        * 还是不够扩展。
        */
        public static void getClassObject_2(){

                Class clazz = Person.class;
                Class clazz1 = Person.class;

                System.out.println(clazz == clazz1);
        }

        /*
        * 方式三:只要通过给定的类的字符串名称就可以获取该类,更为扩展。
        * 可以用Class类中的方法完成。
        * 该方法就是forName。
        * 这种方法只要有名称即可,更为方便,扩展性更强。
        */
        public static void getClassObject_3() throws ClassNotFoundException {

                //可以把类的字符串名称写到配置文件中,然后读取出来。
                String className = "cn.itcast.bean.Person";
                Class clazz = Class.forName(className);

                System.out.println(clazz);
        }
}

二、获取class中的构造函数

import cn.itcast.bean.Person;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo
{
        public static void main(String[] args) throws Exception {
                createNewObject_1();
                System.out.println("--------------------");
                createNewObject_2();
        }

        public static void createNewObject_1() throws ClassNotFoundException,InstantiationException,IllegalAccessException {
                //早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
                //并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象。
                //Person p = new Person();

                //现在:
                String name = "cn.itcast.bean.Person";
                //找寻该文件类文件,并加载进内存,并产生Class对象。
                Class clazz = Class.forName(name);
                //如何产生该类的对象呢?
                Object obj = clazz.newInstance();//调用Person的空参构造函数
        }

        public static void createNewObject_2() throws ClassNotFoundException,InstantiationException,NoSuchMethodException,IllegalAccessException,InvocationTargetException {

                //Person p = new Person("小强",39);

                /*
                * 当获取指定名称对应类中的所体现的对象时。
                * 而该对象初始化不使用空参数构造函数该怎么办呢?
                * 既然是通过指定的构造函数进行对象的初始化。
                * 所以应该先获取到该构造函数,通过字节码文件对象即可完成。
                * 该方法是:getConstructor(parameterTypes);
                */

                String name = "cn.itcast.bean.Person";
                //找寻该名称类文件,并加载进内存,并产生Class对象。
                Class clazz = Class.forName(name);
                //获取到了指定的构造函数对象
                Constructor constructor = clazz.getConstructor(int.class,String.class);
                //通过该构造器对象的newInstance方法进行对象的初始化。
                Object obj = constructor.newInstance(38,"小明");
        }
}

三、获取class的字段

import cn.itcast.bean.Person;
import java.lang.reflect.Field;

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

        /*
        * 获取字节码文件中的字段。
        */
        public static void getFieldDemo() throws Exception {

                Class clazz = Class.forName("cn.itcast.bean.Person");

                //getField只能获取所有可访问公共字段,private获取不到。
                //Field field = claszz.getField("age");

                //getDeclaredField可以获取到公共字段,也可以获取到私有字段。
                Field field = clazz.getDeclaredField("age");

                //对私有字段的访问取消权限检查,暴力访问。
                field.setAccessible(true);

                Object obj = clazz.newInstance();

                //为对象的属性赋值
                field.set(obj,89);

                //获取某对象的某属性值
                Object o = field.get(obj);

                System.out.println(field);
        }
}

四、获取class中的方法

import cn.itcast.bean.Person;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;

public class ReflectDemo
{
        public static void main(String[] args) throws Exception {
                getMethodDemo_1();
                System.out.println("---------------------------");
                getMethodDemo_2();
                System.out.println("---------------------------");
                getMethodDemo_3();
        }

        /*
        * 获取指定Class中的公共函数。
        */
        public static void getMethodDemo_1() throws Exception {

                Class clazz = Class.forName("cn.itcast.bean.Person");

                Method[] methods = clazz.getMethods();//获取的都是公有的方法

                methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包括私有。

                for(Method method : methods){
                        System.out.println(method);
                }
        }

        public static void getMethodDemo_2() throws Exception {

                Class clazz = Class.forName("cn.itcast.bean.Person");

                Method method = clazz.getMethod("show",null);//获取空参数一般方法

                Object obj = clazz.newInstance();

                Constructor constructor = clazz.getConstructor(int.class,String.class);
                obj = constructor.newInstance(37,"小明");

                method.invoke(obj,null);
        }

        public static void getMethodDemo_3() throws Exception {

                Class clazz = Class.forName("cn.itcast.bean.Person");

                Method method = clazz.getMethod("paramMethod",String.class,int.class);//获取空参数一般方法

                Object obj = clazz.newInstance();

                Constructor constructor = clazz.getConstructor();
                obj = constructor.newInstance();

                method.invoke(obj,"小强",89);
        }
}

类的生命周期

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前

链接就是把二进制数据组装为可以运行的状态。

链接分为校验,准备,解析这3个阶段

校验一般用来确认此二进制文件是否适合当前的JVM(版本),

准备就是为静态成员分配内存空间,。并设置默认值

解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。

当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

目前我所理解的反射机制,是可以让我们编写的代码更加灵活,当编写的代码的某部分模块需要更改或者需要挂载新的模块的时候,源程序可以具备更好的兼容性和灵活性。

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3007次
    • 积分:282
    • 等级:
    • 排名:千里之外
    • 原创:26篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档