1.反射的定义

反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象,但是“反”指的是通过对象找到类。                                                            

2.Class对象

2.1 概述

Class对象是反射的起点,可以利用类的Class对象创建类的实例(newInstance),同时提供了操作类的工具,可以获取类的详细信息,并且使用特殊的技术实现类的加载(运行时加载,在编译的时候还没有该类的class文件)。

2.2 Class对象的获取方式

  • a.使用类的字面常量

      • Class<Integer> c=Integer.class;     备注:编译时会进行检查,不需要捕获ClassNotFoundException,Class对象的类型也是明确的。
  • b.使用forName函数
      • Class<?> c=Class.forName("Integer");              备注:需要捕获异常,而且Class对象的类型是Class<?>,类型不明确,可以使用asSubClass进行转换,但是只能转换到Class<? extends Integer>。
      • Class<? extends Integer> u=c.asSubClass(Integer.class);
      • Class<? exnteds Integer> u1=c.getClass(new Integer(10).getClass());
  • c.使用getClass()函数
      • Integer integer=new Integer(10);
      • Class<? extends Integer> c=intger.getClass();   备注:使用对象实例获取Class对象。

3.类型检查

3.1概述

Class对象提供了很多获取类信息的工具,可以获取类的方法,属性,进行类型判断,创建类的对象实例等等。

3.2 相关API介绍

  • a.获取类的构造函数
    1. public class Main {
    2. public static void main(String[] atgs) throws ClassNotFoundException {
    3. printTypeInfo("MyClass");
    4. }
    5.    /**
         获取类的构造函数
      */
    6. public static void printTypeInfo(String className){
    7. try {
    8. Class<?> c = Class.forName(className);
    9. Constructor<?>[] constructors=c.getConstructors();
    10. for(Constructor<?> constructor:constructors){
    11. System.out.println(constructor);
    12. }
    13. }catch(ClassNotFoundException e){
    14. e.printStackTrace();
    15. }
    16. }
    17. }
    18.  
    19. class MyClass {
    20. private int num=10;
    21. public MyClass(int num){
    22. this.num=num;
    23. }
    24.  
    25. public MyClass(){
    26. }
    27.  
    28. @Override
    29. public String toString(){
    30. return String.format("%d",num);
    31. }
    32. } 
  • 备注:1.使用反射创建类的实例,Class.newInstance(),类中必须又一个无参数的构造函数,否则会报错。

  • 2.输出:public MyClass(int)

                     public MyClass()

  • 利用构造函数获取相关的对象
  • 用带参数构造函数,创建实例
    1. Constructor<?> constructor=c.getConstructor(int.class);
    2. MyClass myClass=(MyClass)constructor.newInstance(5);
    3. System.out.println(myClass);
  • 备注:1.上述的代码没有捕获异常,不能直接执行
  • 2.Class.newInstance()其实也就是获取类的无参构造函数,然后创建对象。
  • b.获取类的一般函数
    1. public static void printTypeInfo(String className) {
    2. try {
    3. Class<?> c=Class.forName(className);
    4. for(Method method:c.getMethods()){
    5. System.out.println(method);
    6. }
    7. } catch (ClassNotFoundException e) {
    8. e.printStackTrace();
    9. }
    10. } 
  • 备注:
  • 只能获取构造函数之外的函数,但是还包括从父类中继承来的函数
  • 获取特定的函数
  • getMethod(String methodName,Class<?> ...);
  • 例子:获取特定函数并执行Method.invoke(Obj,Class<?>...)---------动态执行Java的函数
    1. public static void main(String[] args){
    2. Class<?> c=Class.forName(className);
    3. Method method=c.getMethod("getInfo",String.class);
    4. System.out.println(method.invoke(c.newInstance(),new String("123")));
    5. }
    6.  
    7. class MyClass {
    8. private int num=10;
    9. public MyClass(int num){
    10. this.num=num;
    11. }
    12.  
    13. public MyClass(){
    14. }
    15.  
    16. public String getInfo(String string){
    17. return String.format("get : %s",string);
    18. }
    19.  
    20. @Override
    21. public String toString(){
    22. return String.format("%d",num);
    23. }
    24. }
  • 备注:不能直接执行,没有捕获异常,为了看一来比较清楚
  • c.获取类的属性
    1. public static void printTypeInfo(String className) {
    2. try {
    3. Class<?> c=Class.forName(className);
    4. Field[] fields=c.getDeclaredFields();
    5. for(Field field:fields){
    6. System.out.println(field);
    7. }
    8.  
    9. } catch (ClassNotFoundException e) {
    10. e.printStackTrace();
    11. }
    12. }
      } 
  • 备注:还可以获取制定的属性 :field = c.getDeclaredField("num");
  • 操作类的属性,赋值-取值
  • 可能会有访问权限的问题,比如private的属性就不能进行操作,此时可以使用field.setAccessible(true)进行“破坏”面向对象的封装。
    1. field.setAccessible(true);
    2. field.set(myClass,123);
  • d.备注
  • 反射还有很所用处,例如获取泛型的参数化类型,操作注解等等。

4.代理

  • a.一般的代理设计模式
    1. public class Main {
    2. public static void main(String[] atgs) {
    3. proxy proxy=new ProxyServer(new RealServer());
    4. proxy.doSomthing();
    5. }
    6. }
    7.  
    8. interface proxy{
    9. void doSomthing();
    10. }
    11.  
    12. class RealServer implements proxy{
    13. @Override
    14. public void doSomthing(){
    15. System.out.println("doSomething from RealServer");
    16. }
    17. }
    18.  
    19. class ProxyServer implements proxy{
    20. private proxy realServer;
    21. public ProxyServer(proxy realServer){
    22. this.realServer=realServer;
    23. }
    24.  
    25. @Override
    26. public void doSomthing(){
    27. realServer.doSomthing();
    28. }
    29. }
  • b.利用反射的动态代理设计模式
    1. import java.lang.reflect.*;
    2.  
    3. /**
    4. * Created by yangyun on 2016/11/30.
    5. */
    6. public class Main {
    7. public static void main(String[] atgs) {
    8. myProxy myProxyInterface=(myProxy) Proxy.newProxyInstance(
    9. RealServer.class.getClassLoader(),
    10. RealServer.class.getInterfaces(),
    11. new ProxyHandler(new RealServer())
    12. );
    13. myProxyInterface.doSomthing();
    14. }
    15. }
    16.  
    17. interface myProxy{
    18. void doSomthing();
    19. }
    20.  
    21. class RealServer implements myProxy{
    22.  
    23. public RealServer(){
    24. }
    25.  
    26. @Override
    27. public void doSomthing(){
    28. System.out.println("from RealServer doSomething()");
    29. }
    30. }
    31.  
    32. class ProxyHandler implements InvocationHandler{
    33. private Object realProxy;
    34. public ProxyHandler(Object realProxy){
    35. this.realProxy=realProxy;
    36. }
    37.  
    38. @Override
    39. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    40. System.out.println("before invoke()");
    41. Object result=method.invoke(realProxy,args);
    42. System.out.println("after invoke()");
    43. return result;
    44. }
    45. }
  • 有什么意义?

  • 1.如果需要在调用代理服务器的函数之前或者之后做一些别的工作,可以不修改服务器端的代码,只需要修改InvocationHandler的invloke()函数就可以。
  • 2.动态代理还是AOP(Spring 面向切面编程的基础)
  • 3.静态代理每增加一个服务类就应该添加一个代理类,动态代理的话只需要一个InvokationHandler就可以了
  • 备注:
  • System.out.println(myProxyInterface.getClass().getName());//$Proxy0
  • 通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号
  • 我自己的理解可能会有错
  • proxy.newProxyInstance()产生的其实是代理对象,这个代理对象会实现被“代理类RealServer”的所有接口,这里我们把它转型为proxy接口。
  • 当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的,输出method可以看到其实就是doSomething函数。
  • 这就是我们的java动态代理机制,代理对象执行函数全部都通过InvokationHandler的invoke()函数。

参考文献

https://www.zhihu.com/question/24304289

http://blog.csdn.net/xu__cg/article/details/52882023

http://blog.csdn.net/liujiahan629629/articzle/details/18013523

http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

17.Java 反射机制的更多相关文章

  1. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  2. [转]java反射机制

    原文地址:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html 一.什么是反射机制         简单的来说,反射机制指的是程序在运 ...

  3. java 反射机制01

    // */ // ]]>   java反射机制01 Table of Contents 1 反射机制 2 反射成员 2.1 java.lang.Class 2.2 Constructor 2.3 ...

  4. Java 反射机制浅析

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

  5. 5. Java反射机制

    Java反射机制   问题: 在运行时,对一个JAVA类,能否知道属性和方法:能否调用它的任意方法? 答案是可以的,JAVA提供一种反射机制可以实现. 目录 什么是JAVA的反射机制 JDK中提供的R ...

  6. Java反射机制能够获取的信息,与应用

    一.什么是Java反射机制? [1]反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法: [2]对于任意一个对象,都能够调用它的任意一个属性和方法: 像这种动态获取类的信息以及动 ...

  7. Java进阶(六)Java反射机制可恶问题NoSuchFieldException

    作为一种重要特性,Java反射机制在很多地方会用到.在此做一小结,供朋友们参考. 首先从一个问题开始着手. 可恶的问题又来了,NoSuchFieldException,如下图所示: 完全不知道这个qu ...

  8. [转]Java反射机制详解

    目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...

  9. 谈谈Java反射机制

    原文出处: locality 写在前面:什么是java反射机制?我们又为什么要学它?当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突 ...

随机推荐

  1. Sed、Awk单行脚本快速参考

    文本间隔: # 在每一行后面增加一空行 sed G awk '{printf("%s\n\n",$0)}' # 将原来的所有空行删除并在每一行后面增加一空行. # 这样在输出的文本 ...

  2. java内存区域简介

    运行时数据区域 1.程序计数器:是一块较小的内存空间,可以看做当前线程所执行的字节码的行号指示器.字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理. ...

  3. 第一章 Java多线程技能

    1.初步了解"进程"."线程"."多线程" 说到多线程,大多都会联系到"进程"和"线程".那么这两者 ...

  4. D3.js学习(二)

    上一节中我们已经画出了一个基本的图表,不过忘了给坐标轴添加标签了,所以在本节中我们要给坐标轴加上标签,目标效果如下 给X轴添加标签 很明显,标签是不是一个text内容块啊,所以我们只要在svg中添加一 ...

  5. A()方法

      A方法用于在内部实例化控制器,调用格式:A('[项目://][分组/]模块','控制器层名称')最简单的用法: $User = A('User'); 复制代码 表示实例化当前项目的UserActi ...

  6. SpingMvc中的异常处理

    一.处理异常的方式      Spring3.0中对异常的处理方法一共提供了两种: 第一种是使用HandlerExceptionResolver接口. 第二种是在Controller类内部使用@Exc ...

  7. 中文编程语言Z语言开源正式开源!!!

    (Z语言基于.NET环境,源码中有很多高技术的代码,让更多的人知道对大家有会有很好的帮助,请管理员一点要批准放在首页) 本人实现的中文编程语言Z语言现在正式开源,采用LGPL协议. 编译器核心的网址为 ...

  8. github with msysgit:配置SSH Key

    Step 1: Check for SSH keys First, we need to check for existing ssh keys on your computer. Open up G ...

  9. Vim 资料总结

    vi/vim基本使用方法:http://www.cnblogs.com/itech/archive/2009/04/17/1438439.html Vim命令合集: http://www.cnblog ...

  10. 耿丹CS16-2班第六次作业汇总

    Deadline: 2016-11-13 11:59 作业内容 第六次作业总结 00.本次题目分值最高为**6分/题 × 7题 + 5分/篇 × 1篇 = 47分**,其中有新解法者每题加原创分**2 ...