本文参考imooc的教学视频:https://www.imooc.com/video/3736 编写
1、Class类的说明
a、java是面向对象的语言,在java中一切都是对象。
b、类也是对象,类是java.lang.Class类的实例对象, 例如说:String类的类类型用 String.class表示;基本的数据类型 都存在类类型。
c、Class.forName("类的全称"); 不仅表示了,类的类类型,还代表了动态加载类。
d、编译时加载类是静态加载类(比如new 类),运行时刻加载类是动态加载类(比如Class.forName)
2、获取类的全部信息(用java实现); 想获取类的信息,那么必须想获取类的类类型
public class ClassInfoUtil {
/**
* 获取函数信息
* */
public static void queryMethodInfo(Object object){
//获取类的类类型
Class objClass = object.getClass();
//获取类的名称
System.out.println("对象"+object+"的类名为:"+objClass.getName());
/*Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有的【public】的函数,包括父类继承而来
* getDeclaredMethods()获取的是 该类自己声明所有方法,无访问权限的限制。当时父类的就不能显示,必须自己声明的
* */
Method[] methods = objClass.getMethods();
for (Method method : methods) {
//得到方法的返回值类型的类类型
Class returnType = method.getReturnType();
//获取方法的名字
String name = method.getName();
System.out.println("方法的返回类型: "+returnType.getName()+"方法的名字"+name);
//获取参数的类型----》得到的是参数列表的类型的类类型
Class[] paramType = method.getParameterTypes();
for (Class class1 : paramType) {
System.out.println(" 入参的类型名字"+class1.getName());
}
}
}
public static void printFeildInfo(Object object) {
/*
* 成员变量也是对象
* java.lang.reflect.Field
* Filed类封装了成员变量的操作
* getFields()方法来获取的是所有 public 的成员变量的信息
* getDeclaredFields()获取的是该类自己声明的成员变量的信息,无访问权限限制
* */
//获取类的类类型
Class objClass = object.getClass();
Field[] fs = objClass.getFields();
for (Field field : fs) {
//得到成员变量的类型的类类型:如果成员变量是int,那么返回的就是int.class
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName+" "+fieldName);
}
}
public static void printConstructorInfo(Object object) {
/*
* 构造函数也是对象
* java.lang.reflect.Field
* Filed类封装了成员变量的操作
* getConstructor()方法来获取的是所有 public 的构造函数的信息
* getDeclaredConstructors()获取的是该类自己声明的构造函数信息
* */
//获取类的类类型
Class objClass = object.getClass();
Constructor[] constructors = objClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.print(constructor.getName()+"(");
//获取构造函数的的参数列表--》得到的参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
}
3、方法反射的基本操作
public class TestClass {
public static void main(String[] args) {
//要获取print(int,int)方法,1、首先获取一个方法就是获取类信息,获取类信息首先要获取类的类类型
Cal calObject = new Cal();
Class c = calObject.getClass();
//获取方法 名称和参数列表
//getDeclaredMethod()获取类声明的方法
//getMethod() 获取public方法,包括继承父类的
try {
//... 表示可变参数 两种写法一种,一种是直接传数组 new Class[]{int.class,int.class},另一种写全部入参int.class,int.class
Method method = c.getDeclaredMethod("print", new Class[]{int.class,int.class});
//方法的反射 如果被调用的方法有返回参数,即返回。如果没有则返回null
//Object o = method.invoke(calObject,new Object[]{5,6});//两种写法一种,一种是直接传数组(calObject,new Object[]{5,6}),另一种写全部入参invoke(calObject,5,6)
Object o = method.invoke(calObject,5,6); //等同于 calObject.print(5, 6);
System.out.println(o);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("***************************************************");
Cal strObject = new Cal();
Class strClass = strObject.getClass();//获取类的类类型
try {
Method method = strClass.getDeclaredMethod("print", new Class[]{String.class,String.class});
Object o = method.invoke(strObject, "aBcD","xYz");
System.out.println(o);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//一个类文件当中,只能有一个类是public 修饰的,然后如果再写一个类的话,默认是protected的修饰权限,一般这样安排的话是比较亲密的关系
class Cal{
public void print(int a, int b){
System.out.println(a+b);
}
public String print(String a, String b){
System.out.println(a.toUpperCase()+" "+b.toLowerCase());
return "1111";
}
}
4、java 反射了解集合泛型的本质【重要,仔细阅读思考代码有提升】
public class TestClass {
public static void main(String[] args) {
ArrayList list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<String>();
list2.add("hello");
//list2.add(20); //编译的时候会报错
Class c1 = list1.getClass();
Class c2 = list2.getClass();
//反射的操作都是编译以后的操作
System.out.println(c1 == c2);
/*
* c1==c2结果返回ture说明编译之后集合的泛型是去泛型化的
* 结论:java中集合的泛型,是防止错误输入的,只在编译阶段有效
* 绕过编译就无效了
* 验证:我们可以通过方法的反射来操作,绕过编译,只在运行的时候有效
* */
try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list2, 20);//绕过了编译操作就绕过了泛型,这时候20就加到了list2中
System.out.println(list2.size());
System.out.println(list2);
/* for (String string : list2) {
}*/ //现在不能这样遍历
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}