参考慕课网视频“反射-Java高级开发必须懂得"
一、class类的使用
1、静态的成员,普通数据类型类不是对象
2、类是对象,任何类是Java.lang.Class类的实例对象
3、实例对象的三种表现方式
//1、已知类名:任何一个类都有一个隐含的静态成员变量class
Class foo1 = Foo.class;
//2、已知类的对象,通过getClass()方法获取
Class foo2 = foo.getClass();
//3、通过类路径
Class foo3 = null;
try {
foo3 = Class.forName("com.dongzhic.java.reflect.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
4、通过类的类类型创建该类的对象实例
try {
//需要无参构造方法,foo1,foo2,foo3可通过newInstance()方法
Foo foo4 = (Foo) foo1.newInstance();
foo4.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
二、Java动态加载类
1、Class.forName("类的全称");
不仅表示类的类类型,还表示动态加载类
区分编译和运行
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类
三、获取类的成员变量、成员方法、构造器信息
1、获取类的信息需要知道类的类类型
//获取类的信息,首先要获取类的类类型
//传递的是那个子类的对象,c就是该子类的类类型
Class c = obj.getClass();
//获取类的名称
System.out.println("类的名称"+c.getName());
2、获取类的成员函数
Method[] ms = c.getDeclaredMethods();
for (int i=0; i<ms.length; i++){
//1.得到方法返回值类型的类类型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName()+" ");
//2.得到方法的名称
System.out.print(ms[i].getName()+"(");
//3.获取参数类型->>得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes ) {
System.out.print(class1.getName()+", ");
}
System.out.println(")");
}
3、获取类的成员变量
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
//成员变量类型的类类型
Class fieldType = field.getType();
String fieldTypeName = fieldType.getSimpleName();
String fieldName = field.getName();
System.out.println(fieldTypeName+" "+fieldName);
}
4、获取类的构造器
Constructor[] cons = c.getConstructors();
for (Constructor constructor : cons) {
//1.获取构造器的名称
System.out.print(constructor.getName()+"(");
//2.获取构造器的入参类型的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class param : paramTypes) {
//3.获取构造器入参类型的名称
System.out.print(param.getName()+", ");
}
System.out.println(")");
}
四、方法反射的基本操作
public class A {
public void print () {
System.out.println("Hello World!");
}
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.toLowerCase());
}
}
A a1 = new A();
//获取一个方法就要获取类的信息,获取类的信息,需要获取类的类类型
Class c = a1.getClass();
Method m1 = c.getMethod("print", int.class, int.class);
Method m2 = c.getMethod("print", String.class, String.class);
Method m3 = c.getMethod("print");
Object o = m1.invoke(a1, 10, 20);
o = m2.invoke(a1, "dong", "ZHICHENG");
o = m3.invoke(a1);
五、通过java反射理解集合泛型的本质
1、反射的操作都是编译之后的操作,编译之后集合的泛型是去泛型化
ArrayList list = new ArrayList();
ArrayList<String> list1 = new ArrayList<String>();
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1 == c2);//true
2、java中集合的泛型,只在编译阶段有效,绕过编译失效
/**
* c1 == c2 返回true表示编译之后的结合泛型是去泛型化
* java中集合的泛型,只在编译阶段有效,绕过编译失效
*/
try {
Method m = c2.getMethod("add", Object.class);
//绕过了编译就绕过了泛型
m.invoke(list1, 2);
System.out.println(list1.size()); //2
System.out.println(list1); //[hello, 2]
} catch (Exception e) {
e.printStackTrace();
}