Java中的反射

  反射,也可以称为反向获取,在一个程序的运行时,我们可以获取任意一个类的所有方法和属性,同样也可以调用任意一个对象的所有方法和属性。反射应用在一些通用性较高的代码,后面的框架大多数就是用反射来实现的。

一、反射的原理

  • 首先需要把Java文件保存到本地磁盘
  • 编译Java文件,生成.class文件
  • 使用JVM运行,把class文件通过类加载到内存中,再执行
  • class文件在内存中使用Class对象存储

当使用反射的时候,首先需要获取到Class对象,得到这个对象之后,就可以得到class文件里面的所有内容,包含属性,构造方法,普通方法

  • 属性通过一个类Filed
  • 构造方法通过一个类Constructor
  • 普通方法通过一个类Method


    反射的原理

二、获取Class对象

  上面我们说,使用反射的时候,首先要获取类的对象,这是反射的前提。获取类的对象有三种方法:
  1、通过对象的getClass()方法获取,必须要有对象
  2、通过类名.class创建类的对象
  3、调用Class类中的forName()方法,获取类的对象,这种方法最常用

  • 学生类
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

}
  • 测试类
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //方法一:创建类的对象,调用getClass()方法
        Student s = new Student();
        Class clazz1 = s.getClass();
        //输出类的对象,会得到类所在位置的全路径
        System.out.println(clazz1);
        
        //方法二:通过类名.class创建类的对象
        Class clazz2 = Student.class;
        System.out.println(clazz2);
        
        //方法三:调用Class类中的forName()方法获取类的对象,传入的参数必须是类的全路径,需要抛出异常
        Class clazz3 = Class.forName("com.itheima.review01.Student");
        System.out.println(clazz3);
    }

}

三、获取类中的构造方法并使用

  我们获取到类的对象以后,就可以获取类中的所有内容了。首先我们来获取构造方法,有了构造方法后,我们就可以创建对象,然后就可以调用属性和方法。

1、获取构造方法

获取构造方法的方式有两种:
  Constructor<?>[] getConstructors():获取所有public修饰的构造方法
  Constructor<T> getConstructor(Class<?>... parameterTypes):获取带参的构造方法,如果没有参数,则获取的是无参的构造方法

2、使用构造方法

  T newInstance(Object... initargs): 供Constructor创建对象使用,括号内填写构造方法的参数。

3、案例

import java.lang.reflect.Constructor;

public class ReflectDemo2 {
    public static void main(String[] args) throws ReflectiveOperationException {
        Class clazz = Class.forName("com.itheima.review01.Student");
        //获取构造方法
        //方法一
        Constructor[] cs = clazz.getConstructors();
        for (Constructor constructor : cs) {
            //输出构造方法
            System.out.println(constructor);
        }
        
        //方法二
        //获取无参构造:
        Constructor c1 = clazz.getConstructor();
        System.out.println(c1);
        //获取有参构造,括号内是参数的类的对象
        Constructor c2 = clazz.getConstructor(String.class,int.class);
        System.out.println(c2);
        
        //使用构造方法
        Object obj1 = c1.newInstance();
        System.out.println(obj1);//Student类中重写了toString()方法,Student [name=null, age=0]
        
        Object obj2 = c2.newInstance("张三",20);
        System.out.println(obj2);//Student [name=张三, age=20]
    }

}

四、获取属性并使用

1、获取属性

  获取属性的方法有四种:
  Field[] getFields():拿到类中所有的public修饰的字段对象
  Field getField(String name):根据字段名称获取指定的public修饰的字段对象
  Field[] getDeclaredFields():拿到类中所有的字段对象(私有也能拿到)
  Field getDeclaredField(String name):根据字段名称获取指定的字段对象(私有也能拿到)

2、获取和修改属性

  Object get(Object obj):获取指定对象中字段的值(需要传一个对象)
  void set(Object obj, Object value):修改指定对象中的值(需要传一个对象)

3、案例

import java.lang.reflect.Field;

public class ReflectDemo3 {
    public static void main(String[] args) throws ReflectiveOperationException {
        // 创建学生类的字节码对象
        Class clazz = Class.forName("com.itheima.review01.Student");
        // 创建学生类的对象
        Object obj = clazz.newInstance();
        // 获取学生类的属性
        Field f1 = clazz.getDeclaredField("name");
        Field f2 = clazz.getDeclaredField("age");

        // 设置反射时取消Java的访问检查(去除私有权限)
        f1.setAccessible(true);
        f2.setAccessible(true);
        
        //设置属性
        f1.set(obj, "张三");
        f2.set(obj, 20);
        
        //获取属性
        Object name = f1.get(obj);
        Object age = f2.get(obj);
        System.out.println(name);
        System.out.println(age);
    }

}

五、获取普通方法并使用

1、获取普通方法

  Method getMethod(String name, Class<?>... parameterTypes):拿到类里面的成员方法

2、使用普通方法

  Object invoke(Object obj, Object... args)

3、案例

public class ReflectDemo4 {
    public static void main(String[] args) throws ReflectiveOperationException {
        Class clazz = Class.forName("com.itheima.review01.Student");
        Object obj = clazz.newInstance();

        // 获取普通方法
        // 获取无参无返回值的方法并调用
        Method m1 = clazz.getMethod("method");
        m1.invoke(obj);

        // 获取有参无返回值的方法并调用
        Method m3 = clazz.getMethod("setName", String.class);
        m3.invoke(obj, "张三");

        // 获取无参有返回值的方法并调用
        Method m2 = clazz.getMethod("getName");
        Object name = m2.invoke(obj);
        System.out.println(name);

    }

}

六、补充

  创建一个ArrayList<Integer>的一个对象,如何添加一个字符串类型的数据?
  首先来简单介绍一下泛型:

  • Java泛型中的标记符含义:
      E - Element(在集合中使用,因为集合中存放的是元素)
      T - Type(Java类)
      K - Key(键)
      V - Value(值)
      N - Number(数值类型)

  • 泛型的三种
    [1]ArrayList<T> al = new ArraList<T>();
      指定集合元素只能是T类型
    [2]ArrayList<?> al = new ArraList<?>();
      指定集合元素可以使任何类型,这个声明没有任何意义
    [3]ArrayList<? extends E> al = new ArraList<? extends E>();
      ? extends E:接收E类型或者E的子类型
      ? super E:接收E类型或者E的父类型

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 什么是反射 反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型...
    黑心石阅读 1,525评论 0 2
  • 什么是反射 反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型...
    黑心石阅读 5,307评论 1 5
  • 从3.22开始至今的愚人节,沪市已在2000-3000点附近横盘整理近两周,宏观上看,基本处于一种弱势整理状态。 ...
    遁逸阅读 284评论 2 2
  • 1. 沉溺于「轻易获得高成就感」的事情:有意无意地寻求用很小付出获得很大「回报」的偏方,哪怕回报是虚拟的。这种行为...
    romangosu阅读 222评论 0 0
  • 一年,五年,还是十年。有一个人藏在我心里面,很轻也很重,像羽毛一样四处乱飞,飘来飘去,像石头一样沉甸甸地躺在那里,...
    飓风厄玛阅读 305评论 0 0