Java反射机制剖析

java反射机制:

1.指的是可以于运行时加载,探知和使用编译期间完全未知的类.

2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能调用他的任意一个方法和属性;

3.加载完类之后, 在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象), 这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射。

4.每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类.

静态加载类和动态加载类的概念区分:

与反射有关的类包.

java.lang.reflect.*;和java.lang.Class;

Java中所有类型(包括基本类型)都对应一个Class对象,这个Class就是java.lang.Class。即每一个类型,在Class中都有一个Class对象跟它对应.Class 没有公共构造方法。注意不是没有,是没有公共的.

从Class中获取信息

如何获得Class对象

1.针对每一个对象.getCalss,可以得到对应的Class.

2.Class.forName(String),String的写法:包名.类名.就会创建包名.类名对应的那个对象

注:1.2只适用于引用类型

3.对于基本类型:封装类.TYPE代表了对应的基本类型的Class对象.Integer.TYPE对应的是int的Class对象 注:3只适用于基本类型

4.类型,Class。<第4种是通用的.> 上面的4种方法,只有方法2是动态的,只要换一个包就可以了.它具有动态潜质.所以真正意义的想体现动态编程只能使用方法2.

每种类型的Class对象只有一个,即他们的地址只有一个,但是不同类型是不同的.所以下面的打印结果都为true.

//对与引用类型
Class c1 = "".getClass;
Class c2 =     Class.forName("java.lang.String");
Class c3 = String.class;
System.out.println(c1 ==c2);//true
//对于基本类型
Class num1 = Integer.TYPE;
Class num2 = int.class;
System.out.println(num1 == num2);//true

反射获取类中的成员的相关方法

[获取构造<根据参数类型>]使用时一般用不带declared的

Constructor<T> getConstructor(Class<?>... parameterTypes) 
      返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 
 Constructor<?> getConstructors 
      返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 
 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
      返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 
 Constructor<?> getDeclaredConstructors 
      返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。

[获取属性<根据属性名>]使用时一般用是带declared的,因为属性一般都是私有的

Field getField(String name) 
      返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 
 Field getFields 
      返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 
 Field getDeclaredField(String name) 
      返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 
 Field getDeclaredFields 
      返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

[获取方法<方法名加上参数类型>]使用时一般用不带declared的

Method getMethod(String name, Class<?>... parameterTypes) 
      返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 
 Method getMethods 
      返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 
 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
      返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 
 Method getDeclaredMethods 
      返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 
 T newInstance 
      创建此 Class 对象所表示的类的一个新实例。 <new Instance可以动态的创建对象>
 String toString 
      将对象转换为字符串。

注意:

new Instance调用的是无参构造,如果该类没有无参构造方法,则newInstance会产生异常.有declared的方法是支持私有,但是不支持继承,无declared的方法支持继承,不支持私有,且只能取出public的东西.因此取属性的时候一般来说是带declared的,因为属性一般都是私有的,取方法时一般是不带declared的,取构造时一般也是不带declared的.

实例模拟反射获取类中的相关属性和方法

利用反射对属性赋值

Field中的方法

Object get(Object obj)

返回指定对象上此 Field 表示的字段的值。

Field f = c.getXXField(属性名);

值 = f.get(对象);

void set(Object obj, Object value)

将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

f.set(对象,值);

Class

    Class c = Student.class;
    Object obj  = c.newInstance; //创建Student类的对象
    Field f = c.getDeclaredField("name");        //获取name属性
    f.setAccessible(true); //设置私有可以访问.
    f.set(obj, "zhangsan");
    System.out.println(f.get(obj)); //获取obj的name属性的值.

利用反射调用构造

对于构造真正调用是在调用newInstance方法时.

Class c = Class.forName("com.clazz.reflect.Student");
    Constructor con = c.getConstructor;         //没有执行构造,
    Object cObj = c.getConstructor.newInstance;//调用无参的构造方法
    Constructor conAll = c.getConstructor(int.class,String.class,int.class);
    Object caobj = conAll.newInstance(1001,"zjamgs",234235);//调用含参的构造方法.
    System.out.println(caobj); //打印输出

利用反射调用方法

对象.方法名(值1,2,3);

Method m = c.getMethoed(方法名,参数类型…);

m.invoke(对象,方法调用的参数 )如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。

Class c = Class.forName("com.clazz.reflect.Student");
    Object obj = c.newInstance;    //创建Sutdent对象.
    Method msetName = c.getMethod("setName", String.class);//obj无须转换类型
    msetName.invoke(obj, "zhangsan");//调用方法setName, 并传参.
    Method msetId = c.getMethod("setId", int.class);
    msetId.invoke(obj, 409090202);
    System.out.println(obj);

我的微信二维码如下,欢迎交流讨论

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

相关文章

我的Java!越过山丘

当年我是VS程序员,2000年被微软无情抛弃时,我徘徊过,到底继续跟着微软跑还是甩了它!当时兜里没钱,没法再花精力去学习除了名字很像其他都不一样的VS.net……既然甩了微软,那我为什么不直接选一个跨...

Java内存模型的历史变迁

本文通过介绍Java的新/旧内存模型,来展示Java技术的历史变迁。旧的Java内存模型Java使用的是共享内存的并发模型,在线程之间共享变量。Java语言定义了线程模型规范,通过内存模型控制线程与变...

如何识别Java中的内存泄漏

【编者按】作者Martin Gutenbrunner供职于Ruxit,拥有十年的Java Web应用程序架构和管理经验。近日,他在Dzone上撰文分享了Java内存泄漏识别相关经验,由OneAPM工程...

我们为什么要在Android中使用RxJava

感觉RxJava最近风生水起,不学习一下都不好意思了,洒家也是初学RxJava,也是感觉代码好像更复杂更难懂了,看了一篇外文感同身受,简单翻译一下。本文简单介绍使用RxJava优势所在。但可能需要有一...

详解Java中的注解

在Java中,注解(Annotation)引入始于Java5,用来描述Java代码的元信息,通常情况下注解不会直接影响代码的执行,尽管有些注解可以用来做到影响代码执行。注解可以做什么Java中的注解通...