第十七章 反射

17.1调用运行时类中指定的结构:属性、方法、构造器

/*

如何操作运行时类中的指定的属性

*/

@Test

publicvoidtestField1()throwsException{

Classclazz=Person.class;

//创建运行时类的对象

Personp=(Person)clazz.newInstance();

//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性

Fieldname=clazz.getDeclaredField("name");

//2.保证当前属性是可访问的

name.setAccessible(true);

//3.获取、设置指定对象的此属性值

name.set(p,"Tom");

System.out.println(name.get(p));

   }


/*

如何操作运行时类中的指定的方法

*/

@Test

publicvoidtestMethod()throwsException{

Classclazz=Person.class;

//创建运行时类的对象

Personp=(Person)clazz.newInstance();

/*

1.获取指定的某个方法

getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表

*/

Methodshow=clazz.getDeclaredMethod("show",String.class);

//2.保证当前方法是可访问的

show.setAccessible(true);

/*

3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参

invoke()的返回值即为对应类中调用的方法的返回值。

*/

ObjectreturnValue=show.invoke(p,"CHN");

System.out.println(returnValue);

System.out.println("*************如何调用静态方法*****************");

// private static void showDesc()

MethodshowDesc=clazz.getDeclaredMethod("showDesc");

showDesc.setAccessible(true);

//如果调用的运行时类中的方法没有返回值,则此invoke()返回null

ObjectreturnVal=showDesc.invoke(Person.class);

System.out.println(returnVal);//null

   }


/*

如何调用运行时类中的指定的构造器

*/

@Test

publicvoidtestConstructor()throwsException{

Classclazz=Person.class;

//private Person(String name)

/*

1.获取指定的构造器

getDeclaredConstructor():参数:指明构造器的参数列表

*/

Constructorconstructor=clazz.getDeclaredConstructor(String.class);

//2.保证此构造器是可访问的

constructor.setAccessible(true);

//3.调用此构造器创建运行时类的对象

Personper=(Person)constructor.newInstance("Tom");

System.out.println(per);

   }


17.2类的加载过程

程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。


17.3体会反射的动态性

@Test

publicvoidtest2(){

for(inti=0;i<100;i++){

intnum=newRandom().nextInt(3);//0,1,2

StringclassPath="";

switch(num){

case0:

classPath="java.util.Date";

break;

case1:

classPath="java.lang.Object";

break;

case2:

classPath="com..java.Person";

break;

           }

try{

Objectobj=getInstance(classPath);

System.out.println(obj);

}catch(Exceptione) {

e.printStackTrace();

           }

       }

   }

/*

创建一个指定类的对象。

classPath:指定类的全类名

*/

publicObjectgetInstance(StringclassPath)throwsException{

Classclazz=Class.forName(classPath);

returnclazz.newInstance();

   }


17.4获取Class的实例的方式

@Test

publicvoidtest3()throwsClassNotFoundException{

//方式一:调用运行时类的属性:.class

Classclazz1=Person.class;

System.out.println(clazz1);

//方式二:通过运行时类的对象,调用getClass()

Personp1=newPerson();

Classclazz2=p1.getClass();

System.out.println(clazz2);

//方式三:调用Class的静态方法:forName(String classPath)

clazz3=Class.forName("java.lang.String");

System.out.println(clazz3);

System.out.println(clazz1==clazz2);

System.out.println(clazz1==clazz3);

//方式四:使用类的加载器:ClassLoader  (了解)

ClassLoaderclassLoader=ReflectionTest.class.getClassLoader();

Classclazz4=classLoader.loadClass("com.java.Person");

System.out.println(clazz4);

System.out.println(clazz1==clazz4);

   }



17.5动态代理

interfaceHuman{

StringgetBelief();

voideat(Stringfood);

}

//被代理类

classSuperManimplementsHuman{

@Override

publicStringgetBelief() {

return"I believe I can fly!";

   }

@Override

publicvoideat(Stringfood) {

System.out.println("我喜欢吃"+food);

   }

}

/*

要想实现动态代理,需要解决的问题?

问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。

问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。

*/

classProxyFactory{

//调用此方法,返回一个代理类的对象。解决问题一

publicstaticObjectgetProxyInstance(Objectobj){//obj:被代理类的对象

MyInvocationHandlerhandler=newMyInvocationHandler();

handler.bind(obj);

returnProxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);

   }

}

classMyInvocationHandlerimplementsInvocationHandler{

privateObjectobj;//需要使用被代理类的对象进行赋值

publicvoidbind(Objectobj){

this.obj=obj;

   }

//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()

//将被代理类要执行的方法a的功能就声明在invoke()中

@Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{

//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法

//obj:被代理类的对象

ObjectreturnValue=method.invoke(obj,args);

//上述方法的返回值就作为当前类中的invoke()的返回值。

returnreturnValue;

   }

}

publicclassProxyTest{

publicstaticvoidmain(String[]args) {

SuperMansuperMan=newSuperMan();

//proxyInstance:代理类的对象

HumanproxyInstance=(Human)ProxyFactory.getProxyInstance(superMan);

//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法

Stringbelief=proxyInstance.getBelief();

System.out.println(belief);

proxyInstance.eat("四川麻辣烫");

   }

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容