反射的概念:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
一切事物都是对象,构造方法,成员变量,成员方法都是事物,分别对应它的类,对应对象。通过类的字节码,可以分别调用方法得到构造方法对象,成员变量对象,成员方法对象,有对象可以调用各种类里面方法。
——通俗点,反射就是通过获取类的字节码文件对象,调用方法得到类的一切东西,运行的是字节码(动态),这个通过动态获取类的信息方式或者说机制叫做Java语言反射机制。
反射的特点:
Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。
反射是框架的灵魂! 反射的灵魂是字节码文件对象。反射其实就是将运行时一个类的各个部分重新拼装成一个类的过程。
反射的作用:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象(不用new,直接使用字节码文件对象就能给你创建对象)
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法。通过反射甚至可以调用到private方法。
生成动态代理(代理模式中的一种)
假如有两个开发者,开发者一在写程序的时候,需要使用第开发者二所写的类,但开发者二并没完成他所写的类。那么第开发者一的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让开发者一在没有得到开发者二所写的类的时候,来完成自身代码的编译。
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过eclipse和idea。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。
反射底层原理:
蓝色实线部分为编译阶段,红色实线部分为运行阶段,当一个类经过编译器编译后就会生成该类的字节码文件。当程序运行时,如果在代码中使用到类的字节码文件对象的时候(注意是一个对象,字节码文件对象可以通过:类名.class、Class.forName(“类的全限定名”)、类名.getClass()获取),JVM就会调用分配给用户使用的ClassLoader来对该类进行加载,将这个类的字节码文件加载成一个字节码文件对象保存到数据区中,ClassLoader将类中的构造函数、成员变量、成员方法分别转化成对象存放到对应的数据区中,而后,就可以通过获取这些对象来进行对相应的操作。
小例子:通过反射调用User(JavaBean)类的构造函数创建对象、遍历输出成员变量、方法的名字,改变某个(私有)共有成员变量的值、调用某个(私有)公有的成员方法。
例子用到的User类
public class User {
private String name;
private int age;
private int idCard;
private String sex;
private String description;
public User() {
}
public User(String name, int age, int idCard, String sex, String description) {
this.name = name;
this.age = age;
this.idCard = idCard;
this.sex = sex;
this.description = description;
}
private void method1(){
System.out.println("这是一个无参数私有的方法");
}
private void method2(String str){
System.out.println("这是一个有一个String类型参数私有的方法,参数是:"+str);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getIdCard() {
return idCard;
}
public void setIdCard(int idCard) {
this.idCard = idCard;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", idCard=" + idCard + ", sex=" + sex + ", description="
+ description + "]";
}
}
测试ReflectTest类
public class ReflectTest {
/**
* 要使用反射必须有字节码文件对象
* 获取字节码文件对象的三种方式
* 1.Class.forName("类的全限定名"),这种方式最常使用----注册驱动 Class<?> clazz = Class.forName("类的全限定名");
* 2.类名.class----DBUtils中使用BeanHandler的构造函数时传参数。Class clazz = 类名.class;
* 3.对象名.getClass(),------在不知道类名的情况下
*/
private Object obj;
//使用反射调用无参构造函数创建对象
@Test
public void test0(){
try {
Class clazz = Class.forName("com.yanghao.bean.User");
Object o = clazz.newInstance();
System.out.println(o);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//使用反射调用有参构造函数创建对象
@Test
public void test1(){
try {
Class<?> clazz = Class.forName("com.yanghao.bean.User");
Class[] params = {String.class,int.class,int.class,String.class,String.class};
Constructor<?> constructor = clazz.getConstructor(params);
obj = constructor.newInstance("张三",15,4417811,"男","张三是三");
System.out.println(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//使用反射获取类的共有成员变量遍历输出
@Test
public void test2(){
try {
Class clazz = Class.forName("com.yanghao.bean.User");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//使用反射获取类的所有成员变量(公有和私有)遍历输出每个成员变量的值
@Test
public void test3(){
try {
//test1();
Class<?> forName = Class.forName("com.yanghao.bean.User");
Field[] declaredFields = forName.getDeclaredFields();
for (Field field : declaredFields) {
int modifiers = field.getModifiers();
Object value = null;
if(modifiers == Modifier.PUBLIC){
value = field.get(obj);
}
else{
field.setAccessible(true);
value = field.get(obj);
}
System.out.println(field.getName()+":"+value);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取User类中所有的公有方法
@Test
public void test4(){
try {
Class clazz = Class.forName("com.yanghao.bean.User");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取User类中所有的方法,包括公有方法和和私有方法
@Test
public void test5() {
try {
Class clazz = Class.forName("com.yanghao.bean.User");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
method.setAccessible(true);
System.out.println(method.getName());
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//调用User类里面的私有方法Method1和Method2
@Test
public void test6(){
try {
Class<?> clazz = Class.forName("com.yanghao.bean.User");
Object newInstance = clazz.newInstance();
Method method1 = clazz.getDeclaredMethod("method1");
method1.setAccessible(true);
method1.invoke(newInstance);
Method method2 = clazz.getDeclaredMethod("method2", String.class);
method2.setAccessible(true);
method2.invoke(newInstance, "我是参数");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
内省机制(Introspector)
内省机制就是通过反射区访问JavaBean对象的属性,通过内省机制可以很方便的调用一个JavaBean类里面的get和set方法。使用方法如下:
- 获取JavaBean对象中某个成员变量的get和set方法,获取变量的值并赋值:
//创建对象
User user=new User();
//创建属性描述器
PropertyDescriptor descriptor=new PropertyDescriptor("name",User.class);
//获得读方法
Method readMethod=descriptor.getReadMethod();
//调用读方法
readMethod.invoke(user);
//获得写方法
Method writeMethod=descriptor.getWriteMethod();
//调用写方法
writeMethod.invoke(user, "hello");
- 获取JavaBean对象的所有的set和get方法
Class<User> clazz = (Class<User>) Class.forName("User类的全限定名");
User user = clazz.newInstance();
//获取某个JavaBean类的所有属性的属性描述器
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//遍历出每一个属性描述器
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//使用每个属性描述器,获取各个属性的set和get方法
}