《一》、Class类的使用
一、类也是对象,是java.lang.Class的实例对象
二、任何一个类都是Class类的实例对象,有三种表示方式:(Class的构造方法是私有的,只允许JVM调用,因此无法通过关键词new创建Class的实例对象)
- 1、通过类名.class创建,也即说明任何一个类都有一个静态的成员变量class
- 如:
Class c1 = Foo.class;
- 如:
- 2、 通过类的对象的getClass方法
- 如:
Foo foo1 = new Foo();
Class c2 = foo1.getClass();
- 如:
3、通过Class的forName方法传入类的全限定名获取
- 如:
Class c3 = null;
(会有ClassNotFoundException)
c3 = Class.forName("com.imooc.reflect.Foo");
- 如:
c1、c2表示的Foo类的类类型(class type)
- 万事万物皆对象,类也是对象,是Class类的实例对象,这个对象称为类的类类型
- 可以通过类的类类型创建该类的对象
§ 如:Foo foo2 = (Foo)c1.newInstance();
- 一个类只能是Class的一个实例对象,无论通过三种方法中的哪一种获取都一样
《二》、动态加载类
- 三种方法中,c1、c2为静态加载类(编译时加载),而c3为动态加载类(运行时加载)
1、new 出来的都是静态加载类,一招出错,全盘皆输;
2、动态加载类
Class c = Class.forName(args[0]);
OfficeAble oa = (OfficeAble)c.newInstance();//OfficeAble定义的功能类型接口
《三》、获取方法信息
- 1、基本的数据类型,关键字都存在类类型。
例子:int.class String.class Double.class
Class c = obj.getClass();
方法也是对象: - Method类:方法对象
Method[] ms = c.getMethods();//获取所有public方法,包括父类继承的方法
ms.getName();//方法的名称
Class returnType = ms.getReturnType();
returnType.getName();//返回值类型
Class[] paramTypes = ms.getParameterTypes();//参数的类类型数组
方法实例
public class ClassUtil {
public static void printClassMessage(Object obj){
//要获取类的信息,首先要获取类的类类型
Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
//获取类的名称
System.out.println("类的名称是:" + c.getName());
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()获取的是所有public函数,包括父类继承而来的
* getDeclaredMethods()获取的是该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods(); //c.getDeclaredMethods();
for (Method method : ms) {
//得到方法的返回值类型
System.out.print(method.getReturnType().getSimpleName()+" ");
//得到方法的名称
System.out.print(method.getName()+"(");
//得到参数类型---->得到的参数列表类型的类类型
Class[] paramTypes = method.getParameterTypes();
if(paramTypes.length==0){
//若没有参数,则直接返回右括号
System.out.println(")");
}else {
int i = 0;
//遍历打印到倒数第二个参数
for(;i < paramTypes.length-1;i++){
System.out.print(paramTypes[i].getSimpleName()+",");
}
//打印出最后一个参数和右括号,并换行,可以避免多出一个逗号
System.out.println(paramTypes[i].getSimpleName()+")");
}
}
}
}
《四》、获取成员变量构造函数信息
- 获取类的成员对象
Field[] = c.getFields()
获取该类自己生命所有成员变量的信息
Field[] = c.getDeclaredFieds()
1、成员变量也是对象
- java.lang.reflect.Field
- Filed类封装了成员变量的操作
- getFields()方法获取的是所有public成员的信息
2、构造函数也是对象;
- java.lang.Constructor中封装了构造函数的信息;
- getConstructors获取所有的public的构造函数;
- getDeclaredConstructors得到所有的构造函数;
Class c = obj.getClass();
// Field[] field = c.getFields();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 得到成员变量的类型的类类型
Class fieldType = field.getType();
System.out.print("成员变量类型:"+fieldType.getName());
// 得到成员变量名称
String fieldName = field.getName();
System.out.print(" 成员变量名称:"+fieldName);
System.out.println();
}
《五》、方法反射的基本操作
- (1)如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法 - (2)方法的反射的操作
mentod.invoke(对象,参数列表)
A a1= new A();
Class c = a1.getClass();
Method method = c.getMethod("print",new Class[]{int.class,int.class});
// Method method = c.getMethod("print",int.class,int.class); // 另一种写法
method.invoke(a1);//等同于a1.print();的效果
《六》、通过反射了解集合泛型的本质
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* 通过反射了解集合泛型的本质
* @author shm
*
*/
public class MethodDemo02 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("hello");
list.add(20);
ArrayList<String> list1 = new ArrayList<String>();
list1.add("hello");
//list1.add(20);//这个加入是错误的:The method add(int, String) in the type ArrayList<String> is not applicable for the arguments (int)
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1==c2);
//反射的操作都是编译后的操作
/**
* c1=c2结果返回TRUE说明编译后集合的泛型是去泛型化的
* java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译后就无效了
* 验证:我们可以通过反射操作来绕过编译
*/
try {
Method method = c2.getMethod("add", Object.class);
method.invoke(list1, 20);
System.out.println(list1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}