// 通过反射机制,通知力宏做事情
method.invoke(object, args);
// 通过反射,将h作为参数,实例化代理类,返回代理类实例。
return cons.newInstance(new Object[]{h});
ASP站长网而且在
// 将接口类对象数组clone一份。
final Class<?>[] intfs = interfaces.clone();
也提到一个类对象数组的概念,如果你不知道反射,不知道类对象,那么你在阅读者两篇文章的时候,很可能就会雨里雾里,不知所然。通过这篇文章你就能很轻松的掌握类对象和反射。
反射是Java语言中一个很基础,很简单的知识,不仅仅是在工作中会用到,而且也会经常出现在面试中。如果你认真阅读本文,对你在技术层面来说又是一个提升。
一,前言
反射是什么呢?其实是java程序语言的一种机制,我理解为是java的后门。在其他文章中给出的定义和解释都比较晦涩难懂,不如先看一下具体的代码,再去理解,这样就容易很多。
为了更好的理解反射机制,不得不提到类对象的概念,为了不与类和对象的概念搞混,我们就首先看一下类和对象的概念。相信你已经非常熟悉类和对象的概念了,那么我就简单的描述一下类与对象的概念:
类:一个或一组事物的抽象描述,例如狗是对狗狗这一组事物的抽象描述。
对象:具体的某一个事物,例如哈士奇等,也可以说是类的一个实例。
那么类对象是什么呢?
在java中一切皆对象。既然一切皆对象,当然类也是一种对象,那么类的对象类型是什么呢?是java.lang.Class,你也许在其他的地方见到过。
那么类对象是从哪里来的,怎么创建的呢?
我们都知道,想要得到一个类的对象,最基本的方法就是通过new关键字,去实例化一个对象。但类对象是一个特殊的对象,自然不能使用new关键字,翻看Class类的源码就可以证明:
/*
* 私有化构造方法,只有java 虚拟机才能创建类对象
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
Class类中只有这一个私有的构造方法。其实类对象是java虚拟机(JVM)在加载class文件的时候自动在虚拟机内存中给我们创建的。
这里就涉及到了另外一个机制:类加载机制。
简单描述一下类加载机制:就是虚拟机将class文件加载到虚拟机内存中,最终形成可以被虚拟机直接使用的java类型。虚拟机会将class文件中的信息按照所需的存储格式放在方法区中,同时会在内存中(HotSpot是在堆内存中)实例化一个java.lang.Class类对象。
类加载机制是一个很复杂的过程,不是本篇文章的重点,就不展开来说。至少到这里我们已经知道了,类对象是由虚拟机创建的而且HotSpot虚拟机将类对象存放在堆内存中。
那么怎么通过类对象来实现反射呢?为了理解方便,来举一个有趣的例子
二,一个有趣的例子
有一天一个同事养了一只狗狗哈士奇,在作者面前大肆炫耀,说他的狗狗多么萌,多么威武,多么听话……,作者听完心生向往,提出去看一看。但是这个同事高傲的抬起头说了三个字:想的美。
竟然不给我看!!!作者一气之下,就走了java程序的后门-反射。你不让我看,我偏偏要看。
哈士奇类的定义:
package com.zcz.reflecttest;
public class HaShiQi implements Dog {
public String color = "黑色";
private String name = "富贵";
//私有化构造
private HaShiQi() {};
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println(name + " 去吃狗粮");
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(name + " 去跑着玩儿");
}
private void dance() {
System.out.println(name + " 来跳一支舞");
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "名字:"+name+";颜色:"+color;
}
}
可以看到同时的哈士奇实现了Dog接口:
package com.zcz.reflecttest;
public interface Dog {
public void eat();
public void run();
}
从代码中可以看到,我的同事不仅仅没告诉作者他的哈士奇竟然会跳舞,甚至连哈士奇的名字都不想让作者知道,而且连构造器都私有化了。
那么接下来,走后门开始。在上提到类对象,正好我想通过反射看狗狗,也需要用到类对象。那么接下来第一步就先获取HaShiQi的类对象。
三,类对象的获取
超级简单:
package com.zcz.reflecttest;
/**
通过反射查看同事狗狗的信息
@author zhangchengzi
*/
public class LookLook {
public static void main(String[] args) {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
}
}
从这里开始我们的反射的使用的开始了,先看看HaShiQi类中有哪些属性吧?
四,获取属性
代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
可以看到只有一个color属性,使用getFields方法是获取不到私有属性了,想要获取私有属性就要使用下方的方法:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有的属性 —————————");
fields = clazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
——————— 获取所有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
private java.lang.String com.zcz.reflecttest.HaShiQi.name
可以看到,HaShiQi类中私有(private修饰的)的name属性打印出来了。
五,获取方法
代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有的属性 —————————");
fields = clazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有公有的方法 —————————");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
——————— 获取所有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
private java.lang.String com.zcz.reflecttest.HaShiQi.name
——————— 获取所有公有的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
//重写的toString 方法
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
public void com.zcz.reflecttest.HaShiQi.eat()
//Object类中的方法
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
从结果中可以发现,getMethod方法也是只能获取到公有的方法,而且连Object中的方法也获取到了。跟获取属性也是一样的,也有方法可以获取到HaShiQi类中所有的方法:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有的属性 —————————");
fields = clazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有公有的方法 —————————");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("——————— 获取所有类中声明的方法 —————————");
methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
——————— 获取所有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
private java.lang.String com.zcz.reflecttest.HaShiQi.name
——————— 获取所有公有的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
public void com.zcz.reflecttest.HaShiQi.eat()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
——————— 获取所有类中声明的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
private void com.zcz.reflecttest.HaShiQi.dance()
public void com.zcz.reflecttest.HaShiQi.eat()
这样就可以同时获取到HaShiQi类中的私有方法(private修饰的)dance了。
六,获取构造器
代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有的属性 —————————");
fields = clazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有公有的方法 —————————");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("——————— 获取所有类中声明的方法 —————————");
methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("——————— 获取所有公有的构造器 —————————");
Constructor[] constructors = clazz.getConstructors();
for(Constructor constructor : constructors) {
System.out.println(constructor);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
——————— 获取所有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
private java.lang.String com.zcz.reflecttest.HaShiQi.name
——————— 获取所有公有的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
public void com.zcz.reflecttest.HaShiQi.eat()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
——————— 获取所有类中声明的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
private void com.zcz.reflecttest.HaShiQi.dance()
public void com.zcz.reflecttest.HaShiQi.eat()
——————— 获取所有公有的构造器 —————————
因为HaShiQi类中没有公有的构造器,所以这里什么都没有打印出来。自然也有获取到私有构造器的方法:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
//获取类对象,除了这份方法外还有另外两种方法
Class clazz = HaShiQi.class;
System.out.println("——————— 获取所有公有的属性 —————————");
Field[] fields = clazz.getFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有的属性 —————————");
fields = clazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
System.out.println(field);
}
System.out.println("——————— 获取所有公有的方法 —————————");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("——————— 获取所有类中声明的方法 —————————");
methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("——————— 获取所有公有的构造器 —————————");
Constructor[] constructors = clazz.getConstructors();
for(Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("——————— 获取所有的构造器 —————————");
constructors = clazz.getDeclaredConstructors();
for(Constructor constructor : constructors) {
System.out.println(constructor);
}
}
打印结果:
——————— 获取所有公有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
——————— 获取所有的属性 —————————
public java.lang.String com.zcz.reflecttest.HaShiQi.color
private java.lang.String com.zcz.reflecttest.HaShiQi.name
——————— 获取所有公有的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
public void com.zcz.reflecttest.HaShiQi.eat()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
——————— 获取所有类中声明的方法 —————————
public void com.zcz.reflecttest.HaShiQi.run()
public java.lang.String com.zcz.reflecttest.HaShiQi.toString()
private void com.zcz.reflecttest.HaShiQi.dance()
public void com.zcz.reflecttest.HaShiQi.eat()
——————— 获取所有公有的构造器 —————————
——————— 获取所有的构造器 —————————
private com.zcz.reflecttest.HaShiQi()