JAVA反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
ava的反射是大多数框架的基础,如struts,Hibernate和Spring等。
通过反射机制可以获得一个陌生的java类的所有信息。如属性,方法,构造器,修饰符等。
也就是说反射是为了能够动态地加载一个类,动态地调用一个方法,动态地访问一个属性等动态的要求而设计的。它的出发点在于JVM会为每个 类创建一个java.lang.Class类的实例,通过这个对象可以获得这个类的信息。
反射机制的API主要集中在java.lang.reflect包下面。
获得对象运行时的类,可以实现动态创建对象和编译,体现出很大的灵活性
Class.class是对所有类抽象出来的类
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Java反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
Class类:
众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。
当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。
Class对象
Class并没有public constructor。它的private Class() {},意指不允许任何人经由编程方式产生Class object。其object 只能由JVM 产生。
获取方法
1)运用getClass()
注:每个class 都有此函数
String str = “abc”;
Class c1 = str.getClass();
2)运用Class.getSuperclass()
Button b = new Button();
Class c1 = b.getClass();
Class c2 = c1.getSuperclass();
3)运用static method——Class.forName()(最常被使用)
Class c1 = Class.forName (“java.lang.String”);
4)运用primitive wrapper classes的TYPE 语法
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
5)访问所有类都会有的静态的class属性。
Class clazz3 = Person.class;
Class intClazz = int.class;
Class voidClazz = void.class;
Field类
Field类,代表的是类的属性(字段)
Field对象通过Class类的getDeclaredFields()或getDeclaredField()方法获得。
获得类中定义的所有属性
1.获得所有属性对象组成的数组,包括私有,非继承的,
Field[] fields = clazz.getDeclaredFields();
2.遍历该数组,获得每个元素分别表示每个属性
for(Field f : fields) {
3.打印属性的类型和名字
String name = f.getName();
String type = f.getType().getName();
//Object value = f.get(obj); obj为要访问的属性所在的对象名,访问类private的成员,会抛非法访问异常
System.out.println("类型:" + type + "属性名:" + name);
}
访问以下obj对象私有name属性,并且改变name属性
Field nameField = clazz.getDeclaredField(“name”);//此处为私有属性
nameField.setAccessible(true); //取消Java编译器对该属性的访问权限语法检查用反射机制可以打破封装性,导致了java对象的属性不安全。
Object value = nameField.get(obj);//用get方法指定是哪个对象的属性
System.out.println(value);
nameField.set(obj, “wangwu”);
Method setNameMethod = clazz.getDeclaredMethod(“setName”, String.class);//第二个为可变形参类型
//Method setNameMethod = clazz.getDeclaredMethod(“setName”, new Class[]{String.class});
setNameMethod.invoke(obj, “lisi”);//第二个为可变实参数
获得类中定义的构造方法
Constructor[] constructors = clazz.getConstructors();
for(Constructor con : constructors) {
String name = con.getName();
System.out.print(“构造函数:” + name + “,参数类型依次为:”);
Class[] parameterTypes = con.getParameterTypes();
for(Class parameterType : parameterTypes)
System.out.print(parameterType.getName() + ” “);
System.out.println();
}
调用有参的构造函数,创建对象
Constructor constructor = clazz.getConstructor(new Class[]{String.class, int.class});
//GDK1.5之前都是用的数组,后来才用的可变参数,向前兼容所以数组也可以
或Constructor constructor = clazz.getConstructor(String.class, int.class);即参数是String与int类型的构造函数,
Person person = (Person) constructor.newInstance(“zhaoliu”, 33);
对数组参数
Constructor constructor=clazz.getConstructor(int[].class);
再(Person)constructor.newInstance(new Object[]{new int[]{参数,参数}})
System.out.println(person);
*/
用默认的构造函数创建对象
Class clazz= Person.class; Person you=(Person)clazz.newInstance();因为返回类型为object所以要强转
先获得构造方法再来实例化一个类是很麻烦的,会涉及到构造方法的查找和调用。所以要养成一个好习惯,没自定义一个类都提供一个无参的构造方法。这样就可以直接调用newInstance()方法来创建对象。
获得包名
Package pack = clazz.getPackage();
System.out.println(“包名为:” + pack.getName());
获得修饰符
/*int num = clazz.getModifiers();//当有多个修饰符时会相加
System.out.println(num);
if(num==Modifier.PUBLIC)
System.out.println(“这个类是public的”);
*/
if(Modifier.isPublic(num))
System.out.println(“这个类是public的”);
if(Modifier.isAbstract(num))
System.out.println(“这个类是Abstract的”);
if(Modifier.isInterface(num))
System.out.println(“这是一个接口”);