首页 > 编程语言 > 详细

JAVA 反射机制详解

时间:2015-10-27 02:05:34      阅读:260      评论:0      收藏:0      [点我收藏+]

? ? ? JAVA中万事万物皆为对象,包括类也是对象!所有的类都是java.lang.Class这个类的对象! 不信你可以随便选一个类测试一下, 我选java.lang.String为例 ?String类有一个静态成员变量class ?通过该成员变量我们可以得到?Class c = String.class ? 即:String类型是这个Class类的一个对象 ?官方称这个对象c为String的类类型(class type) ?同理 所有的类型与String一样

下面看我们如何创建某个类的类类型呢??有三种方式:

比如说我们现在有个类叫做ReflectTest ?

1、Class c1 = ReflectTest.class; //通过类的静态成员变量

2、Class c2 = new ReflectTest().getClass(); //调用该类的对象的getClass方法

3、Class c3 = Class.forName("com.xue.reflect.ReflectTest"); //通过Class类型的一个静态方法

每个类的类类型只有一个!!! 也就是说c1 == c2 == c3

还可以给类类型加上泛型:

Class<ReflectTest> c4 = ReflectTest.class;

可以通过类的类类型实例化该类的对象:

ReflectTest r = (ReflectTest) c1.newInstance();//这边要进行强制转换!除非前面创建类类型的时候指定了泛型就不用强制转换了

?

完整代码如下:

package com.xue.reflect;

?

public class ReflectTest {

?

?

?

?

public static void main(String[] args) {

Class c1 = ReflectTest.class;

Class c2 = new ReflectTest().getClass();

Class<ReflectTest> c4 = ReflectTest.class;

try {

Class c3 = Class.forName("com.xue.reflect.ReflectTest");

System.out.println("c1 == c3?:"+(c1 == c3));

} catch (ClassNotFoundException e) {

?

e.printStackTrace();

}

System.out.println("c1 == c2?:" + (c1 == c2));

?

try {

ReflectTest r = (ReflectTest) c1.newInstance();

r.toString();

ReflectTest r1 = c4.newInstance();

System.out.println(r1.toString());

} catch (InstantiationException e) {

?

e.printStackTrace();

} catch (IllegalAccessException e) {

?

e.printStackTrace();

}

?

}

?

?

@Override

public String toString() {

String s = "I am ReflectTest Class";

return s;

}

?

}

?

?

?

我们还可以通过Class.forName("类全称") 动态加载类, 这样的好处就是编译的时候不用静态加载所有的类

?

代码如下 ?我们先写一个Animal 接口:

package com.xue.reflect;

?

public interface Animal {

? ?

public void call();

}

?

?

然后再写2个实现类 分别是Tiger.java ?和 ?Miao.java

?

Tiger.java :

package com.xue.reflect;

?

public class Tiger implements Animal {

@Override

public void call() {

System.out.println("哇~吼");

}

?

}

Miao.java:

package com.xue.reflect;

?

public class Miao implements Animal {

@Override

public void call() {

System.out.println("喵~喵");

}

}

?

?

然后我们只要通过以下方式就可以动态加载我们所用到的类了:

package com.xue.reflect;

?

public class CallTest {

?

public static void main(String[] args) {

CallTest ct = new CallTest();

ct.call("com.xue.reflect.Miao");//这边我们穿的类是Miao这个类名 ?所以Tiger这个类是不会加载的

?

}

?

?

?

public void call(String s) {

try {

Class c = Class.forName(s);//动态加载类 ?s为所用到的类的全称

try {

Animal animal = (Animal)c.newInstance(); //因为我们所有的类都是实现Animal接口 ?所以可以通过这种方式来实例化对象

animal.call(); //调用call类中重写的call方法

} catch (InstantiationException e) {

?

e.printStackTrace();

} catch (IllegalAccessException e) {

?

e.printStackTrace();

}

?

?

} catch (ClassNotFoundException e) {

?

e.printStackTrace();

}

?

}

?

}

?

?

?

接下来我们还可以通过某个类的类类型来获取该类的所有方法,成员变量,构造方法等 ?代码如下

package com.xue.reflect;

?

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

?

public class ReflectDetail {

?

public static void main(String[] args) {

ReflectDetail rd = new ReflectDetail();

rd.printMethods("hello"); //获取String类的所有方法及返回值和传参列表

rd.printField("hello"); //获取String类的所有成员变量

rd.printConst("hello"); //获取String类的所有构造函数

?

?

}

?

//获取类的所有方法及返回值和传参列表

public void printMethods(Object o) {

Class c1 = o.getClass(); //获得该类的类类型

System.out.println(c1.getName()); //打印该类的名称

Method m[] = c1.getDeclaredMethods(); //获得该类所有的方法

for (Method me : m) {

?

System.out.print("ReturnType:"+me.getReturnType().getName()+" ?Method:"+me.getName()+" ? params: ");?

Class types[] = me.getParameterTypes(); //获得某个方法的传参列表

for (Class c : types) {

System.out.print(c.getName()+ " ");

}

?

System.out.println();

?

?

}

?

?

}

?

? ? ? ?//获得该类的所有成员变量

public void printField(Object o) {

Class c1 = o.getClass();

Field fs[] = c1.getDeclaredFields();

for (Field f : fs) {

Class type = f.getType();

System.out.print("Type :" + type.getSimpleName() + " ParamName: " + f.getName());

System.out.println();

}

}

?

? ? ? ?//获得该类的所有构造函数以及传参列表

public void printConst(Object o) {

Class c1 = o.getClass();

Constructor cons[] = c1.getConstructors();

for (Constructor con : cons) {

System.out.print("Constructor: "+ con.getName()+" params: ");

Class cs [] = con.getParameterTypes();

for (Class c : cs) {

System.out.print(c.getName()+" ");

}

System.out.println();

}

?

?

}

?

}

?

?

?

接下来我们要研究下泛型的本质 : 泛型的本质就是只在编译的时候有用,如果绕开编译就失去了效果

下面我们看个代码就了解了

package com.xue.reflect;

?

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.List;

?

public class ReflectGenerics {

?

public static void main(String[] args) {

List list1 = new ArrayList(); //list1 不加泛型

List<String> list2 = ?new ArrayList<String> (); ?//list2 加上泛型String

Class c1 = list1.getClass(); //分别获得两个类类型 ?看是否相同 ?

Class c2 = list2.getClass();

System.out.println("c1 == c2 ? : "+ (c1 == c2)); //如果相同的话说明加泛型和不加泛型都是同一个类! 结果为true 所以是相同类型

try {

Method m = c2.getMethod("add", Object.class);//我们这里用加了泛型的list2来做实验看能不能把数字1插进去 如果插进去了的话说明泛型只有在编译期有效果,说明我们已经绕开了泛型的限制

try {

Object o = m.invoke(list2, 1);//通过invoke方法来实现list.add(xxx)方法

System.out.println(list2.size());//如果这里输入为1的话说明我们已经把数字1成功插入到list2中了 !其结果就是已经插入 ?所以我们可以证实泛型的限制只在编译时候有效

} catch (IllegalAccessException e) {

?

e.printStackTrace();

} catch (IllegalArgumentException e) {

?

e.printStackTrace();

} catch (InvocationTargetException e) {

?

e.printStackTrace();

}

} catch (NoSuchMethodException e) {

?

e.printStackTrace();

} catch (SecurityException e) {

?

e.printStackTrace();

}

}

?

}

?

上面代码的结果为:

c1 == c2 ? : true

1

?

?

因为是第一次写博客 ?排版和表达能力都有点乱。。。请多多包涵 ?!如果有错误请帮忙指出下!

?

JAVA 反射机制详解

原文:http://582336034.iteye.com/blog/2252085

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!