zoukankan      html  css  js  c++  java
  • 反射

    1java代码的阶段

    一段java代码在程序运行期间会经历三个阶段: source-->class-->runtime

     

    2) Class 对象

    java中用一个Class对象来表示一个java类的class阶段

    Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等

    获得class对象的三种方式和区别

    // 1. 根据给定的类名来获得  用于类加载

    String classname = "cn.itcast.reflect.Person"; // 来自配置文件

    Class clazz = Class.forName(classname); // 此对象代表Person.class

     

    // 2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型

    Object obj = new Person();

    Class clazz1 = obj.getClass(); // 获得对象具体的类型

     

    // 3. 如果是明确地获得某个类的Class对象  主要用于传参

    Class clazz2 = Person.class;

    // java中所有的类型都会对应一个Class对象 int Integer

    Class intClazz = int.class;

    Class intarrClazz = int[].class;

    Class voidClazz = void.class;

     

    3)反射

    反射就是获得一个java类的各个组成部分

    // 反射类的成员方法

    Class clazz = Person.class;

    Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

    method.invoke();

     

    // 反射类的构造函数

    Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

    con.newInstance(params...)

     

    // 反射类的属性

    Field field = clazz.getField(fieldName);

    field.setAccessible(true);

    field.setObject(value);

     

    4) 反射用在哪里

    到底框架是什么?  框架就是将开发中大量重复的代码集中起来写个通用的程序

    框架就是用反射来实现的

    框架需要现在的类调用将来写的类

     

    框架是将来的程序员调用的,框架不能实现完整的功能,框架只是一些一些通用的代码

    框架要运行一定会依赖将来写的类

    现在写的类要调用将来写的类,我们先针对接口进行调用,将来的类需要实现接口,那么方法就固定了

    但是将来写的类的类名我们无法获知,这时就需要调用者通过配置文件告诉框架具体的类名

     

    1. 理解Class

       对象都是根据类创建出来的—>创建一个对象代表李四这个人—>李四(跑起来)

    Person.class(描述所有和李四类似的事物的信息à Person对象 à 李四(赵六、王五)

    Class.class(描述字节码这类事物的特征–> Class对象—> Person.class字节码(Student.class Boy.class String.class)

     

    所有的Person对象能做的事情都用方法来描述,例如跑步用run方法描述

    所有的Class对象(字节码)能做的事情用方法来描述,例如创建对象用newInstance来描述

     

    2. 通过反射获得Class对象

    三种方式获得

    // 1. 根据给定的类名来获得

    String methodname = "run";

    String classname = "cn.itcast.reflect.Person"; // 来自配置文件

    Class clazz = Class.forName(classname); // 此对象代表Person.class

    Object obj = clazz.newInstance(); // 创建对象

     

     

    // 2. 如果拿到了对象,不知道是什么类型

    Object obj = new Person();

    Class clazz1 = obj.getClass(); // 获得对象具体的类型

     

    // 3. 如果是明确地获得某个类的Class对象

    Class clazz2 = Person.class; // 主要用于传参

     

    // java中所有的类型都会对应一个Class对象 int Integer

    Class intClazz = int.class;

    Class intarrClazz = int[].class;

    Class voidClazz = void.class;

     

    3. 反射能做什么事情

    // 调用任何一个对象的任何方法

    // 读取配置文件获得如下信息

    String classname = "cn.itcast.reflect.Student";

    String methodname = "study";

     

     

    // Personrun方法调用

    // 1.创建Person对象

    Class clazz = Class.forName(classname); // 此对象代表Person.class

    Object obj = clazz.newInstance(); // 创建对象

    // 2.获得表示run方法的对象

    Method runMethod = clazz.getMethod(methodname);

    // 3.通过Person对象来调用run方法

     

    4. 通过反射获得类的成员变量

    // 获得代表某个属性的Field对象

    Class clazz = Person.class;

     

    Field[] fields = clazz.getDeclaredFields();

    for(Field field : fields) {

    String name = field.getName(); // 获得属性名

    Class type = field.getType(); // 获得属性的类型

    System.out.println("属性名:" + name + "属性类型:" + type);

    }

     

    // 获得对象的某个指定的属性,并为该属性赋值

    // 明确告诉你,获得name属性

    String fieldname = "name";

    Object obj = new Person();

     

    // 1. 获得Class对象()

    Class clazz1 = obj.getClass();

    // 2. 获得指定的属性

    Field nameField = clazz1.getDeclaredField(fieldname);

    // 3. 为属性赋值

    // 私有属性不行,因为java虚拟机会检查访问权限

    // 如果一定要访问,就需要取消java访问检查

    nameField.setAccessible(true);

    nameField.set(obj, "zhangsan");

    /*

    Person p = (Person) obj;

    System.out.println(p.getName());*/

    Object value = nameField.get(obj); // 获得指定对象上该字段的值

    System.out.println(value);

    5. 通过反射获得类的构造方法

    // 获得类

    Class clazz = Person.class;

     

    // 获得类的所有构造函数

    Constructor[] constructors = clazz.getConstructors();

    for(Constructor con : constructors) {

    // 遍历参数类型

    Class[] parameterTypes = con.getParameterTypes();

    for(Class type : parameterTypes)

    System.out.print(type.getName() + "   ");

    System.out.println();

    }

     

    // 获得指定的构造函数,创建对象

    // 要求调用参数为 String int 的构造函数

    // 1. 反射出指定的构造函数

    Constructor con = clazz.getConstructor(String.class, int.class);

    // 2. 调用构造函数创建对象

    Object obj = con.newInstance("wangwu", 23);

    System.out.println(obj); // toString

    6. 通过反射获得类的成员方法

    Class clazz = Person.class;

     

    // 获得类的所有方法

    Method[] methods = clazz.getDeclaredMethods();

    for(Method m : methods) {

    String name = m.getName(); // 方法名

    System.out.print("方法名:" + name);

    // 参数类型

    System.out.print(", 参数类型依次为:");

    Class[] types = m.getParameterTypes();

    for(Class type : types)

    System.out.print(type.getName() + "  ");

    // 返回值类型

    Class returnType = m.getReturnType();

    System.out.print(",返回值类型:" + returnType.getName());

    System.out.println();

    }

     

    // 反射出指定的方法,调用

    // 创建一个对象

    Object obj = clazz.newInstance();

    // 调用play方法

    Method playMethod = clazz.getMethod("play", String.class);

    playMethod.invoke(obj, "zhangsan");

    // 调用eat方法

    Method eatMethod = clazz.getMethod("eat");

    eatMethod.invoke(null);

    // 调用sleep方法

    Method sleepMethod = clazz.getMethod("sleep", String[].class);

    String[] arr = {"a","b"};

    sleepMethod.invoke(obj, (Object)arr); // 符合1.41.5的语法

     

    // 什么情况下用哪个?

    // 1. 如果我们需要加载一个类

    Class.forName("cn.itcast.reflect.Person"); // 去加载一个类

    // 2. 如果我们要判断一个对象的类型

    Object obj = new Person();

     

    // 判断obj对象是不是Person类型对象

     

    if(obj.getClass() == Person.class)

    System.out.println("是一个Person对象");

    else

    System.out.println("不是一个Person对象");

     

     

    obj = new Student();

    // 把子类当做父类来用,不能调用子类的方法,此时需要强转

    // 强转之前需要判断类型

    // instanceof 判断对象是否实现了指定的接口(或继承了指定的类)

    if(obj instanceof Person) {

    Person p = (Person) obj;

    p.run();

    }

     

    // 3. 如果我们在调用方法时,方法需要的参数是Class类型,

    doXX(Person.class);

  • 相关阅读:
    Spring Boot配置过滤器的两种方式
    Redis工具类封装RedisUtils
    Android_开机动画
    Android_OTA升级
    QT_学习笔记
    松翰单片机_SN8F570310——ADC
    全志_基于dts设备树驱动开发
    松翰单片机_SN8F570310
    松翰单片机_SN8F570310——GPIO
    松翰单片机_SN8F570310——COM & OPA
  • 原文地址:https://www.cnblogs.com/qq809306794/p/3183193.html
Copyright © 2011-2022 走看看