反射机制是java中底层的动态工作机制,是java的核心特性。
静态:经过java编译器的处理以后就固定下来执行顺序,也就是在编译的过程中就已经确定了的,称为静态
动态:java程序在运行期间,才能确定的处理顺序,称为动态
发射API的作用:
1 动态加载类
2 动态获取类的信息(类型,属性,方法,构造器等)
3 动态创建对象
4 动态访问属性
5 动态访问方法
动态的加载类并且获取类的信息:
在运行期间动态的加载给定的类到内存方法区。
在动态加载类时要使用类全限定名(类全限定名:包名.类名),我们使用Class类中的一个静态方法动态加载给定的类,这个方法是forName(类全限定名),这个方法的返回值是Class类型的对象,可以通过这个对象访问方法区中类的信息。
Class 在Java中代表类型,任何类型都是Class类型的对象,Class类型的对象在java运行期间是唯一的,并且按需加载。
将一个类加载到内存中,我们把它看做一个对象,那么这个对象就是属于Class类型的对象。
这里我们先写一个普通类Student.Java 用于测试java反射机制。
public class Student {
public String name;
public String gender;
public int age;
public Student() {
name = "Tom";
gender = "f";
age = 45;
}
public Student(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return name+","+gender+","+age;
}
}
@Test
public void testClassLoader(){
try {
Class cls=Class.forName("com.xu.test.Student");
//获取类名
String classType=cls.getName();
System.out.println(classType);//result:com.xu.test.Student
//动态获取类中的属性的声明,Field是反射包中的类型,代表属性的信息
Field[] fields=cls.getDeclaredFields();
for(Field field:fields){
/*result:
* class java.lang.reflect.Field name
* class java.lang.reflect.Field gender
* class java.lang.reflect.Field age
*/
System.out.println(field.getClass()+" "+field.getName());
}
//动态获取声明方法中的信息
//Method类型的对象描述了方法的信息
Method []methods=cls.getDeclaredMethods();
for(Method method:methods){
//获取方法参数列表
//Class就是代表类型的,类型列表就是Class类型的数组
Class [] param=method.getParameterTypes();
/*
* result:
* class java.lang.String getName([])
* void setName([class java.lang.String])
* class java.lang.String getGender([])
* void setGender([class java.lang.String])
* int getAge([])
* void setAge([int])
*/
System.out.println(method.getReturnType()+" "+method.getName()+"("+Arrays.toString(param)+")");
}
//动态获取构造方法的信息
Constructor []constructors=cls.getDeclaredConstructors();
for(Constructor constructor:constructors){
Class [] param=constructor.getParameterTypes();
/*
* result:
* com.xu.test.Student []
* com.xu.test.Student [class java.lang.String, class java.lang.String, int]
*/
System.out.println(constructor.getName()+" "+Arrays.toString(param));
}
} catch (ClassNotFoundException e) {
//如果没有找该类的话就抛出此异常
e.printStackTrace();
}
}
/**
* 有三种获取类型Class的方式:
* 1 Class.forName(类全限定名)动态根据类名获取类型
* 2 类型.class静态已知类型情况下获取类型,用于已知类型获取类的信息
* 3 对象.getClass()获取对象的类型
*/
// @Test
public void testClass(){
try {
Class cls=Class.forName("com.xu.test.Student");
Class cls1=Student.class;
System.out.println(cls==cls1);//result:true 说明两个对象是一个对象
Class classType=int.class;
System.out.println(classType);//int
Student s=new Student();
cls=s.getClass();
System.out.println(cls);//class com.xu.test.Student
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 有三种获取类型Class的方式:
* 1 Class.forName(类全限定名)动态根据类名获取类型
* 2 类型.class静态已知类型情况下获取类型,用于已知类型获取类的信息
* 3 对象.getClass()获取对象的类型
*/
// @Test
public void testClass(){
try {
Class cls=Class.forName("com.xu.test.Student");
Class cls1=Student.class;
System.out.println(cls==cls1);//result:true 说明两个对象是一个对象
Class classType=int.class;
System.out.println(classType);//int
Student s=new Student();
cls=s.getClass();
System.out.println(cls);//class com.xu.test.Student
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Class类型经常用于加载包中资源
包中资源:将软件需要用到的只读资源 图片 文件 音乐,经常被打包到包中
Java提供了2种包中资源的读取方式:
1 使用Class类上定义的方法getResource(包路径)是非静态方法必须使用对象调用。
bin
|--se
|-- reflect
| |-- demo.txt
| |-- TestCase.class
|-- net
|-- img.png
包路径:绝对路径,从包的根开始/se/reflect/demo.txt
相对路径: demo.txt 表示此文件与当前Class类型在一个包中
(注:此处的路径是以java的包为路径,不是操作系统文件路径!)
getResource(路径)返回值是URL类型的对象 ,在URL类型中有openStream()方法,可以返回流对象inputStream。getResourceAsStream()是 getResource与openStream的合体。
@Test
public void testgetResource() throws IOException{
Class cls=this.getClass();
URL txt=cls.getResource("demo.txt");
InputStream in=txt.openStream();
in.close();
ClassLoader loader = cls.getClassLoader();
URL img = loader.getResource("se/net/img.png");
in= img.openStream();
System.out.println(in);
in.close();
}
2 ClassLoader是Java类的加载器,将一个类读取到方法区中,就是ClassLoader的功劳。ClassLoader中也定义了getResource(路径)方法用于加载资源,路径也是包路径,是一种绝对路径但是不能写“/” 如:se/reflect/demo.txt
动态创建对象:
1 使用无参数构造器创建对象,Class类提供的便捷方法newInstance方法。如果没有无参构造器抛出异常。
2 使用有参数构造器创建对象
先找到构造器,再调用构造器,并且传递参数调用构造器创建对象
@Test
public void testConstructor(){
try {
Class cls=Class.forName("com.xu.test.Student");
Object obj=cls.newInstance();
System.out.println(obj);
//事先知道构造器的参数列表
// Class [] types={String.class,String.class,int.class};
// Object[] params={"Jerry","f",23};
//获得指定参数列表的构造器
// Constructor constructor=cls.getConstructor(types);
Constructor constructor=cls.getConstructor(String.class,String.class,int.class);
//执行构造方法
// obj=constructor.newInstance(params);
obj=constructor.newInstance("Jerry","f",23);
System.out.println(obj);
} catch (InstantiationException e) {
//没有无参构造器异常
e.printStackTrace();
} catch (IllegalAccessException e) {
//没有访问权限异常
e.printStackTrace();
} catch (ClassNotFoundException e) {
//没有找到类异常
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
//参数错误异常
e.printStackTrace();
} catch (InvocationTargetException e) {
//方法执行异常,获取真正抛出异常的原因
Throwable x=e.getCause();
x.printStackTrace();
// e.printStackTrace();
}
}
//动态访问对象的属性
// @Test
public void testField(){
try {
String fieldName="name";
Class cls = Class.forName("com.xu.test.Student");
Object obj=cls.newInstance();
//反射API在类上找到属性信息
Field field=cls.getField(fieldName);
//在对象上获得属性的值
Object name=field.get(obj);
System.out.println(name);
field.set(obj, "Jerry");
name=field.get(obj);
System.out.println(name);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void testMethod(){
try {
Class cls=Class.forName("com.xu.test.Student");
//从类中获取方法的信息
Method method=cls.getMethod("getGender");
Object obj=cls.newInstance();
//在对象上执行方法,obj在执行方法期间传递给了this变量
System.out.println(method.invoke(obj));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}