Java中的反射机制

时光怂恿深爱的人放手 提交于 2019-12-10 20:24:20

在学习反射机制之前我们先学习一下什么是动态语言和静态语言?
(1)动态语言

是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被 引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代 码可以根据某些条件改变自身结构。
主要动态语言:Object-C、C#、JavaScript、PHP、Python等。

(2)静态语言

与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。
Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性, 我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更 加灵活!

1.反射的基本概念

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

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

(3)Java反射的优缺点
优点:

可以实现动态创建对象和编译,体现出很大的灵活性

缺点:

 对性能有影响。
 使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望 做什么并且它满足我们的要求。这类操作总是慢于 直接执行相同的操作。 

(4)一个类加载的任务
当我们第一次使用一个类,该类会被加载,系统会做两件事:
    <1> 该类的字节码文件会被加载到内存中,形成一个类加载区(方法区)
    <2> 会为这个字节码文件创建一个Class对象
(5)反射的使用步骤

在这里插入图片描述
(6)java内存分析图
在这里插入图片描述

2.Class类

(1)Class类的方法

Class类的常用方法 功能
static ClassforName(String name) 返回指定类名name的Class对象
Object newInstance() 调用缺省构造函数,返回Class对象的一个实例
getName() 返回此Class对象所表示的实体(类,接口,数组类 或void)的名称。
Class getSuperClass() 返回当前Class对象的父类的Class对象
Class[] getinterfaces() 获取当前Class对象的接口
ClassLoader getClassLoader() 返回该类的类加载器
Method getMothed(String name,Class… T) 返回一个Method对象,此对象的形参类型为 paramType
Field[] getDeclaredFields() 返回Field对象的一个数组

(2)获取Class对象的方式

  • 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
Class class3 = Student.class;
  • 已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class class1 = person.getClass();
  • 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获- 取, 可能抛出ClassNotFoundException
Class class2 = Class.forName("com.kuang.reflection.Student");
  • 内置基本数据类型可以直接用类名.Type
Class type = Integer.TYPE;
  • 还可以利用ClassLoader

(3)获取一个类的构造器
获取所有的构造器包括父类子类

Constructor[] constructors = class1.getConstructors();  //获得所有public的构造器包括父类

获取本类的构造器

Constructor[] constructors2 = class1.getDeclaredConstructors();  //获得所有public的构造器

获取指定的构造器

Constructor constructor = class1.getConstructor(null);
Constructor constructor2 = class1.getConstructor(int.class,int.class,String.class);

(4)获取一个类的属性

Field[] fields = class1.getFields(); //只能获得public的属性
Field[] fields2 = class1.getDeclaredFields(); //返回全部的属性,可以获得私有的
Field name = class1.getDeclaredField("name"); //获取指定的字段!

(5)获取一个类的方法

Method[] methods = class1.getMethods(); //返回当前类和被继承的类的public方法
Method[] declaredMethods = class1.getDeclaredMethods(); //获得当前类的所有方法

参数1为方法名,参数2为类型

Method setName = class1.getMethod("setName",String.class);

(6)通过反射创建对象!执行方法,修改字段!

public class Test7 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("com.reflection.User");
        //创建对象,new  无参,有参!
        System.out.println("==========================================");
        User user1 = (User) c1.newInstance(); //创建对象!
        System.out.println(user1); //默认调用的是无参构造器,你们可以删掉无参试试!  new User();

        System.out.println("==========================================");
        //通过指定构造器创建对象! new User(1, 3, "reflection");
        Constructor declaredConstructor = c1.getDeclaredConstructor(int.class, int.class, String.class);
        User user2 = (User) declaredConstructor.newInstance(1, 3, "reflection");
        System.out.println(user2);

        System.out.println("==========================================");
        User user3 = (User) c1.newInstance();
         // user3.setName("刘恒"); 
        
        //1. 获得你要操作的方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //2. 通过invoke方法执行方法
        //一个class可能存在多个对象, 这个方法需要找到是那个对象使用的,给他赋值;
        setName.invoke(user3,"刘恒");
        System.out.println(user3.getName());
        //获得字段
        System.out.println("==========================================");
        User user4  = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name"); //反射无法直接破坏私有的
        //显示调用setAccessible为true,则可以访问private方法!
        name.setAccessible(true);
        name.set(user4,"恒哥");
        System.out.println(user4.getName());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!