Java篇-反射

一 : Class解析

java.lang.Class:是反射的源头。
首先我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的),此.class文件加载到内存以后,就是一个运行时类,存在在缓存区。那么这个运行时类本身就是一个Class的实例.

获取运行时类实例
Person p = new Person();
        Class clazz = p.getClass();//通过运行时类的对象,调用其getClass(),返回其运行时类。

1.每一个运行时类只加载一次!
2.有了Class的实例以后,我们才可以进行如下的操作:
1)创建对应的运行时类的对象
2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解、...)
3)调用对应的运行时类的指定的结构(属性、方法、构造器)
4)反射的应用:动态代理

二 : 获取Class的实例操作

  • 调用运行时类本身的.class属性
Class clazz1 = Person.class;
        System.out.println(clazz1.getName());
        
Class clazz2 = String.class;
        System.out.println(clazz2.getName());
  • 通过运行时类的对象获取
Person p = new Person();
        Class clazz3 = p.getClass();
        System.out.println(clazz3.getName());
  • 通过Class的静态方法获取.通过此方式,体会一下,反射的动态性
String className = "com.atguigu.java.Person";
        Class clazz4 = Class.forName(className);
        System.out.println(clazz4.getName());
  • 通过类的加载器
ClassLoader classLoader = this.getClass().getClassLoader();
        Class clazz5 = classLoader.loadClass(className);
        System.out.println(clazz5.getName());
证明每一个运行时类只加载一次

内存地址空间相同,证明为统一个运行时类

System.out.println(clazz1 == clazz3);//true
        System.out.println(clazz1 == clazz4);//true
        System.out.println(clazz1 == clazz5);//true

三 : 类的加载器

类加载的过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化.


类加载过程

类加载器

类加载器
系统类加载器
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
        System.out.println(loader1);
扩展类加载器
ClassLoader loader2 = loader1.getParent();
        System.out.println(loader2);
引导类加载器

打印结果(null) 自动加载,无法直接获取

ClassLoader loader3 = loader2.getParent();
        System.out.println(loader3);
系统类加载器加载Person 类
Class clazz1 = Person.class;
        ClassLoader loader4 = clazz1.getClassLoader();
        System.out.println(loader4);
引导类加载器自动加载

打印结果null

String className = "java.lang.String";
        Class clazz2 = Class.forName(className);
        ClassLoader loader5 = clazz2.getClassLoader();
        System.out.println(loader5);

四 : 通过反射获取Class对象和完整结构

  • 获取对象

创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
要想能够创建成功:
①要求对应的运行时类要有空参的构造器。
②构造器的权限修饰符的权限要足够。

person空参构造器不能用private修饰

public void test1() throws Exception{
        String className = "com.atguigu.java.Person";
        Class clazz = Class.forName(className);
        Object obj = clazz.newInstance();
        Person p = (Person)obj;
        System.out.println(p);
    }
  • 获取设置运行时类的属性
① getFields()

获取到运行时类中及其父类中声明为public的属性

public void test1(){
        Class clazz = Person.class;
        Field[] fields = clazz.getFields();
        for(int i = 0;i < fields.length;i++){
            System.out.println(fields[i]);
        }
        System.out.println();
    }
② getDeclaredFields()

获取运行时类本身声明的所有的属性

Field[] fields1 = clazz.getDeclaredFields();
        for(Field f : fields1){
            System.out.println(f.getName());
        }
③获取 权限修饰符 变量类型 变量名
Class clazz = Person.class;
        Field[] fields1 = clazz.getDeclaredFields();
        for(Field f : fields1){
            //1.获取每个属性的权限修饰符
            int i = f.getModifiers();
            String str1 = Modifier.toString(i);
            System.out.print(str1 + " ");
            //2.获取属性的类型
            Class type = f.getType();
            System.out.print(type.getName() + " ");
            //3.获取属性名
            System.out.print(f.getName());
            
            System.out.println();
        }
④获取运行时类中声明为public的指定属性名为fieldName的属性

getField(String fieldName)
获取运行时类中声明为public的指定属性名为fieldName的属性

Class clazz = Person.class;
Field name = clazz.getField("name");
⑤将运行时类的指定的属性赋值
Person p = (Person)clazz.newInstance();
name.set(p,"TZ");
System.out.println("%"+name.get(p));
⑥获取运行时类中指定的名为fieldName的属性

不惧权限修饰符
getDeclaredField(String fieldName)

Field age = clazz.getDeclaredField("age");
        //由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。

          //声明为protected 不在一个包的情况下也要加`age.setAccessible(true)` 否则不用加
        age.setAccessible(true);
        age.set(p,10);
        System.out.println(p);
  • 获取运行时类的方法
①getMethods():

获取运行时类及其父类中所有的声明为public的方法

Method[] m1 = clazz.getMethods();
        for(Method m : m1){
            System.out.println(m);
        }
        System.out.println();
②getDeclaredMethods()

获取运行时类本身声明的所有的方法

Method[] m2 = clazz.getDeclaredMethods();
        for(Method m : m2){
            System.out.println(m);
        }
③获取 注解 权限修饰符 返回值类型 方法名 形参列表 异常
Method[] m2 = clazz.getDeclaredMethods();
        for(Method m : m2){
            //1.注解
            Annotation[] ann = m.getAnnotations();
            for(Annotation a : ann){
                System.out.println(a);
            }
            
            //2.权限修饰符
            String str = Modifier.toString(m.getModifiers());
            System.out.print(str + " ");
            //3.返回值类型
            Class returnType = m.getReturnType();
            System.out.print(returnType.getName() + " ");
            //4.方法名
            System.out.print(m.getName() + " ");
            
            //5.形参列表
            System.out.print("(");
            Class[] params = m.getParameterTypes();
            for(int i = 0;i < params.length;i++){
                System.out.print(params[i].getName() + " args-" + i + " ");
            }
            System.out.print(")");
            
            //6.异常类型
            Class[] exps = m.getExceptionTypes();
            if(exps.length != 0){
                System.out.print("throws ");
            }
            for(int i = 0;i < exps.length;i++){
                System.out.print(exps[i].getName() + " ");
            }
            System.out.println();
        }
④调用运行时类中指定的方法
Class clazz = Person.class;
        //getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
        Method m1 = clazz.getMethod("show");
        Person p = (Person)clazz.newInstance();
        //调用指定的方法:Object invoke(Object obj,Object ... obj)

            注 :   'returnVal' 为方法返回值
        Object returnVal = m1.invoke(p);//我是一个人

        //无返回值
        System.out.println(returnVal);//null
        
        Method m2 = clazz.getMethod("toString");
        Object returnVal1 = m2.invoke(p);

          //打印返回值
        System.out.println(returnVal1);//Person [name=null, age=0]
        //对于运行时类中静态方法的调用
        Method m3 = clazz.getMethod("info");
        m3.invoke(Person.class);
        
        //getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
 
注 : `其中 display 为private 修饰方法`
        Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);
        m4.setAccessible(true);
        Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN
        System.out.println(value);//10
⑤获取所有构造器
public void test2() throws ClassNotFoundException{
       String className = "com.atguigu.java.Person";
       Class clazz = Class.forName(className);
       
       Constructor[] cons = clazz.getDeclaredConstructors();
       for(Constructor c : cons){
           System.out.println(c);
       }
   }
⑥获取父类
@Test
    public void test1(){
        Class clazz = Person.class;
        Class superClass = clazz.getSuperclass();
        System.out.println(superClass);
    }
⑦获取带着泛型的父类
public void test2(){
        Class clazz = Person.class;
        Type type1 = clazz.getGenericSuperclass();
        System.out.println(type1);
    }
⑧获取父类的泛型
public void test3(){
        Class clazz = Person.class;
        Type type1 = clazz.getGenericSuperclass();
        
        ParameterizedType param = (ParameterizedType)type1;
        Type[] ars = param.getActualTypeArguments();
        
        System.out.println(((Class)ars[0]).getName());
    }
⑨获取实现的接口
public void test4(){
        Class clazz = Person.class;
        Class[] interfaces = clazz.getInterfaces();
        for(Class i : interfaces){
            System.out.println(i);
        }
    }
⑩获取所在的包
public void test5(){
        Class clazz = Person.class;
        Package pack = clazz.getPackage();
        System.out.println(pack);
    }
11.获取注解
public void test6(){
        Class clazz = Person.class;
        Annotation[] anns = clazz.getAnnotations();
        for(Annotation a : anns){
            System.out.println(a);
        }
    }
12.调用指定的构造器

调用 private Person(String name,int age)这个构造器

public void test3() throws Exception{
        String className = "com.atguigu.java.Person";
        Class clazz = Class.forName(className);
        
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Person p = (Person)cons.newInstance("TZ",20);
        System.out.println(p);
    }  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,516评论 0 6
  • 一:java概述: 1,JDK:Java Development Kit,java的开发和运行环境,java的开发...
    慕容小伟阅读 1,733评论 0 10
  • 引用计数技术及智能指针的简单实现 基础对象类 辅助类 智能指针类 使用测试 参考: C++ 引用计数技术及智能指针...
    赤龙绕月阅读 339评论 0 0
  • 最近国家在鼓吹“大众创业”,其实目的很明显,一是产业结构升级的过程中需要大量新兴产业,而创业又是发展新兴产业的最快...
    布客飞龙阅读 353评论 1 36