------- android培训、java培训、期待与您交流! ----------
反射(Reflect):就是将java类中的各种成分映射到相应的类。
Java反射机制提供如下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
1. 动态语言:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言
2. java的动态机制:但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
3. Class类
a) Java有个Object 类是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等其中getClass()返回一个Class 对象。
b) Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象,注意它的private Class() {},意指不允许任何人经由编程方式产生Class object。是的,其object 只能由JVM 产生。
4. 获取对应的Class
a) 对象.getClass() 如: Class c=”abc”.getClass();
b) Class.getSuperclass() 如:Class c2 =c1.getSuperclass();//获得父类
c) static method--Class.forName()(最常被使用)
如:Classc=Class.forName(“java.util.LinkedList$Entry”);
d) 基本类型的包装类的TYPE 如:Classc=Integer.TYPE 返回原生类型,这里是int
e) 类名.Class 如Classc=String.Class
5. 获取Fields JAVA 的Class<T>类提供了几个方法获取类的属性。
a) publicField getField(String name) 它反映此 Class 对象所表示的类或接口的指定公共成员
b) publicFileld getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段(包括private)
c) publicField[] getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此Class 对象所表示的类或接口的所有可访问公共字段
d) publicField[] getDeclaredField() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段(包括private)
6. 注意:如果用getDeclaredField或getDeclaredField获取了private 权限的成员时又想要对其访问时需要用到 暴力反射 Field f=p.getClass().setAccessible(true); 设置可访问性
7. 获取Method
a) publicMethod getMethod(String name,Class<?>…parameterType) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法
b) publicMethod[] getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
c) publicMethod getDeclaredMethod(Stringname,Class<?>…parameterTyprs返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法
d) publicMethod[] getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
8. 注意:调用此函数使用 public Object invoke(Object obj,Object…args)
Method method=str.getClass().getMethod(“charAt”,int.class)
Method.invoke(str,0);//jdk 1.5
9. 接收数组参数的成员方法的反射
a) 如main(String[] args)函数 Class clazz=Class.forName(“main”,String[].class)
由于jdk1.4和jdk1.5的invoke发生了变化,由1.4的数组参数变成了1.5的可变个数,如果参数本身是非基本类型数组则会将数组进行拆分,所以要对这里进行特殊处理 如 clazz.invoke(null,Object[]{new String[]{“123”,”abc”}})或
calzz.invoke(null,(Object)new String[]{“123”,”abc”});
10. 获取类的Constructor通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
a) publicConstructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此Class 对象所表示的类的指定公共构造方法
b) publicConstructor<?>[] getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此Class 对象所表示的类的所有公共构造方法
c) publicConstructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此Class 对象所表示的类或接口的指定构造方法
d) publicConstructor<?>[] getDeclaredConstructors() 返回Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。它们是公共、保护、默认(包)访问和私有构造方法
12. 反射在框架中的开发框架与反射的关系:框架可以通过反射机制预先搭建引用实际未开发好的功能,而工具类是被用户所调用,框架则是调用用户提供的类
13. 用类加载器的方式管理资源和配置文件:通过加载配置文件中的属性加载所配置的类
package cn.itcast.reflect.demo;
import cn.itcast.domain.Person;
public class Reflect_GetClassDemo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
/*
* 要想获取字节码文件中的成员,必须要先获取字节码文件对象。
* 获取字节码文件对象的方式:
* 1,通过Object类中的getClass方法。
* 2,使用的任意数据类的一个静态成员class,所有的数据类型都具备的一个属性。
* 3,使用Class类中的forName方法。通过给定类名来获取对应的字节码文件对象。
*/
getClass_3();
}
public static void getClass_3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String className = "cn.itcast.domain.Person";
/*
* 1,通过给定的类名称,加载对应的字节码文件,并封装成字节码文件对象Class.
*/
Class clazz = Class.forName(className);
// System.out.println(clazz);
//通过newInstance()就可以创建字节码对象所表示的类的实例。
/*
* 2,通过new创建给定的类的实例。
* 3,调用该类的构造函数。
* 通常被反射的类都会有提供空参数的构造函数。
* 没有对应的构造函数,会报InstantiationException
* 如果有提供,但是权限不够,会报IllegalAccessException
*
*/
Object obj = clazz.newInstance();
/* Person p = new Person();
* 1,加载Person类,并将Person类封装成字节码文件对象。
* 2,通过new创建Person对象。
* 3,调用构造函数对对象初始化。
*/
System.out.println(obj);
}
public static void getClass_2() {
Class clazz = Person.class;
}
public static void getClass_1() {
Person p1 = new Person();
Person p2 = new Person();
Class clazz1 = p1.getClass();
Class clazz2 = p2.getClass();
System.out.println(clazz1 == clazz2);//true
// System.out.println(clazz1.getName());//获取类的名字。
}
}
//类Person
package cn.itcast.domain;
public class Person {
private String name;
private int age;
public Person() {
super();
System.out.println("person run");
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public void show(String name,int age){
System.out.println("show run...name="+name+",age="+age);
}
public static void staticShow(){
System.out.println("static show run");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}