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("四川麻辣烫");
}
}