J2EE
前言:框架=设计模式+反射
。学习和使用框架我们可以不用了解反射,但是为了能更好的去学习和了解框架,我们需要对框架的组成部分进行学习。
目录
一、什么是反射
反射是java语言中的一种机制,在程序运行时动态加载类并获取类的所有属性和方法。本质:JVM得到class文件,
再将class文件反编译从而获取类的各种信息。
二、反射的优点
1、可以解耦,提供代码的可扩展性
2、在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活
的代码,这些代码可以在运行时装配。
三、反射的用途
反射是框架的核心的一部分,所有反射可用于各种通用框架的开发。框架可以根据解析配置文件来加载不同的类或
者对象,调用不同的方法,为保证通用性,就需要用到反射。使用反射机制编写的代码是非常灵活的。
反射的本质图解:
四、反射的基本使用
1、获取class对象的三种方法
①Class.forName("全类名")
②类名.class
③对象.getClass()
代码:三种方式获得的都是一个Class对象
student类:用来测试反射方法的类
package com.zwf.reflect;
public class Student {
private String sid;
private String sname;
public Integer age;
static{
System.out.println("加载进jvm中!");
}
public Student() {
super();
System.out.println("调用无参构造方法创建了一个学生对象");
}
public Student(String sid) {
super();
this.sid = sid;
System.out.println("调用带一个参数的构造方法创建了一个学生对象");
}
public Student(String sid, String sname) {
super();
this.sid = sid;
this.sname = sname;
System.out.println("调用带二个参数的构造方法创建了一个学生对象");
}
@SuppressWarnings("unused")
private Student(Integer age) {
System.out.println("调用Student类私有的构造方法创建一个学生对象");
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public void hello() {
System.out.println("你好!我是" + this.sname);
}
public void hello(String name) {
System.out.println(name + "你好!我是" + this.sname);
}
@SuppressWarnings("unused")
private Integer add(Integer a, Integer b) {
return new Integer(a.intValue() + b.intValue());
}
}
获取:
//方式一
Class stuClz1 = Class.forName("com.zwf.reflect.Student");
//方式二
Class stuClz2=Student.class;
//方式三
Class stuClz3 = new Student().getClass();
//比较
System.out.println(stuClz1==stuClz2);//true
System.out.println(stuClz2==stuClz3);//true
2、反射实例化
package com.zwf.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* @author zjjt
*
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
//获取student的字节码对象即student类实例
Class<Student> stuClz1 = (Class<Student>) Class.forName("com.zwf.reflect.Student");
//反编译获取student对象的各种信息,即通过class字节码对象反射获得该对象,默认调用无参构造
Student stu = (Student)stuClz1.newInstance();
//stu可以当做正常对象使用
stu.hello();
//DeclaredConstructor和Constructor的区别
//DeclaredConstructor可以获取类的私有、公有属性或方法,需要获得访问权限;Constructor只能获取公有属性或方法
//获取student的有参构造方法
Constructor<Student> c = stuClz1.getDeclaredConstructor(String.class);
//反射方式调用student对象有参构造student对象
Student s = c.newInstance("zs");
System.out.println(s);
Constructor<Student> c1 = stuClz1.getDeclaredConstructor(String.class,String.class);
Student s1 = c1.newInstance("2","ls");
System.out.println(s1);
Constructor<Student> c2 = stuClz1.getDeclaredConstructor(Integer.class);
//获取访问权限
c2.setAccessible(true);
Student s2 = c2.newInstance(18);
System.out.println(s2);
}
}
3、反射动态调用方法:
package com.zwf.reflect;
import java.lang.reflect.Method;
/**
* 反射动态方法调用
* @author zjjt
*
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
//获得student的字节码class对象即student的类实例
Class<Student> stuClz = (Class<Student>) Class.forName("com.zwf.reflect.Student");
//反编译获取student对象的各种信息,即通过class字节码对象反射获得student类实例,默认调用无参构造
Student s = stuClz.newInstance();
//通过反射获得该对象的hello方法
Method m1 = stuClz.getDeclaredMethod("hello");
/**
* invoke()
* 参数一:类实例,这里是Student的类实例
* 参数二:当前被调用的方法,传递参数值。如果无参则不用传
* 返回值:被反射调用的方法的返回值.void类型方法返回null
* 执行我们通过反射获得的方法体
*/
m1.invoke(s);
/**
* getDeclaredMethod()
* 参数一:方法名称
* 参数二:方法需要传入的参数类型的类对象
* 返回值:执行该方法返回的值
* 这里就是使用反射的方式来调用我们的方法
*/
Method m2 = stuClz.getDeclaredMethod("add", Integer.class,Integer.class);
//获得访问权限
m2.setAccessible(true);
System.out.println(m2.invoke(s, 10 , 5));//15
}
}
4、反射读写属性
package com.zwf.reflect;
import java.lang.reflect.Field;
/**
* 反射读写属性
* @author zjjt
*
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
//获得student类的字节码对象即student类实例
Class<Student> stuClz = (Class<Student>) Class.forName("com.zwf.reflect.Student");
//通过反射获取student对象
Student s = stuClz.newInstance();
//反射获取sname属性
Field f = stuClz.getDeclaredField("sname");
//获得访问权限
f.setAccessible(true);
//反射写属性
f.set(s, "zs");
//反射读属性
System.out.println(f.get(s));//zs
//反射获得所有属性
Field[] fs = stuClz.getDeclaredFields();
for (Field ff : fs) {
ff.setAccessible(true);
System.out.println(ff.getName()+":"+ff.get(s));
}
}
}
打印结果:
注意:下面读所有属性时,sname为zs
通过反射获取的student对象s,在操作s时其实就是在操作它的类实例stuClz。
图解:
总结:
①通过反射这个机制,我们只需要修改xml文件即可实现同样的代码可以获取不同的对象,执行不同的方法。
②字节码文件对象就是每一个类对应的一个类实例。我们其实可以发现这些操作和传统的new来操作在实际运行效果上没有什么区别。但是带入框架来理解,可以看出使用反射机制写出的代码非常灵活,也证实了框架的通用性。
框架=设计模式+反射
③反射还有一个优点,就是当某一个实体类不见了,未涉及到该实体类的模块还是可以正常运行的,如果是传统的编写方式会产生编辑错误,整个项目都不能运行。