JAVA 反射机制详解

      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

 

 

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

 

猜你喜欢

转载自582336034.iteye.com/blog/2252085