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