反射-Day13(2019/5/10)-JAVA

反射

image.png

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

Java 反射机制,可以实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法; ⑤生成动态代理。

一、 获取源头 Class(重点)

①Class.forName(”包名.类名”)//一般尽量采用该形式
②类.class
③对象.getClass()

public class  Source {
public static void main(String[] args) {
//第一种方式:对象.class
Source s=new Source();
Class<?>c1=s.getClass();
//第二种方式:类.class
Class<?>c2=Source.class;
//第三种方式(推荐方式): Class.forName()
Class<?>c3=null;
try {
c3=Class.forName("com.shsxt.ref.simple.Source");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c3.getName());
}
}


\color{red}{注意}

1.创建对象的时候,拿到的都是当天前类型Class对象的一个镜像|赋值体

2.在类加载的时候,会在内存中存在当天前类型的一个Class对象,一个类的Class对象中存储这个类的所有信息(属性,方法,构造器...)

3.只要我们能够获取这个类型的Class对象,就可以对这个类做一切操作

Class 类的实例表示正在运行的 Java 应用程序中的类和接口

public class ReflectDemo02 {
    public static void main(String[] args) throws ClassNotFoundException{
        //1.对象.getClass()
        Class cls1="哈哈".getClass();
        Class cls2="呵呵".getClass();
        System.out.println(cls1==cls2);
        
        //2.类名.class
        Class cls3=String.class;
        System.out.println(cls1==cls3);
        System.out.println(cls3);
        
        //3.Class.forName("类的权限命名:包名+类名")   推荐
        Class cls4=Class.forName("java.lang.String");
        System.out.println(cls3==cls4);
        
        //4.根据子类的Class对象获取父类的Class对象
        Class cls5=cls4.getSuperclass();
        System.out.println(cls5);
        
        //5.获取基本数据类型的Class对象
        Class base1=int.class;
        System.out.println(base1);
        Class cls6=Integer.class;
        System.out.println(base1==cls6);
        Class base2=Integer.TYPE;  //得到对应的基本数据类型的class对象
        System.out.println(base1==base2);
        
        //常用的方法
        //1.getName() 包名+类名
        System.out.println(cls5.getName());
        
        //2. Class<?>[] getInterfaces()  
        Class[] arr=cls4.getInterfaces();
        System.out.println(Arrays.toString(arr));
        
        //3.String getSimpleName()  
        System.out.println(cls4.getSimpleName());
        
        //4.boolean  isInterface()  isPrimitive() 
        System.out.println(Integer.class.isPrimitive());
        System.out.println(Integer.TYPE.isPrimitive());
        
    }
}



二、实例化对象****(****重点****)**

1)通过反射获取到类中的构造器

2)根据构造器创建对象

l 构造器Constructor对象.newInstance(实参)方法

l 直接通过class类的newIntance()方法创建对象,方法没有参数 调用空构造

构造器方法

image.png

注意****:newInstance()****是调用空构造,如果空构造不存在,会出现异常。由此可知,使用其他构造器创建对象比较麻烦,使用空构造非常简单。 确保空构造存在.

public class ReflectDemo03 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        //1.先获取类的Class
        Class cls=Person.class;
        //2.通过Class类中的方法,获取到Person类中的构造器
        
        /*
         *   Constructor<T> getConstructor(Class<?>... parameterTypes) 
                      返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 
             Constructor<?>[] getConstructors() 
                      返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 
         */
        Constructor con1=cls.getConstructor(int.class,String.class,int.class);
        Person p=(Person) con1.newInstance(01,"卢妹妹",18);
        System.out.println(p);
        
        Person p1=(Person)cls.newInstance();
        System.out.println(p1);
        
        /*
         *   Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
                      返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 
             Constructor<?>[] getDeclaredConstructors() 
                      返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 
         */
        Constructor<Person>[] cons=cls.getDeclaredConstructors();
        System.out.println(Arrays.toString(cons));
        //私有的构造器
        //放开权限
        cons[1].setAccessible(true);  //权限方法
        Person p3=cons[1].newInstance(02,"卢双双");
        cons[1].setAccessible(false); 
        System.out.println(p3);
        
        
    }
}


|

三:属性和方法

获取所有属性(包括父类或接口) ,使用 Field 即可操作

image.png

获取所有方法(包括父类或接口),使用 Method 即可。

image.png
package com.shsxt.ref01;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class ReflectDemo04 {
    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
//      testField(Person.class);
        testMethod(Person.class);
    }
    
    /*
     * 操作方法   调用方法,能给方法传递实参
     * 
     *  Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
            返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 
        Method[] getDeclaredMethods() 
        Method getMethod(String name, Class<?>... parameterTypes) 
            返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 
        Method[] getMethods() 
            返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 
     */
    public static void testMethod(Class cls) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
        Method[] arr=cls.getMethods();
        Person p=(Person) cls.newInstance();
//      Method me=cls.getDeclaredMethod("setAge", int.class);
        Method me=cls.getDeclaredMethod("toString");
        System.out.println(me.invoke(p));;
        System.out.println(p.getAge());
//      System.out.println(Arrays.toString(arr));
        //静态方法执行的时候,invoke第一个参数可以为null
        cls.getMethod("haha").invoke(null);
    }
    
    /*
     * 反射操作类中的字段  能设置值  能获取值
     * Field getDeclaredField(String name) 
                  返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 
       Field[] getDeclaredFields() 
                  返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 
       Field getField(String name) 
                  返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 
       Field[] getFields()  
     */
    public static void testField(Class cls) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
        Field name=cls.getDeclaredField("name");
        //Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。 
        name.setAccessible(true);
        //void set(Object obj, Object value)  
        Person p=new Person(05,"大力",18);
        name.set(p, "大力水手");
        System.out.println(name.get(p));
        System.out.println(name.getName());
        System.out.println(Modifier.toString(name.getModifiers()));
    }
}


四:修饰符

获取修饰符,使用 Modifier 即可

image.png

五:类加载器

在 java 中有三种类类加载器: ⑴Bootstrap ClassLoader 此加载器采用 c++编写,一般开发中很少见。 ⑵Extension ClassLoader 用来进行扩展类的加载,一般对应的是 jre\lib\ext 目录中的类 ⑶AppClassLoader 加载 classpath 指定的类,是最常用的加载器。同时也是 java 中默认的加载器。 了解即可。

image.png

了解一下类的生命周期 : 在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开 JVM。 在程序执行中 JVM 通过装载链接初始化这 3 个步骤完成。 类的装载是通过类加载器完成的,加载器将.class 文件的二进制文件装入 JVM 的方法区,并且在堆区创建描述这个类的 java.lang.Class 对象。用来封装数据。 但是同一个类只会被类装载器装载一次。 链接就是把二进制数据组装为可以运行的状态。链接分为校验,准备,解析这 3 个阶段 1、校验一般用来确认此二进制文件是否适合当前的 JVM(版本), 2、准备就是为静态成员分配内存空间。并设置默认值 3、解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以 被运行程序使用(建立完整的对应关系) 完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个 对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向 Class 对象时就会被卸载,结束类的生命周期。

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

推荐阅读更多精彩内容