15、反射 | |
15.1 Java反射机制概述 | 1课时 |
15.2 理解Class类并获取Class类的实例 | 1课时 |
15.3 类的加载与ClassLoader的理解 | 1课时 |
15.4 通过反射创建运行时类的对象 | 1课时 |
15.5 通过反射获取运行时类的完整结构 | 1课时 |
15.6 通过反射调用运行时类的指定属性、指定方法等 | 1课时 |
15.7 反射的应用:动态代理 | 1课时 |
案例
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
import javax.swing.plaf.synth.SynthSliderUI;
import org.junit.Test;
/**
* 本章要涉及的内容:
*
* 1.反射的概述
* 2.Class的理解 和 实例化 (掌握)
* 3.类的加载和ClassLoader的理解
* 4.使用反射,创建指定的运行时类的对象 (掌握)
* 5.使用反射,获取运行时类中的所有的结构:属性、方法、构造器、父类、接口、注解、父类的泛型...
* 6.使用反射,调用运行时类中的指定的结构:属性、方法、构造器 (掌握)
* 7.反射的应用:动态代理,体会反射的动态性。
*
*/
public class ReflectionTest {
/**
* Properties:常用来处理属性文件。
* @throws IOException
*
*
*/
@Test
public void test5() throws IOException{
//处理工程下的配置信息
Properties pros = new Properties();
//默认文件的读取位置:当前工程下。
// FileInputStream is = new FileInputStream("jdbc.properties");
FileInputStream is = new FileInputStream("src\jdbc1.properties");
pros.load(is);
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ",password = " + password);
System.out.println("**************************************");
Properties pros1 = new Properties();
ClassLoader loader = ReflectionTest.class.getClassLoader();
//默认读取配置文件的位置是:src目录下
// InputStream inputStream = loader.getResourceAsStream("jdbc1.properties");
InputStream inputStream = loader.getResourceAsStream("com\xxx\java\jdbc2.properties");
pros1.load(inputStream);
String user = pros1.getProperty("name");
String pwd = pros1.getProperty("password");
System.out.println("user = " + user + ",pwd = " + pwd);
}
/**
* 了解类的加载过程 和 类的加载器:ClassLoader
* @throws ClassNotFoundException
*
*
*/
@Test
public void test4() throws ClassNotFoundException{
//获取系统类加载器
ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();
System.out.println(classLoader1);
//获取扩展类加载器
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);
//获取引导类加载器(获取不到)
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println(classLoader3);
//说明:用户自定义类是由系统类加载器加载的
ClassLoader loader1 = Person.class.getClassLoader();
System.out.println(loader1);
//说明:java 核心api是由引导类加载器加载的
ClassLoader loader2 = Class.forName("java.lang.String").getClassLoader();
System.out.println(loader2);
}
/**
* java.lang.Class的理解
* 1.Class是反射的源头
* 2.java源程序经过编译(javac.exe)以后,生成一个或多个字节码(.class)文件,我们使用java.exe命令,
* 将指定的字节码文件加载到内存中,解释运行。此过程是使用JVM的类的加载器、解释器等实现的。
* 加载到内存中的字节码文件对应的类,称为运行时类,此运行时类,即为一个Class的实例。
*
* 3.Class的一个实例,对应着一个加载内存中的运行时类。
*
* 4.加载到内存中的运行时类,只被类的加载器加载器一次,之后会被缓存下来。
*
* @throws ClassNotFoundException
* @throws Exception
*/
//如何获取Class的实例 (4种)
@Test
public void test3() throws ClassNotFoundException{
//方式一(掌握):调用运行时类的属性:.class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二(掌握):可以调用运行时类对象的getClass()
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2);
//方式三(掌握):调用Class类的静态方法:forName(String className).
//注释:className需要提供类的全类名
Class clazz3 = Class.forName("com.xxx.java.Person");
System.out.println(clazz3);
System.out.println(clazz1 == clazz2 && clazz1 == clazz3);
//方式四(了解):使用类的加载器(ClassLoader)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.xxx.java.Person");
System.out.println(clazz4);
System.out.println(clazz1 == clazz4);
}
//有了反射以后,类的封装性受到影响了。如何理解这两个技术?
//单例模式被打破了?!
//通过反射,实现Person类对象的创建,属性、方法的调用
@Test
public void test2() throws Exception{
Class clazz = Person.class;
//通过反射,调用指定的构造器,创建运行时类Person类的对象
Constructor con = clazz.getConstructor(String.class,int.class);
Person p = (Person) con.newInstance("Tom",12);
System.out.println(p);
//通过反射,调用当前对象的指定的属性
Field field1 = clazz.getField("name");
field1.set(p, "HanMeimei");
//通过反射,调用当前对象的指定的方法
Method method1 = clazz.getMethod("show");
method1.invoke(p);
System.out.println("***********************************");
//通过反射,调用运行时类Person类的私有的构造器
Constructor con1 = clazz.getDeclaredConstructor(String.class);
con1.setAccessible(true);
Person p1 = (Person) con1.newInstance("田杰");
System.out.println(p1);
//通过反射,调用运行时类Person类的私有的属性
Field field2 = clazz.getDeclaredField("age");
field2.setAccessible(true);
field2.set(p1, 23);
System.out.println(p1);
//通过反射,调用运行时类Person类的私有的方法
Method method2 = clazz.getDeclaredMethod("display",String.class);
method2.setAccessible(true);
String info = (String) method2.invoke(p1, "中国");//此invoke()的返回值,即为对应的display()的返回值
System.out.println(info);
}
//反射之前的体会
@Test
public void test1(){
// Person p = new Person("Tom");//不可直接调用
Person p1 = new Person("Tom", 12);
p1.name = "HanMeimei";
// p1.age = 10;//不可直接调用
p1.show();
// p1.display("CHN");//不可直接调用
Person p2 = new Person("Tim", 12);
}
}
public class Person {
public String name;
private int age;
public Person(){
System.out.println("Person()");
}
private Person(String name){
this.name = name;
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void show(){
System.out.println("name = " + name + ",age = " + age);
}
public String info(){
return name + ":" + age;
}
private String display(String nation){
System.out.println("我是" + nation + "国家的人");
return nation;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
jdbc.properties
name=u62c9u54c8u5475
password=abc123
反射的应用一案例
import org.junit.Test;
/**
* 反射的应用一:创建运行时类的对象 (掌握)
*
*/
public class NewInstanceTest {
//有了Class实例以后,可以做什么呢?
//可以创建运行时类的对象。
@Test
public void test1() throws Exception{
Class clazz = Class.forName("com.tzy.java.Person");
/*
* 1.newInstance():实际上调用的就是运行时类中的空参的构造器
* 2.可能调用,也要受封装性的影响。
*
* 说明:建议创建的Bean类,都提供空参的构造器,而且权限一般都为public!
* 应用场景:①默认子类的构造器通过super()的方式,调用父类空参的构造器。
* ②方便通过反射的方式,创建运行时类的对象
*
*/
Person p = (Person) clazz.newInstance();
System.out.println(p);
}
}
15-2 理解Class类并获取Class的实例
15-3 类的加载ClassLoader的理解
15-4 创建运行时类的对象
15-5 获取运行时类的完整结构
15-6 调用运行时类的指定属性、指定方法等
反射总结案例
import java.io.Serializable;
public class Creature<T> implements Serializable {
public boolean gender;
double weight;
public void play(T t){
System.out.println("Creature");
}
}
public interface MyInterface {
String info();
}
import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
@MyAnnotation(value="xxxx") public class Person extends Creature
public String name;
private int age;
private static String nation = "CHN";
public Person(){
System.out.println("Person()");
}
private Person(String name){
this.name = name;
}
protected Person(String name,int age){
this.name = name;
this.age = age;
}
@MyAnnotation(value="hello")
public void show() throws RuntimeException{
System.out.println("name = " + name + ",age = " + age);
}
public String info(){
return name + ":" + age;
}
private String display(String nation){
System.out.println("我是" + nation + "国家的人");
return nation;
}
@Override
@MyAnnotation(value="hi")
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return 0;
}
public static void showNation(){
System.out.println("我是中国人!");
}
}
/** * 反射的应用二:获取运行时类的所有的结构:属性 * */ public class FieldTest {
//如何获取运行时类中所有属性
@Test
public void test1(){
Class clazz = Person.class;
//getFields():只能获取当前运行时类,及其所有父类中声明为public的属性
Field[] fields = clazz.getFields();
for(int i = 0;i < fields.length;i++){
System.out.println(fields[i]);
}
System.out.println("*****************");
//getDeclaredFields():能够获取当前运行时类中声明的所有的属性,不论权限的大小。
Field[] fields1 = clazz.getDeclaredFields();
for(int i = 0;i < fields1.length;i++){
System.out.println(fields1[i]);
}
}
//权限修饰符 数据类型 变量名
@Test
public void test2(){
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
// 1.权限修饰符
int modifier = f.getModifiers();
// System.out.println(modifier);
System.out.print(Modifier.toString(modifier) + " ");
//
// // 2.类型
Class type = f.getType();
System.out.print(type.getName() + " ");
//
// // 3.变量名
System.out.println(f.getName());
}
}
}
/** * 反射的应用二:获取运行时类的所有的结构:方法 */ public class MethodTest {
// 获取运行时类中声明的所有的方法
@Test
public void test1() {
Class clazz = Person.class;
// getMethods():获取当前运行时类,及其所有的父类中声明为public的方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("*********************");
// getDeclaredMethods():获取当前运行时类中声明的所有的方法,不论权限的大小
Method[] methods1 = clazz.getDeclaredMethods();
for (Method m : methods1) {
System.out.println(m);
}
}
// 注解
// 权限修饰符 返回值类型 方法名(参数类型1 参数名1,参数类型2 参数名2,...) throws 异常类型1,异常类型2,...{}
@Test
public void test2() {
Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
// 1.注解
Annotation[] annos = m.getAnnotations();
for (Annotation a : annos) {
System.out.println(a);
}
// 2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + " ");
// 3. 返回值类型
Class returnType = m.getReturnType();
System.out.print(returnType.getName() + " ");
// 4.方法名
System.out.print(m.getName() + "(");
// 5.(形参类型 变量名,....)
Class[] paras = m.getParameterTypes();
for (int i = 0; i < paras.length; i++) {
if (i == paras.length - 1) {
System.out.print(paras[i].getName() + " args_" + i);
break;
}
System.out.print(paras[i].getName() + " args_" + i + ",");
}
System.out.print(")");
// 6. 异常类型
Class[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes != null && exceptionTypes.length != 0) {
System.out.print(" throws ");
}
for (Class c : exceptionTypes) {
System.out.print(c.getName() + " ");
}
System.out.println();
}
}
}
/** * 反射的应用二:获取运行时类的所有的结构:构造器 */ public class ConstructorTest {
@Test
public void test1(){
Class clazz = Person.class;
//getConstructors():获取运行时类中声明为public权限的构造器
Constructor[] cons = clazz.getConstructors();
for(Constructor c : cons){
System.out.println(c);
}
System.out.println("*********************");
//getDeclaredConstructors():获取运行时类中所有的构造器,不论权限大小
Constructor[] cons1 = clazz.getDeclaredConstructors();
for(Constructor c : cons1){
System.out.println(c);
}
}
}
/** * 反射的应用二:获取运行时类的所有的结构:其它结构 */ public class OtherTest {
//获取运行时类所实现的接口
@Test
public void test5(){
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for(Class c : interfaces){
System.out.println(c);
}
}
@Test
public void testGetSuperClassGenericParam() throws Exception{
String className = "com.xxx.java1.Person";
className = "com.xxx.java2.CustomerDAO";
className = "com.xxx.java2.OrderDAO";
String superClassGenericParam = getSuperClassGenericParam(className);
System.out.println(superClassGenericParam);
}
//体会反射的动态性
public String getSuperClassGenericParam(String className) throws Exception{
Class clazz = Class.forName(className);
Type genericSuperClass = clazz.getGenericSuperclass();
ParameterizedType paramsType = (ParameterizedType) genericSuperClass;
Type[] arguments = paramsType.getActualTypeArguments();
return ((Class)arguments[0]).getName();
}
//获取运行时类的带泛型的父类的泛型
//逻辑性代码 功能性代码
@Test
public void test4(){
Class clazz = Person.class;
Type genericSuperClass = clazz.getGenericSuperclass();
ParameterizedType paramsType = (ParameterizedType) genericSuperClass;
Type[] arguments = paramsType.getActualTypeArguments();
System.out.println(((Class)arguments[0]).getName());
}
//获取运行时类的带泛型的父类
@Test
public void test3(){
Class clazz = Person.class;
Type genericSuperClass = clazz.getGenericSuperclass();
System.out.println(genericSuperClass);
}
//获取运行时类的父类
@Test
public void test2(){
Class clazz = Person.class;
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
Class superClass1 = superClass.getSuperclass();
System.out.println(superClass1);
}
//获取运行时类所属的包
@Test
public void test1(){
Class clazz = Person.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
}
/** * 反射的应用三:调用运行时类中的指定的结构:属性、方法、构造器 (掌握) */ public class ReflectionTest { //int i = 10; Integer j = i; //如何调用运行时类的指定的构造器 (模板代码) @Test public void test4() throws Exception{ Class clazz = Person.class; //第一步:getDeclaredConstructor(Class ... params): Constructor con = clazz.getDeclaredConstructor(String.class,int.class); // Constructor con = clazz.getDeclaredConstructor(String.class,Integer.class);//不可以使用Integer替换类声明的int型参数 //第二步:setAccessible(true):保证当前的构造器是可操作的 con.setAccessible(true);
//第三步:newInstance(Object paramValue):调用构造器,创建运行时类的对象
Person p = (Person) con.newInstance("田杰",23);
System.out.println(p);
}
//如何调用运行时类的指定的方法 (模板代码)
@Test
public void test3() throws Exception{
Class clazz = Person.class;
//第一步:getDeclaredMethod(String methodName,Class ... params):获取当前运行时类中指定的方法
Method m1 = clazz.getDeclaredMethod("display",String.class);
//2.第二步:setAccessible(true):保证当前的方法是可操作的
m1.setAccessible(true);
//3.第三步:invoke(Object obj,Object ... objs):调用此方法
//此invoke()方法的返回值即为对应的要调用的方法的返回值。
Person person = (Person) clazz.newInstance();
String info = (String) m1.invoke(person,"中国");
System.out.println(info);
//另例:静态方法如何调用?
Method m2 = clazz.getDeclaredMethod("showNation");
m2.setAccessible(true);
// m2.invoke(Person.class);
m2.invoke(null);
}
//如何调用 运行时类的指定的属性 (模板代码)
@Test
public void test2() throws Exception{
Class clazz = Person.class;
//第一步:getDeclaredField(String fieldName):获取当前类中声明的属性,不用考虑权限
Field f1 = clazz.getDeclaredField("age");
System.out.println(f1);
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//第二步:setAccessible(true):保证当前的属性是可操作的
f1.setAccessible(true);
//第三步:对属性进行设置获取
//1.如何设置当前属性的值
f1.set(person, 12);
//2.如何获取当前属性的值
int age = (int) f1.get(person);
System.out.println(age);
//另例:如何调用静态的属性?
Field f2 = clazz.getDeclaredField("nation");
f2.setAccessible(true);
f2.set(null, "CHINA");
System.out.println(f2.get(null));
}
//如何调用 运行时类的指定的属性 (不用练了)
@Test
public void test1() throws Exception{
Class clazz = Person.class;
//getField(String fieldName):
Field f1 = clazz.getField("name");
System.out.println(f1);
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//如何设置当前属性的值
f1.set(person, "Tom");
//如何获取当前属性的值
String name = (String) f1.get(person);
System.out.println(name);
}
}
15-7 反射的应用:动态代理
静态代理案例
/**
* 静态代理的例子1:如下
*
* 静态代理的例子2:实现Runnable接口的方式,就是代理模式
*
*/
public class ClothFactoryTest {
public static void main(String[] args) {
NikeClothFactory nikeFactory = new NikeClothFactory();//创建被代理类对象
ProxyClothFactory proxy = new ProxyClothFactory(nikeFactory);//创建代理类对象
proxy.produceCloth();
}
}
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
ClothFactory clothFactory;
public ProxyClothFactory(ClothFactory clothFactory){
this.clothFactory = clothFactory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂需要进行前期准备操作");
clothFactory.produceCloth();
System.out.println("代理工厂需要进行后期处理操作");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批衣服");
}
}
动态代理案例
/**
* 动态代理的例子
*/
interface Human{
String say();
void fly();
}
//被代理类
class SuperMan implements Human{
@Override
public String say() {
return "我是超人!我怕谁!";
}
@Override
public void fly() {
System.out.println("I believe I can fly!");
}
}
class HumanUtil{
public void method1(){
System.out.println("==========通用的操作一=================");
}
public void method2(){
System.out.println("==========通用的操作二=================");
}
}
/*
* 要想实现动态代理类对象的功能,需要解决两个问题:
* ①如何根据加载到内存中的被代理类对象,动态的去创建代理类的对象
* ②如何通过代理类的对象调用接口中声明的方法时,实现对被代理类对象同名方法的调用
*
*/
class MyInvocationHandler implements InvocationHandler{
private Object obj;//被代理类的对象
public void bind(Object obj){//实例化被代理类的对象
this.obj = obj;
}
//解决上述说明的问题②
//当通过代理类的对象调用接口中的方法a时,就会调用如下的InvocationHandler中的invoke()
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HumanUtil humanUtil = new HumanUtil();
humanUtil.method1();
//method:单行注释中的方法a
Object returnVal = method.invoke(obj, args);
humanUtil.method2();
return returnVal;
}
}
class ProxyFactory{
//调用此方法,返回一个代理类的对象
public static Object getProxyInstance(Object obj){//形参obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
//解决上述说明的问题①
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), handler);
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan man = new SuperMan();//被代理类对象
Object proxyObj = ProxyFactory.getProxyInstance(man);//proxyObj:代理类对象
Human human = (Human) proxyObj;
Object returnValue = human.say();//代理类对象调用接口中声明的方法
System.out.println(returnValue);
human.fly();
System.out.println("****************");
NikeClothFactory nike = new NikeClothFactory();
ClothFactory proxy = (ClothFactory) ProxyFactory.getProxyInstance(nike);
proxy.produceCloth();//代理类对象调用接口中声明的方法
}
}