昨天去参加比赛了,所以没有进行博客迁移。人生中的第一场健体比赛,虽然没得奖,但是收获和带来的思考颇丰。意外地进入了男子B组(174以上)的半决赛,然后在半决赛的时候还被裁判员点名出去单独比较,这个很让我惊喜。最后不意外地止步决赛。事后看视频感觉自己没发挥好,有些遗憾,下一次比赛要更加认真的对待!

废话少说,进入今天的主题:Java反射。

这篇文章是根据马士兵老师的Java视频课程所整理的。感谢马士兵老师,很有个人魅力的一个人。

前言

我们写程序时一直在使用各种各样不同的类来生成对象,但是却从没想过为什么可以这样做。所谓的类,只不过是.java文件中的一些文本罢了,我们知道很多事情JVM帮我们做了,但却并不知道JVM做了什么。

类的加载机制

学Java的人都知道这样一句话:

在Java中,一切都是对象。

所谓的类,其实在JVM中也是对象,它的类型就是类类型。说起来有点拗口,但确实

所有的类都是通过ClassLoader这个类加载到内存中的CodeSegment中去的。但是类也分等级,比如核心类,如String;拓展类,如xxx(具体类名不记得了..);还有自己定义的类,如Student。这些类是被不同的ClassLoader加载进来的,

通过下列程序来查看Java的类加载过程:

class TestClassLoader{

public static void main(String[] args){

new A();

System.out.println("--------");

new B();

new C();

new C();

}

class A{

}

class B{

}

class C{

static {

System.out.println("ccccccccc");

}

}

}

运行上述程序,打印verbose日志,发现JVM的类加载过程如下:

1. JVM首先使用bootstrap classloader和extension classloader去加载一些核心类,如String类这些,可以认为这些类是Java程序运行所必须的类。

2. 使用application classloader去加载TestClassLoader这个我们创建的类。然后其中的代码从main方法开始执行,首先碰到的是方法参数中的String类,这个时候applicationclassloader会问extensionclassloader有没有加载过String类,如果extensionclassloader不知道,它会再向上询问bootstrapclassloader,并最终得到结果并告诉applicationclassloader。如果没加载过,那么applicationclassloader会去找String类进行加载,如果已经加载过了,就不再加载。否则每次遇见类就加载的话,我们就可以让程序加载我们的自己写的和某些核心类同名的类了,相当于是将java中的核心类替换成了我们自己的类,这是极不安全的。因此classloader的这种逐级向上询问的方式可以防止开发者篡改核心类的代码,开发核心病毒。

3. 一个类只会被加载一次,原因如上所述。

4. 静态代码块是在类加载的时候执行的,所以上述代码中虽然new了两个C对象,但是其静态代码块只会执行一次。即只会输出一次ccccccccc

关于上面提到的三种classLoader

bootstrap class loader

implemented by native language (C, C++)

load core classes of jdk

extension class loader

load classed from jre/lib/ext

application class loader

load user-define classes

other class loaders

SecureClassLoader

URLClassLoader

这三种classloader并不是继承关系,而是层次关系,比如你load我,我再load他,这样子。

思考这样一个问题:

写一个方法,这个方法的签名为Object fun(String className){}。要求在方法体中实现根据传入的类名生成一个该类的对象,并返回。

对于人来说,这个任务非常简单,但是对于计算机来说,这个任务就非常麻烦了,因为方法得到的类名是一个String对象,如何将这个String对象转换成类的类型呢?这个时候就必须要用到反射了。理解反射机制也必须理解上面所讲的类加载机制。

插一句:其实万物都有始。我们不了解类加载机制也不妨碍我们写一些应用层的代码,但是不代表类的加载是无缘无故完成,它必定有一个过程,必定有一个开始的地方。

TestReflect.java

public class TestReflect {

public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException {

//假设现在程序知道了有一个类的名字叫做Student,现在要创建它的对象

String s = "Reflect.Student";//一定要用完全限定名,这点和马士兵视频中的不同,可能是jdk版本的原因

//首先要根据类名去寻找这个类文件,并将其加载到内存中来,加载后以一个Class对象的方式存在与内存中

Class c = Class.forName(s); // throws ClassNotFoundException

//根据加载进来的类对象创建这个类的对象

Object student = c.newInstance(); // throws InstantiationException and IllegalAccessException

//探知这个类的属性

Field[] fields = c.getFields();

System.out.println("探知到的属性数 = "+fields.length);

for(Field field : fields){

System.out.println(field.getName());

}

//探知这个类的方法

Method[] methods = c.getMethods();

System.out.println("探知到的方法数 = "+methods.length);

for (Method method : methods){

System.out.println(method.getName());

//调用这个类的方法

if (method.getName().equals("fun1")){

method.invoke(student);//throws IllegalArgumentException

}

//甚至还能调用Method的getParameterTypes()和getReturnType()拿到方法的参数类型和返回值类型。具体的可以参考Java的API文档

}

}

}

Student.java

class Student {

public String i = "public";

protected String s = "protected";

String ss = "default";

private String sss = "private";

static String kk = "static";

static {

System.out.println("class Student has been loaded");

}

Student(){

System.out.println("object Student has been constructed");

}

public void fun1(){

System.out.println("public function fun1() has been invoked");

}

protected void fun2(){

System.out.println("protected function fun2() has been invoked");

}

void fun3(){

System.out.println("default function fun3() has been invoked");

}

private void fun4(){

System.out.println("private function fun4() has been invoked");

}

}

输出:

class Student has been loaded

object Student has been constructed

探知到的属性数 = 1

i

探知到的方法数 = 10

fun1

public function fun1() has been invoked

wait

wait

wait

equals

toString

hashCode

getClass

notify

notifyAll

从上面的输出可以看出,利用反射动态加载的类,只能使用其public属性和方法,其他三种修饰符的一律不可以使用。

总结

所谓反射,其实跟中文中的词汇“反射”没什么特别大的联系,在Java中只是一种用于动态加载和生成类对象并使用之的技术手段。

在哪里会用到反射?

当一个程序的运行依赖于配置文件时,这个程序极有可能使用了反射。因为程序从配置文件中读到的只能是字符串,要根据字符串实现不同的逻辑,很可能涉及到不同的类,而要根据字符串生成不同的类,则必须用到反射。当然也可以在程序内写很多分支判断语句,但是这种做法会产生大量的不运行代码,而且,除非分支语句能够穷尽所有的可能,否则这个程序总存在bug。尤其是当程序运行所依赖的外部参数多于一个时,分支语句的个数简直是成指数增加,几乎不可能穷尽。

后记:我试着学习鸿洋和郭霖的文风,而尽量避免stormzhang的风格,因为我个人感觉前者的文章看着更加舒服。但我深知自己离他们任何一个人的水平都还差太远,所以如果文章中出现哪些技术性错误,请一定告诉我错在哪里,谢谢!

如果这篇文章有帮到你,请在下方留言,这将是对我莫大的鼓励。

java反射用在哪里_Java反射相关推荐

  1. java 反射 慢在那里_Java 反射到底慢在哪?

    反射具体是怎么影响性能的?这引起了我的反思. 是啊,在阐述某个观点时确实有必要说明原因,并且证明这个观点是对的,虽然反射影响性能人尽皆知,我曾经也真的研究过反射是否存在性能问题,但并没有在写文章的时候 ...

  2. java反射消耗性能吗_JAVA反射会降低你的程序性能吗?

    早两天写了<从把三千行代码重构成15行代码谈起>这篇文章,看到评论中有一些同学的回复还是在质疑反射的性能,好像程序用上了反射,就像开上了拖拉机似的.本来我觉得这个话题没有什么好讨论的了,网 ...

  3. java获取object属性值_java反射获取一个object属性值代码解析

    有些时候你明明知道这个object里面是什么,但是因为种种原因,你不能将它转化成一个对象,只是想单纯地提取出这个object里的一些东西,这个时候就需要用反射了. 假如你这个类是这样的: privat ...

  4. java反射机制详解_Java反射机制详解

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

  5. java反射设置属性值_Java反射如何有效的修改final属性值详解

    前言 以前写过一篇 Java 反射修改 final 属性值,本文将在这里重新温习一下Java反射如何有效的修改final属性值,下面话不多说了,来一起看看详细的介绍: 假设有个类 class Pers ...

  6. java反射的编译过程_Java反射机制小结和实际操作

    一.什么是反射 1.编译和运行 在了解什么是Java反射机制前,先聊聊Java的编译和运行. 还记得第一次使用记事本编写第一个Java程序的场景吗?通过命令窗口,使用javac命令编译一个.java文 ...

  7. java 获取接口的注解_java反射注解妙用-获取所有接口说明

    前言 最近在做项目权限,使用shiro实现restful接口权限管理,对整个项目都进行了重构.而权限管理需要用到所有的接口配置,包括接口url地址,接口唯一编码等.想要收集所有的接口信息,如果工程接口 ...

  8. java反射有什么用_java反射的作用知识点总结

    Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助. 什么是Java的反射? 反射是Java的特征之一,是一种间接操作 ...

  9. java反射机制详解_JAVA反射机制详解_JSP/Java编程_互联网开发技术网_传播最新的编程技术_php361.com...

    今天,下午在和朋友聊天的时候,聊起了反射这个话题. 我们就从下面这个段简单的代码开始吧. 这个代码输出什么,想必大部分的读者跟我一样,会很快地知道答案:0 1 2 3 4 5 6 7 8 9.事实也是 ...

最新文章

  1. 7个极具杀伤性的Linux命令
  2. Java_Web使用简单的批处理操作
  3. 循环数组对象 php,PHP循环遍历stdClass对象的数组
  4. MQTT 控制报文 - PINGREQ心跳报文,PINGRESP - 第4章
  5. Google 宣布 Kotlin-first 已四年,为什么 Java 开发者仍不买账?
  6. Ubuntu 下使用 FDDB 测试人脸检测模型并生成 ROC 曲线
  7. 迪文屏学习系列之数据录入
  8. c语言ab43错误的是,求助,AB+没法玩下去了,详情请看报错代码
  9. ckplayer(超酷网页视频播放器)
  10. aardio - 仿安装界面进行窗口高度调节的方法
  11. php当月1号怎么获取,php获取下月1号和月底最后一天的时间
  12. 【芝麻信用对接】欺诈信息验证
  13. Python数据挖掘——烟火图像分类:传统机器学习建模方法与卷积神经网络性能比较
  14. python3操作USB设备
  15. Python实现决策树算法和朴素贝叶算法,并根据天气数据集预测是否出游
  16. 大数据的过去、现在和未来:万字长文解读《大数据四十二条》
  17. 面试:m3u8到底是什么格式
  18. 怎么修改照片dpi值?怎么提高照片分辨率dpi?
  19. 数字调制系统工作原理_无人值守道闸系统的工作原理
  20. Android性能测试方法【硬核】

热门文章

  1. ceph rados命令使用
  2. MQTT消息长度限制
  3. c++重载(以运算符重载为主)
  4. Vue源码终笔-VNode更新与diff算法初探
  5. Oracle用户管理
  6. Resin介绍及其使用配置
  7. 快速构建Windows 8风格应用32-构建辅助磁贴
  8. E8.Net 2005工作流平台版本发布
  9. Java线程怎样映射到操作系统线程
  10. PHP autoload机制详解