一:Class类的使用
在面向对象的世界里,世间万物皆对象。类也是对象,类是java.lang.Class类的实例对象
任何一个类都是Class类的实例对象,这个对象称为该类的类类型。这个实例对象有三种表达方式
public class Demo1 {
public static void main(String[] args) {
//Reflect的对象
Reflect re=new Reflect();
//1.第一种表达方式,实际也在告诉我们任何一个类都有一个隐含的静态成员class
Class c1=Reflect.class;
//2.第二种方式,已经知道该类的对象通过getClass方式
Class c2=re.getClass();
//官网说c1,c2表示了Reflect的类类型(Class Type),即万事万物皆对象
//一个类只可能是Class类的一个实例对象
System.out.println(c1==c2); //true
//3.第三种方式
try {
Class c3=Class.forName("com.swpu.relect.Reflect");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Reflect{}
二:动态加载类
Class.forName("类的全称")不仅表示了类的类类型,还表示了动态加载类。
编译时刻加载类是静态加载类,new创建对象是静态加载类,在编译时刻就需要加载所有可能使用到的类,通过动态加载类可以解决该问题。
运行时刻加载类是动态加载类。
三:java获取方法信息
基本类型都有类类型
public class Demo2 {
public static void main(String[] args) {
Class c1= int.class;
Class c2=String.class;
Class c3=void.class;
System.out.println(c1.getName()); //return int
System.out.println(c2.getName()); //java.lang.String
System.out.println(c3.getName()); //void
}
}
编写了一个API接口来获取类的信息
public class ClassUtil {
/**
* 打印类的信息,包括类的成员函数,成员变量
* @param object
*/
public static void PrintClassMessage(Object object){
//要获取类的信息,首先获取类的类类型
Class c=object.getClass();
//获取类的名称
System.out.println("类的名称为:"+c.getName());
/*
* 获取方法.
* getMethods()方法获取的是所有public的函数,包括从父类继承而来的
* getDeclaredMethods:获取的是所有自己定义的方法,不问访问权限,不包括父类继承过来的
*/
Method [] ms=c.getMethods();
for(Method m:ms){
//得到方法的返回值类型的类型
Class returnType=m.getReturnType();
System.out.print(returnType+" ");
//获取到方法名
System.out.print(m.getName()+"(");
//获取参数类型-->得到的是参数 列表类型的类类型
Class [] ParamTypes=m.getParameterTypes();
for(Class param:ParamTypes){
System.out.print(param.getName()+",");
}
System.out.println(")");
}
}
}
四:java获取成员变量的信息
/**
* 成员变量也是对象,是java.lang.reflect.Field的对象
*
*/
Field[] fs=c.getDeclaredFields();
for(Field f:fs){
//得到成员变量的类类型
Class fieldType=f.getType();
String typeName=fieldType.getName();
//得到成员变量的名称
String fieldName=f.getName();
System.out.println(typeName+"("+fieldName+")");
//
}
五:java获取构造方法的信息
public static void printConMessage(Object obj){
Class c=obj.getClass();
/**
* 构造函数也是对象
* java.lang.Constructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数
* getDeclaredConstructors得到所有的构造函数的信息
*/
Constructor[] cs=c.getDeclaredConstructors();
for(Constructor con:cs){
System.out.print(con.getName()+"(");
//获取构造函数的参数列表-->得到的是参数列表的类类型
Class[] returnType=con.getParameterTypes();
for(Class class1:returnType){
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
六:方法反射对象的基本操作
1):如何获取一个方法:方法的名称和方法的参数列表唯一确定一个方法
2):方法反射的操作:method.invoke(对象,参数列表)
public class MethodInvoke {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//要获取print(int,int)方法
A a1=new A();
Class c=a1.getClass();
/*
*2.获取方法 名称 参数列表
*/
try {
Method m=c.getMethod("print", new Class[] {int.class,int.class});
//方法的反射操作:用m对象来进行操作,和a1.print(0的效果一样
//方法如果没有返回值返回null,有返回值就返回具体的值
Object o=m.invoke(a1,10,20);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
try {
Method ms=c.getMethod("print", String.class,String.class);
Object o1=ms.invoke(a1, "Hello","World");
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A {
public void print(int a,int b){
System.out.println(a+b);
}
public void print(String a,String b){
System.out.println(a.toUpperCase()+","+b.toUpperCase());
}
}
七:通过Class,Method了解集合泛型的本质
public class Demo6 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ArrayList list=new ArrayList();
ArrayList<Integer >list1=new ArrayList<Integer>();
list1.add(1);
//list1.add("string");是错误的
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1==c2); //return true;说明编译之后集合的泛型是去泛型化的
//反射的操作都是编译之后的操作
/*
* java中集合的泛型,是防止错误消息的输入,只在编译阶段有效果,绕过编译就无效了
* 我们可以通过方法的反射来验证:
*/
try {
Method m=c1.getMethod("add",Object.class);
Object o=m.invoke(list1, "fanxing");//绕过编译操作就绕过了泛型
System.out.println(list1.size());
System.out.println(list1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
最后进行一下总结:
我们要用到反射,首先要获取类,获取类有三种方法:
1):通过类.class来获取
2):通过类实例化之后的对象.getclass()方法来获取
3):通过class.forName("类名")来获取,这也是动态加载,在这里还要分清楚动态加载和静态加载的区别
我们获取到类之后就可以通过方法来获取类中的成员变量(getField),方法(getMethod),方法中的参数列表类型(getParamType),构造函数(getConstructor),进而获得他们的类类型和名称。
当有了这些基础之后我们就可以来进行方法的反射操作,还可以验证泛型的本质。