在java中,静态成员和普通数据类型不是对象,其他都是对象。所以类也是对象(实例)。
类是java.lang.Class类的实例对象。
如何表示这个对象呢?看下面的获取类类型
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。new 创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类。通过Class a=Class.forName(arg[0]);此时为动态加载,因为编译时不知道使用哪个类,因此编译没有加载任何类,通过编译。运行时,根据 Javac office.java word (word为arg[0],也是类类型),去确定a是哪个类。这就是动态加载。如果word不存在,此时运行会报错。这就是为何有时候会出现编译通过,运行报错的原因。
动态加载一个好处,就是可以随时增加需要编译的类。例如没有excel类,只有word类,也可以运行,需要excel类时再由程序员写此类(为了能统一控制,word类、excel类需要继承同一个父类或者继承同一个接口)。
反射的操作都是编译后的操作
编译之后集合的泛型是去泛型化的。java的集合泛型,是为了防止输入错误的,只在编译阶段有效,绕过编译就无效了。
获取类类型(class type)
类是Class的对象,获取类类型有三种方式:
Class c1=obj.getClass();
Class c2=Object.class;
Class c3=Class.getname("java.lang.String");
实例:
List list = new List();
Class c1 = list.getClass();
Class c2 = ArrayList.class;
区分两者:
Class c1=int.class;//int的类类型(这是基本数据类型的类类型)
Class c2=Integer.class;//Interger的类类型,这是类的类类型,与上面的int.class不是同一个东西。
通过c1.getName()就可以看出两者的区别
Java反射机制——获取成员变量&构造函数
一、成员变量是java.lang.reflect.Field的对象
1、Field类封装了关于成员变量的操作
2、Field[] fs = c.getFields()方法获取所有public的成员变量Field[]信息
3、c.getDeclaredFields获取的是该类自己声明的成员变量信息
4、field.getType()获得成员类型的类类型
5、field.getName()获得成员的名称
二、构造函数是java.lang.Constructor类的对象
1、通过Class.getConstructor()获得Constructor[]所有公有构造方法信息
2、建议getDeclaredConstructors()获取自己声明的构造方法
3、Constructor.getName():String
4、Constructor.getParameterTypes():Class[]
成员变量也是对象,是java.lang.reflect.Field的对象;
方法反射的操作
//获取该方法所在类的类类型
A a1 = new A();
Class c = a1.getClass();
//通过名称和参数列表获取方法
//c.getMethod()获取的是public 的方法
//c.getDeclaredMethod(方法名,参数列表)获取的是自己声明的方法
Method m = c.getMethod(“print”,newClass[]{int.class,int.class});
//也可以这样写Method m =c.getMethod(“print”,int.class,int.class);
//调用方法 原来的调用是a1.print(10,20);
Object o = m.invoke(a1,new Object[](10,20));
//或者这样写m.invoke(a1,10,20);
//如果方法没有返回值,则返回null,需要强制类型转换
利用反射绕过编译
ArrayList list = new ArrayList();
ArrayList<String> list1 = newArrayList<String>();
list1.add(“hello”);
//这句话是错误的,不能通过编译list1.add(20);
Class c1 = list.getClass();
Class c2 = list1.getClass();
//注意:c1 == c2这是true
Method m = c2.getMethod(“add”,Object.class);
m.invoke(list1,20);
//这样写是可以通过编译的