1、Class类
在面向对象的世界里,万事万物皆对象。类是对象,类是java.lang.Class类的实例对象。
任何一个类都是Class的实例对象,这个实例对象有三种表示方法:
- //1、任何一个类都有一个隐含的静态成员class
- Class c1 = Foo.class;
- //2、已经知道该类的对象,通过getClass方法
- Class c2 = f.getClass();
- /**
- * c1,c2表示了Foo类的类类型(Class Type)
- * 类是class类的实例对象
- * 我们称这个对象为该类的的类类
- */
- //3、通过Class.forName方法
- Class c3 = null;
- try {
- c3 = Class.forName("cn.fedomn.demo.Foo");
- } catch (Exception e) {
- e.printStackTrace();
- }
- /**
- * 我们可以通过类的类类型创建该类的对象实例-->通过c1,c2,c3创建Foo类型的对象
- */
- try {
- Foo f2 = (Foo)c1.newInstance();//需要有无参数的构造方法
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
//1、任何一个类都有一个隐含的静态成员class Class c1 = Foo.class; //2、已经知道该类的对象,通过getClass方法 Class c2 = f.getClass(); /** * c1,c2表示了Foo类的类类型(Class Type) * 类是class类的实例对象 * 我们称这个对象为该类的的类类 */ //3、通过Class.forName方法 Class c3 = null; try { c3 = Class.forName("cn.fedomn.demo.Foo"); } catch (Exception e) { e.printStackTrace(); } /** * 我们可以通过类的类类型创建该类的对象实例-->通过c1,c2,c3创建Foo类型的对象 */ try { Foo f2 = (Foo)c1.newInstance();//需要有无参数的构造方法 } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
2、动态加载类
首先搞清楚,动态加载类和静态加载类的区别
- 静态加载类:编译时刻加载类
- 动态加载类:运行时刻加载类(如功能型类 数据库驱动,需要用时才加载进来)
注意:new 创建对象 是静态加载类,在编译时刻就需要加载所有的可能使用到的类
动态加载类,解决用的时候才加载该类,如下
其中cn.fedomn.demo.Word类implements OfficeAble
- public class Office {
- public static void main(String[] args){
- try {
- //动态加载类,在运行时刻加载
- Class c = Class.forName("cn.fedomn.demo.Word");
- //通过类型转换,创建该类对象
- OfficeAble oa = (OfficeAble)c.newInstance();
- oa.start();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class Office { public static void main(String[] args){ try { //动态加载类,在运行时刻加载 Class c = Class.forName("cn.fedomn.demo.Word"); //通过类型转换,创建该类对象 OfficeAble oa = (OfficeAble)c.newInstance(); oa.start(); } catch (Exception e) { e.printStackTrace(); } } }
3、获取方法信息
- public class ClassUtil {
- public static void printClassMessage(Object obj){
- //首先获取类的类类型
- Class c = obj.getClass();
- //获取类的名称
- System.out.println("类的名称是:"+c.getName());
- /**
- * Method类,方法对象
- * 一个成员对象就是一个Method对象
- * getMethods()方法获取的是所以public的函数,包括父类继承而来的
- * getDeclaredMethods()方法获取的是所有该类自己声明的方法,不问访问权限
- */
- Method[] ms = c.getMethods();c.getDeclaredMethods();
- for(int i=0;i<ms.length;i++){
- //获取方法返回值类型--->得到方法的返回值类型 的 类类型
- Class returnType = ms[i].getReturnType();
- System.out.print(returnType.getName()+" ");
- //得到方法的名称
- System.out.print(ms[i].getName()+"(");
- //获取参数类型--->得到的是参数列表类型 的 类类型
- Class[] paramTypes = ms[i].getParameterTypes();
- for(Class class1 : paramTypes){
- System.out.print(class1.getName()+",");
- }
- System.out.println(")");
- }
- }
- }
public class ClassUtil { public static void printClassMessage(Object obj){ //首先获取类的类类型 Class c = obj.getClass(); //获取类的名称 System.out.println("类的名称是:"+c.getName()); /** * Method类,方法对象 * 一个成员对象就是一个Method对象 * getMethods()方法获取的是所以public的函数,包括父类继承而来的 * getDeclaredMethods()方法获取的是所有该类自己声明的方法,不问访问权限 */ Method[] ms = c.getMethods();c.getDeclaredMethods(); for(int i=0;i<ms.length;i++){ //获取方法返回值类型--->得到方法的返回值类型 的 类类型 Class returnType = ms[i].getReturnType(); System.out.print(returnType.getName()+" "); //得到方法的名称 System.out.print(ms[i].getName()+"("); //获取参数类型--->得到的是参数列表类型 的 类类型 Class[] paramTypes = ms[i].getParameterTypes(); for(Class class1 : paramTypes){ System.out.print(class1.getName()+","); } System.out.println(")"); } } }
4、获取成员变量和构造函数信息
- /**
- *获取成员变量信息
- */
- public static void printFieldMessage(Object obj) {
- Class c = obj.getClass();
- /**
- * 成员变量也是对象
- * java.lang.reflect.Field
- * Field类封装了关于成员变量的操作
- * getField()方法获取所有public的成员变量的信息
- * getDeclaredField()获取的是该类自己声明的成员变量的信息
- */
- Field[] fs = c.getDeclaredFields();
- for(Field field : fs){
- //得到成员变量的类型的类类型
- Class fieldType = field.getType();
- String typeName = fieldType.getName();
- //得到成员变量的名称
- String fieldName = field.getName();
- System.out.println(typeName+" "+fieldName);
- }
- }
- /**
- * 获取对象构造函数的信息
- */
- public static void printConMessage(Object obj){
- Class c = obj.getClass();
- /**
- * 构造函数也是对象
- * java.lang.Constructor中封装了构造函数的信息
- * getConstructors获取所有的public的构造函数
- * getDeclaredConstructors得到所有的构造函数
- */
- Constructor[] cs = c.getDeclaredConstructors();
- for(Constructor constructor : cs){
- System.out.print(constructor.getName()+"(");
- //获取构造函数的参数列表-->得到参数列表的类类型
- Class[] paramTypes = constructor.getParameterTypes();
- for(Class class1 : paramTypes){
- System.out.print(class1.getName()+",");
- }
- System.out.println(")");
- }
- }
/** *获取成员变量信息 */ public static void printFieldMessage(Object obj) { Class c = obj.getClass(); /** * 成员变量也是对象 * java.lang.reflect.Field * Field类封装了关于成员变量的操作 * getField()方法获取所有public的成员变量的信息 * getDeclaredField()获取的是该类自己声明的成员变量的信息 */ Field[] fs = c.getDeclaredFields(); for(Field field : fs){ //得到成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); //得到成员变量的名称 String fieldName = field.getName(); System.out.println(typeName+" "+fieldName); } } /** * 获取对象构造函数的信息 */ public static void printConMessage(Object obj){ Class c = obj.getClass(); /** * 构造函数也是对象 * java.lang.Constructor中封装了构造函数的信息 * getConstructors获取所有的public的构造函数 * getDeclaredConstructors得到所有的构造函数 */ Constructor[] cs = c.getDeclaredConstructors(); for(Constructor constructor : cs){ System.out.print(constructor.getName()+"("); //获取构造函数的参数列表-->得到参数列表的类类型 Class[] paramTypes = constructor.getParameterTypes(); for(Class class1 : paramTypes){ System.out.print(class1.getName()+","); } System.out.println(")"); } }
5、方法反射操作
method.invoke(对象,参数列表)
- public class MethodDemo1 {
- public static void main(String args[]){
- //要获取print(int,int)方法
- //1、要获取一个方法就是获取类的信息,获取类的信息 首先获取类的类类型
- A a = new A();
- Class c = a.getClass();
- /**
- * 2、获取方法 名称和参数列表来决定
- * getMethod获取的是public方法
- * getDeclaredMethod获取自己声明的方法
- */
- try {
- Method m = c.getMethod("print", int.class,int.class);
- //方法的反射操作
- //用m对象来进行方法调用
- //等同于a.print(10, 20);
- //方法如果没有返回值返回null,有返回值返回具体返回值
- try {
- Object o = m.invoke(a, 10,20);
- } catch (IllegalAccessException | IllegalArgumentException
- | InvocationTargetException e) {
- e.printStackTrace();
- }
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (SecurityException e) {
- 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.toLowerCase());
- }
- }
public class MethodDemo1 { public static void main(String args[]){ //要获取print(int,int)方法 //1、要获取一个方法就是获取类的信息,获取类的信息 首先获取类的类类型 A a = new A(); Class c = a.getClass(); /** * 2、获取方法 名称和参数列表来决定 * getMethod获取的是public方法 * getDeclaredMethod获取自己声明的方法 */ try { Method m = c.getMethod("print", int.class,int.class); //方法的反射操作 //用m对象来进行方法调用 //等同于a.print(10, 20); //方法如果没有返回值返回null,有返回值返回具体返回值 try { Object o = m.invoke(a, 10,20); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { 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.toLowerCase()); } }
6、通过反射了解集合泛型的本质
注意:反射的操作(class method field)都是在编译时候的操作,是运行时刻执行的
下例中:对ArrayList<String>插入int类型的值,就是利用反射invoke,绕过编译实现插入。
- public static void main(String args[]){
- ArrayList list1 = new ArrayList();
- ArrayList<String> list2 = new ArrayList<String>();
- //list2.add(20);错误只能插入String
- list2.add("hello");
- Class c1 = list1.getClass();
- Class c2 = list2.getClass();
- System.out.println(c1==c2);
- //反射的操作都是编译之后的操作
- /**
- * c1==c2返回true,说明编译之后集合的泛型是去泛型化的
- * Java中集合的泛型,是防止错误输入的,只在编译阶段有效 编译后就无效了
- * 验证:通过方法的反射来操作,绕过编译
- */
- try {
- Method m = c2.getMethod("add", Object.class);
- m.invoke(list2, 10);//绕过编译操作 就绕过了泛型 插入成功
- //这个时候就不能for-each遍历了
- System.out.println(list2);
- } catch (Exception e) {
- }
- }