cnfox

Java反射机制-框架设计的灵魂
框架 既然反射机制是框架设计的灵魂,那我们就先简单说一下什么是框架:是一个半成品软件,框架中的代码已经...
扫描右侧二维码阅读全文
12
2019/09

Java反射机制-框架设计的灵魂

框架

 既然反射机制是框架设计的灵魂,那我们就先简单说一下什么是框架:是一个半成品软件,框架中的代码已经是软件的一部分,但因为是半成品所以不能独立运行,我们可以在框架的基础上进行软件开发;利用框架开发软件可以做到简化编码的作用.
 反射机制是框架设计的灵魂;其实我们在使用框架的时候,不会使用反射也没有关系,因为框架都为我们写好了;假如你要开发一套框架需要用到深入理解掌握反射机制
 但是!我们理解掌握了反射,在学习框架的时候就能用的更好,因为你知道了内部框架实现的一些原理,你也就能清晰的明白了,所以对于反射还是得重点的去掌握.

反射

  • 概念:将类的各个组成部分封装为其他对象,这就是反射机制

 概念是比较抽象的,让我来通俗易懂的语言来表述下:

 我们先忘记反射那个概念,然后我们聊一个你熟悉的东西:Java代码。运行Java代码可以通过一个Java类创建一个对象,这个过程是什么样子?也就是Java代码在计算机中经历的阶段

 Java代码从无到有到运行结束一共经历三个阶段:Source源代码阶段、Class类对象阶段、Runntime运行时阶段

第一阶段:Source源代码阶段

 这个阶段的大体过程是类文件(Person.java)中写一个类(public class Person),类中有成员变量、构造方法、成员方法,但是这样一个完整类文件还不能够直接运行,还需要一个编译的操作(javac)后形成一个字节码文件(Person.class).字节码文件中有三个比较重要的部分分别对应着Java类文件中的成员变量、构造方法、成员方法.源代码阶段的类文件和字节码文件并没有进内存,还是在硬盘上.这时候要是按照我们之前的做法,就是new一个Person对象,这就到了我们的第三阶段.

第二阶段:Class类对象阶段

 字节码文件要是能变成对象(对象在内存里),我们需要把字节码文件加载到内存中才能够有对象.第二阶段做的是一件非常重要的是事情就是把源代码阶段的Class文件通过类加载器(ClassLoader)加载进内存,在内存里会有一个对象(Class类对象)来描述Class字节码文件的共同的特征和行为.
 内存中的Class类对象也有比较重要的三部分(成员变量、构造方法、成员方法),每一部分又有各自的特点,比如说成员变成可以get set ,构造方法可以创建对象,成员方法可以来运行执行,所以将他们分别封装为 Field对象、Contructor对象、Method对象
通过Class类对象的行为我们就可以来创建对象(Person对象)

第三阶段:Runntime运行时阶段

 new对象

java代码三个阶段

 然后我们在回头看一下概念,就容易理解了,那反射机制有什么好处呢?

好处

  1. 可以在程序运行过程中,操作这些对象。
  2. 可以解耦,提高程序的可扩展性。

怎么理解程序运行中操作对象?

 我们在代码管理工具中新建一个类文件,定义一个字符串变量并赋值,然后我们用变量名加点的形式,代码管理工具就会提示我们很多方法

提示

 代码管理工具之所有可以提示那么多方法,其实内部就是利用的反射机制,我们定义了一个字符串,类加载器就会把这个字节码文件加载进内存,在内存中有一个Class类对象.Class类对象已经把所有的方法抽取出来封装成Method对象,然后把所有的方法都放进了一个Method[] 中,然后需要提示的时候,工具只需要遍历成员展示出来就可以了.

获取Class字节码对象的三种方式

 概念的解释是需要大量的语言去表述的,理解概念之后的操作就变得简单易懂起来,下面获取Class字节码对象我们就可以使用代码简单的体现下就可以啦,都是很好理解的.

  1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象 多用于配置文件,将类名定义在配置文件中。(第一阶段获取方式)
  2. 类名.class:通过类名的属性class获取 多用于参数的传递(第二阶段获取方式)
  3. 对象.getClass():getClass()方法在Object类中定义着 多用于对象的获取字节码的方式(第三阶段获取方式)

注意:
 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

package cn.icnfox.Java;

public class Person {

    private String name;
    private int age;
    
    public String sex;
    public String cn;
    
    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;
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", cn=" + cn + "]";
    }
        
        public void eat() {
        System.out.println("吃饭饭");
    }
    public void eat(String food) {
        System.out.println("吃饭饭"+food);
    }
}
package cn.icnfox.Java;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Test {

    public static void main(String[] args) throws Exception {
        
        //获取class 方法一  class.forname
        Class class1 = Class.forName("cn.icnfox.Java.Person");
        System.out.println(class1);
        
        //获取class 方法二  类名.class
        Class class2 =Person.class;
        System.out.println(class1==class2);

        //获取class 方法三  类名.getclass
        Person p = new Person();
        Class class3 =p.getClass();
        System.out.println(class1==class3);
    }
}
//运行结果
class cn.icnfox.Java.Person
true
true

使用Class对象

获取功能:

  • 获取成员变量们

    • Field[] getFields() :获取所有public修饰的成员变量
    • Field getField(String name) 获取指定名称的 public修饰的成员变量
    • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
    • Field getDeclaredField(String name)
package cn.icnfox.Java;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Test {

    public static void main(String[] args) throws Exception {
        //获取成员变量
        Field[] fields = class1.getFields();
        //遍历输出
        for (Field field : fields) {
            System.out.println(field);
        }
        
        //获取成员变量 sex
        Field sex = class1.getField("sex");
        //设置sex
        sex.set(p, "男");
        //获取sex
        Object value = sex.get(p);
        System.out.println(value);
        System.out.println("-----");
        
        Field[] fields2 = class1.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }
        
        Field dname = class1.getDeclaredField("name");
        //Class获取到私有变量,通过设置 setAccessible(true) 直接对私有变量进行getset操作为暴力反射
        dname.setAccessible(true);//暴力反射
        dname.set(p, "张三");
        System.out.println(p);
    }
}
//运行结果
public java.lang.String cn.icnfox.Java.Person.sex
public java.lang.String cn.icnfox.Java.Person.cn
男
-----
private java.lang.String cn.icnfox.Java.Person.name
private int cn.icnfox.Java.Person.age
public java.lang.String cn.icnfox.Java.Person.sex
public java.lang.String cn.icnfox.Java.Person.cn
Person [name=张三, age=0, sex=男, cn=null]
  • 获取构造方法们

    • Constructor<?>[] getConstructors()
    • Constructor getConstructor(类<?>... parameterTypes)
    • Constructor getDeclaredConstructor(类<?>... parameterTypes)
    • Constructor<?>[] getDeclaredConstructors()
package cn.icnfox.Java;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Test2 {

    public static void main(String[] args) throws Exception {

            Person p = new Person();
            Class class1 =p.getClass();
            System.out.println("--------1");
        //获取构造器数组
            Constructor[] constructors = class1.getConstructors();
            for (Constructor constructor : constructors) 
                {
            System.out.println(constructor); 
            }
            System.out.println("--------2");
        //获取构造器
            Constructor con= class1.getConstructor(String.class, int.class);
            System.out.println(con);
        //使用构造器创建对象
            Object Persont = con.newInstance("张三",21);
            System.out.println(Persont);
            System.out.println("--------3");
        //我们尝试下获取空参数构造器
        //获取空参数构造器
            Constructor con1= class1.getConstructor();
            System.out.println(con1);
        //使用构造器创建对象
            Object Persont1 = con1.newInstance();
            System.out.println(Persont1);
            System.out.println("--------4");
        //空参数构造可以简化成一下代码    
            Object Person2 = class1.newInstance();
            System.out.println(Person2);
            
        //其他的获取就不挨个演示了
        //con1.setAccessible(true); 也有暴力反射
    }
}
//运行结果
--------1
public cn.icnfox.Java.Person(java.lang.String,int)
public cn.icnfox.Java.Person()
--------2
public cn.icnfox.Java.Person(java.lang.String,int)
Person [name=张三, age=21, sex=null, cn=null]
--------3
public cn.icnfox.Java.Person()
Person [name=null, age=0, sex=null, cn=null]
--------4
Person [name=null, age=0, sex=null, cn=null]
  • 获取成员方法们

    • Method[] getMethods()
    • Method getMethod(String name, 类<?>... parameterTypes)
    • Method[] getDeclaredMethods()
    • Method getDeclaredMethod(String name, 类<?>... parameterTypes)
  • 获取全类名

    • String getName()
package cn.icnfox.Java;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test3 {

    public static void main(String[] args) throws Exception {

            Person p = new Person();
            Class class1 =p.getClass();
            System.out.println("--------1");
            //获取方法无参
            Method method = class1.getMethod("eat");
            //执行方法
            Person p1= new Person();
            method.invoke(p1);
            
            //获取方法有参
            Method method2 = class1.getMethod("eat",String.class);
            //执行方法
            method2.invoke(p1,"和肉肉");
            System.out.println("--------2");
            
            //获取所有方法 此处会打印出object的方法
            Method[] methods = class1.getMethods();
            for (Method method3 : methods) {
                System.out.println(method3);
                //获取方法名
                String name = method3.getName();
                System.out.println(name);
                //method3.setAccessible(true);支持暴力反射
            }
            //获取类名
            System.out.println("--------3");
            String name2 = class1.getName();
            System.out.println(name2);
            
    }
}
//运行结果
--------1
吃饭饭
吃饭饭和肉肉
--------2
public java.lang.String cn.icnfox.Java.Person.toString()
toString
public java.lang.String cn.icnfox.Java.Person.getName()
getName
public void cn.icnfox.Java.Person.setName(java.lang.String)
setName
public void cn.icnfox.Java.Person.eat()
eat
public void cn.icnfox.Java.Person.eat(java.lang.String)
eat
public int cn.icnfox.Java.Person.getAge()
getAge
public void cn.icnfox.Java.Person.setAge(int)
setAge
public final void java.lang.Object.wait() throws java.lang.InterruptedException
wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
wait
public boolean java.lang.Object.equals(java.lang.Object)
equals
public native int java.lang.Object.hashCode()
hashCode
public final native java.lang.Class java.lang.Object.getClass()
getClass
public final native void java.lang.Object.notify()
notify
public final native void java.lang.Object.notifyAll()
notifyAll
--------3
cn.icnfox.Java.Person
Last modification:September 13th, 2019 at 12:56 am
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment