概述
反射
概述
-
java是一门静态语言,但是反射机制让java有了动态机制。
-
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期
借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内
部属性及方法。
-
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个
类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可
以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看
到类的结构,所以,我们形象的称之为:反射。
-
正常方式:引入需要的”包类”名称 ->通过new实例化 ->取得实例化对象
-
反射方式:实例化对象 ->getClass()方法 ->得到完整的“包类”名称
*Class
-
我们可以将它定义为类的类
-
在Object类中定义了以下的方法,此方法将被所有子类继承(java反射源头):
● public final Class getClass();
-
常用方法
方法名 功能说明 static Class forName(String name) 返回指定类名 name 的 Class 对象 Object newInstance() 调用缺省构造函数,返回该Class对象的一个实例 getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 Class getSuperClass() 返回当前Class对象的父类的Class对象 Class [] getInterfaces() 获取当前Class对象的接口 ClassLoader getClassLoader() 返回该类的类加载器 Class getSuperclass() 返回表示此Class所表示的实体的超类的Class Constructor[] getConstructors() 返回一个包含某些Constructor对象的数组 Field[] getDeclaredFields() 返回Field对象的一个数组 Method getMethod(String name,Class … paramTypes) 返回一个Method对象,此对象的形参类型为paramType
类加载与ClassLoader
- 类加载过程:程序经过javac.exe文件后,会成以class结尾的字节或字节码文件,接着我们使用java.exe命令对某个字节码文件解析运行。相当于某个字节码文件加载到内存中。这个过程就叫做类的加载,被称为运行时类,是一个Class实例。
//先建立一个Person
@Test
public void test2(){
// 对于自定义类,使用系统类加载器加载(
//类加载器是负责加载类的一个对象,ClassLoader是一个抽象类。最常见的加载策略是根据的类的全名,然后找到这个类的class文件,然后从文件读取这个类的数据加载到JVM。每个类都能通过getClassLoader方法获取加载这个类的类加载器。
)
ClassLoader classLoader = Person.class.getClassLoader();
System.out.println(classLoader);
// 调用系统类加载器的getParent获取扩展类加载器
System.out.println(classLoader.getParent());
// 通过扩展类加载器获取getParent无法获取扩展类加载器
System.out.println(classLoader.getParent().getParent());
// System.out.println(classLoader.getParent().getParent().getParent());报错,因为上一条代码已经为空了
}
-
哪些类型可以为Class的一个实例?
(1)class: 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
-
下面提供如何获取Class实例的例子。
package com.hyb.Reflection;
import org.junit.Test;
/**
* @program: getClassTest
* @description:
* @author: Huang Yubin
* @create: 2021-06-16 22:14
**/
public class getClassTest {
/*新建一个Person类*/
@Test
public void test1(){
/*public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement
*/
// 方式一:通过运行时类的属性
Class<Person> personClass = Person.class;
System.out.println(personClass);
// class com.hyb.Reflection.Person
// 方式二:通过运行时类的对象
Person person = new Person();
System.out.println(person.getClass());
// class com.hyb.Reflection.Person
// 方式三:调用Class的静态方法,forName(String classPath)
Class<?> aClass=null;
try {
aClass = Class.forName("com.hyb.Reflection.Person");
System.out.println(aClass);
// class com.hyb.Reflection.Person
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 比较
System.out.println(personClass==person.getClass());
System.out.println(person.getClass()==aClass);
System.out.println(personClass==aClass);
// true
// true
// true
/*可见三种方式产生的 Class实例都是一样的,也就是说,加载到内存中的类会缓存一段时间,我们可以
* 通过不同的方式获得该类,而且该类只加载一次,没有必要去加载多次。*/
// 方式四:利用类的加载器获取一个Class的实例,getClassLoader(了解)
ClassLoader classLoader = Person.class.getClassLoader();
Class<?> aClass1 = null;
try {
aClass1 = classLoader.loadClass("com.hyb.Reflection.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(aClass1);
// class com.hyb.Reflection.Person
}
}
- 利用Properties和类的加载器读取文件
//之前的方式
@Test
public void test1(){
// 配置文件在当前工程或者module下,不要在src里
Properties properties = new Properties();
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("myTest.properties");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
properties.load(fileInputStream);
String user=properties.getProperty("user");
String password=properties.getProperty("password");
System.out.println(user + "->" + password);
// hyb->123456789
} catch (IOException e) {
e.printStackTrace();
}
try {
assert fileInputStream != null;
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
properties.clear();
}
//方式二
@Test
public void test2(){
Properties properties = new Properties();
ClassLoader classLoader = getFileTest.class.getClassLoader();
//这里唯一的区别就是这个文件目录必须在当前module下的src下,前面是说不要在src下,这里不一样
InputStream resourceAsStream = classLoader.getResourceAsStream("myTest.properties");
try {
properties.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
String user=properties.getProperty("user");
String password=properties.getProperty("password");
System.out.println(user + "->" + password);
// hyb->123456789
try {
assert resourceAsStream != null;
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
properties.clear();
}
*创建运行时类的对象
- 调用Class对象的newInstance()方法
package com.hyb.Reflection;
import org.junit.Test;
/**
* @program: NewInstanceTest
* @description:创建运行时类的对象
* @author: Huang Yubin
* @create: 2021-06-17 10:21
**/
public class NewInstanceTest {
@Test
public void test1(){
// 首先要拿到这个类
Class<Person> personClass = Person.class;
// 利用newInstance创建运行时类的对象
Person person = null;
try {
person = personClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println(person);
}
}
- 思考
-
既然可以通过调用newInstance方法造对象,那说明是否还存在除了调用空参构造器创造对象这种方法外,还存在另一种方法?
-
如果Person对象里的空参构造器是私有的,这个方法还管用吗?
-
提示:直接查看源码便可以得到答案,或者你可以在Person类中的空参构造器加上输出,看是否有运行结果就可以了。看了源代码可以知道,原来这个方法里,还是调用了运行时类的空参构造器而且当你修改Person类的空参构造器为私有时,你会发现程序报错,这就说明,newInstance的方法必须保证javabean类里的构造器是私有的而且无参。
-
那么没有无参构造器真的不能创建一个对象了吗?
-
不是!只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。步骤如下:
-
通过Class类的**getDeclaredConstructor(Class … parameterTypes)**取得本类的指定形参类
型的构造器
-
向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
-
通过Constructor实例化对象。
//1.根据全类名获取对应的Class对象 String name = “atguigu.java.Person"; Class clazz = null; clazz = Class.forName(name); //2.调用指定参数结构的构造器,生成Constructor的实例 Constructor con = clazz.getConstructor(String.class,Integer.class); //3.通过Constructor的实例创建对应类的对象,并初始化类属性 Person p2 = (Person) con.newInstance("Peter",20); System.out.println(p2);
-
-
-
运行时类结构
-
在这里不做获取类属性的例子,只做获取运行时类方法的例子。
-
首先我们创建一个Person父类。
package com.hyb.Reflection; /** * @program: PersonFather * @description: * @author: Huang Yubin * @create: 2021-06-17 13:03 **/ public class PersonFather { private String fatherName; private int fatherAge; public PersonFather() { } public PersonFather(String fatherName, int fatherAge) { this.fatherName = fatherName; this.fatherAge = fatherAge; } public String getFatherName() { return fatherName; } public void setFatherName(String fatherName) { this.fatherName = fatherName; } public int getFatherAge() { return fatherAge; } public void setFatherAge(int fatherAge) { this.fatherAge = fatherAge; } @Override public String toString() { return "PersonFather{" + "fatherName='" + fatherName + ''' + ", fatherAge=" + fatherAge + '}'; } }
-
之后我们将之前创建的Person类补全,尽量符合一个javabean结构。
package com.hyb.Reflection; /** * @program: Person * @description: * @author: Huang Yubin * @create: 2021-06-16 22:14 **/ public class Person extends PersonFather{ private String name; private int age; public Person() { } public Person(String fatherName, int fatherAge, String name, int age) { super(fatherName, fatherAge); this.name = name; this.age = age; } 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; } @Override public String toString() { return "Person{" + "name='" + name + ''' + ", age=" + age + '}'; } }
-
然后我们来测试,看如何获取Person类的方法,是否通过它能获取父类的方法。
@Test public void test1(){ // 获取Person类 Class<Person> personClass = Person.class; // getMethods方法 Method[] methods = personClass.getMethods(); for (Object obj:methods){ System.out.println(obj); } // public java.lang.String com.hyb.Reflection.Person.toString() // public java.lang.String com.hyb.Reflection.Person.getName() // public void com.hyb.Reflection.Person.setName(java.lang.String) // public int com.hyb.Reflection.Person.getAge() // public void com.hyb.Reflection.Person.setAge(int) // public void com.hyb.Reflection.PersonFather.setFatherAge(int) // public int com.hyb.Reflection.PersonFather.getFatherAge() // public java.lang.String com.hyb.Reflection.PersonFather.getFatherName() // public void com.hyb.Reflection.PersonFather.setFatherName(java.lang.String) // public final void java.lang.Object.wait() throws java.lang.InterruptedException // public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException // public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException // public boolean java.lang.Object.equals(java.lang.Object) // public native int java.lang.Object.hashCode() // public final native java.lang.Class java.lang.Object.getClass() // public final native void java.lang.Object.notify() // public final native void java.lang.Object.notifyAll() }
- 我们从输出可以看到,getMethods()方法可以获得一个类的极其父类的所有public方法。
-
通过getDeclaredMethods,获得该类的所有的方法,不包括父类。
@Test public void test2(){ Class<Person> personClass = Person.class; Method[] declaredMethods = personClass.getDeclaredMethods(); for (Object obj:declaredMethods){ System.out.println(obj); } // public java.lang.String com.hyb.Reflection.Person.toString() // public java.lang.String com.hyb.Reflection.Person.getName() // public void com.hyb.Reflection.Person.setName(java.lang.String) // public int com.hyb.Reflection.Person.getAge() // public void com.hyb.Reflection.Person.setAge(int) }
-
前面说到,我们可以调用类里的属性和方法结构,那方法的属性和结构我们是否可以调用呢?答案是肯定的。
-
一个方法的基本结构:
@注解
**权限修饰符 类型 方法名(类型 参数,类型 参数……)throws 异常/接口/泛型/
-
public Class<?>[] getInterfaces() 确定此对象所表示的类或接口实现的接口。
public Class<? Super T> getSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的Class。
public Constructor[] getConstructors()返回此 Class 对象所表示的类的所有public构造方法。
public Constructor[] getDeclaredConstructors()返回此 Class 对象表示的类声明的所有构造方法。
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
public Field[] getFields() 返回此Class对象所表示的类或父类或接口的public的字段。返回此Class对象所表示的类或接口的public的Field。(getDeclaredFields返回当前类不包括父类,包括私有和公有)
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称。
get Annotation(Class annotationClass)
getDeclaredAnnotations()
获取父类泛型类型:Type getGenericSuperclass()
泛型类型:ParameterizedType
获取实际的泛型类型参数数组:getActualTypeArguments()
类所在的包 Package getPackage()
-
**调用运行时类实例
*如何获取指定属性并修改?
- 不建议使用getField,该方法要确保被调属性是公有的。
package com.hyb.Reflection;
import org.junit.Test;
import java.lang.reflect.Field;
/**
* @program: ReflectionTest
* @description:
* @author: Huang Yubin
* @create: 2021-06-17 15:20
**/
public class ReflectionTest {
@Test
public void test1(){
// 获得一个类
Class<Person> personclass = Person.class;
try {
// 创建运行时类的对象
Person personClass = personclass.newInstance();
// 获取想要的类的属性
Field name = personclass.getDeclaredField("name");
// 保证属性可修改
name.setAccessible(true);
// 修改属性
name.set(personClass,"hyb");
// 查看修改后的属性
System.out.println(name.get(personClass));
} catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
*如何获取并操作类的方法?
@Test
public void testMethod(){
// 获得一个类
Class<Person> personClass = Person.class;
try {
// 获得该类的对象
Person person = personClass.newInstance();
// 指定要调用的类的方法
// private String PersonPrivateMethod(String name){
// return this.name=name;
// }
Method personPrivateMethod = personClass.getDeclaredMethod("PersonPrivateMethod", String.class);//方法名,类型所在类
// 将该权限设置为可访问的
personPrivateMethod.setAccessible(true);
// 操作该私有方法,返回类型即该私有方法的类型
Object newHyb = personPrivateMethod.invoke(person, "newHyb");
System.out.println(newHyb);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
/*多个参数,且无返回值
* private void PersonPrivateNullReturnMethod(String name,int age){
this.name=name;
this.age=age;
}
* */
try {
Person person1 = personClass.newInstance();
Method personPrivateNullReturnMethod = personClass.getDeclaredMethod("PersonPrivateNullReturnMethod", String.class, int.class);
personPrivateNullReturnMethod.setAccessible(true);
personPrivateNullReturnMethod.invoke(person1,"newHybNew",0);//返回null
System.out.println(person1.toString());
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
}
如何获取指定构造器并操作?
@Test
public void testConstructor(){
Person person = null;
try {
// 获取该类
Class<Person> personClass = Person.class;
// 调用指定构造器
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class, String.class, int.class);
// 使得该构造器可以访问
declaredConstructor.setAccessible(true);
person = declaredConstructor.newInstance("hfy", 60, "hyb", 20);
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println(person);
// PersonFather{fatherName='hfy', fatherAge=60}Person{name='hyb', age=20}
}
**反射应用
什么是代理?
-
当两个对象之间需要交互,可通过第三方对象进行代理,这个时候极大地节省了两个对象之间的时间和资源。
-
在Java里:
客户对象产生需求:要目标对象去干一件事。
目标对象不想做,委托代理对象去做。期间,始终都是客户对象和目标对象在交涉。
静态代理
-
我们了解了什么是代理,我们便可以设计出这种模式。
目标对象让自己的代理对象去做,那么其实本意都是在干同一件事,而客户对象产生的也就一个目标,不管你到底是目标对象做的还是代理对象做的。所以,客户对象可以定义为一个接口,而目标对象实现这个接口,让代理对象去做,所以代理对象也得实现这个接口。
package com.hyb.Reflection;
/**
* @program: StaticProxyTest
* @description:
* @author: Huang Yubin
* @create: 2021-06-17 16:37
**/
//设计客户接口
interface Customer{
// 客户产生目标,做一些事情
void doSomething();
}
//有目标对象为客户做一些事
class Target implements Customer{
@Override
public void doSomething() {
System.out.println("没问题,我叫我代理去为你完成这些事情!");
}
}
//代理人去做
class proxy implements Customer{
// 实例化接口
private Customer customer;
// 产生构造器,也就产生这件事
public proxy(Customer customer) {
this.customer = customer;
}
@Override
public void doSomething() {
System.out.println("我已经做好了你的事情");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
// 目标对象实例化
Target target = new Target();
target.doSomething();
// 没问题,我叫我代理去为你完成这些事情!
// 代理接受这个目标对象命令
proxy proxy = new proxy(target);
// 代理执行命令
proxy.doSomething();
// 我已经做好了你的事情
}
}
- 好处,可以在不改变目标对象的前提下,对目标对象进行功能扩展。
- 坏处:静态代理只是一对一的,若是产生很多过程,便会出现很多代理类。
- 动态代理便恰到好处解决了这个问题。
**动态代理
- 上面提到静态代理会产生多个接口,造成繁琐,那么可以升级我们的思维,我们将代理抽象成一个大类,但是我们知道每次产生的要求都是不一样的,所以我们可以动态操作,每次只要产生了要求,就让代理大类去处理,就叫做动态处理。
- 产生需求,有人去做。
//客户产生需求
interface NewCustomer{
void DoSomething();
}
//目标对象需要做这些事
class NewTarget implements NewCustomer{
@Override
public void DoSomething() {
System.out.println("我挺忙的,但也没有固定代理,我立马去找一个代理帮你做!");
}
}
-
代理市场是一个大类,需要产生具体代理实例。
- 首先我们要生成一个代理市场,而且这个代理市场里必须有实现可代理任何事情的方法
class ProxyFactory{ public static Object ProxyAnythingMethod(){ return null; } }
-
这个代理市场的基本架构,要实现两个问题:
- 哪个目标对象?
- 目标对象产生了什么需求?
- 如何解决目标对象的需求?(解决目标对象的方法)
-
java提供了一个专门生成代理对象的代理类Proxy,我们就能通过这个代理类去产生为目标对象服务的代理对象。
而这个代理对象依旧要实现上面的问题。
-
哪个是目标对象?
// 1,目标对象进来了,但要提供自己的信息,**哪个类的加载器**,具体为什么需要加载器,待会再说。 ClassLoader classLoader = obj.getClass().getClassLoader();
-
目标对象产生了什么需求?
// 2,然后目标对象描述自己要干的事情,即是这个类实现客户的接口 Class<?>[] interfaces = obj.getClass().getInterfaces();
-
如何解决目标对象的需求?
// 3,具体实现这件事的过程 // 1.在java里,Proxy类下的静态方法(newProxyInstance(目标类加载器, 目标对象接口, 自己的接口))用来生成一个代理对象, // 2,而这个代理对象的代理类实现了InvocationHandler接口,代表可以做任何事情 // 3,所以我们要实现这个接口也即是实现目标对象的需求,即我们要定义一个类(myInvocationHandler)去实现这个接口。 // 我们需要创建3.3这个类的对象。 // myInvocationHandler myHandler = new myInvocationHandler(); // 我们也需要将目标对象传进去,才能知道目标对象的需求。 myInvocationHandler myHandler = new myInvocationHandler(obj); // 然后我们的条件足够了,产生代理对象去执行需求 Object o = Proxy.newProxyInstance(classLoader, interfaces, myHandler);
class myInvocationHandler implements InvocationHandler{ // 该接口里就提供了一个实现任何需求的方法,而我们具体要实现什么需求,就要通过反射的方式去获取目标对象有什么需求。 // 当我们调用代理对象时,就会自动调用如下方法去实现具体需求。 // 那么我们要通过反射实现。1,要知道是什么目标对象,由于这里上面没有传实参,所以我们得声名。 Object object; // 2.通过构造器赋值得知是什么目标对象 public myInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // args:既然是反射机制,我们自然要知道反射的方法的形参数,而这个参数可能是空的,也可能是多个,不知道是什么类型,所以是个Object数组 Object invoke = method.invoke(object, args);//获取了目标对象里的方法,即需求 return invoke; } }
-
-
解决完这些需求,就是在main函数里具体实现过程了!
public class DynamicProxyTest { public static void main(String[] args) { // 产生一个目标对象 NewTarget newTarget = new NewTarget(); // 找到代理市场,产生一个代理对象 // Object o = ProxyFactory.ProxyAnythingMethod(newTarget); // 这个是Object类型肯定是没有错的,但具体类型是接口,不是NewTarget,因为它实现是接口中的方法,即客户的方法。 NewCustomer o = (NewCustomer) ProxyFactory.ProxyAnythingMethod(newTarget); o.DoSomething(); } }
-
全部代码:
package com.hyb.Reflection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @program: DynamicProxyTest
* @description:
* @author: Huang Yubin
* @create: 2021-06-17 17:31
**/
//客户产生需求
interface NewCustomer{
void DoSomething();
}
//目标对象需要做这些事
class NewTarget implements NewCustomer{
@Override
public void DoSomething() {
System.out.println("我挺忙的,但也没有固定代理,我立马去找一个代理帮你做!");
System.out.println("代理已经帮你做完了!");
}
}
class ProxyFactory{
public static Object ProxyAnythingMethod(Object obj){
// 1,目标对象进来了,但要提供自己的信息,**哪个类的加载器**,具体为什么需要加载器,待会再说。
ClassLoader classLoader = obj.getClass().getClassLoader();
// 2,然后目标对象描述自己要干的事情,即是这个类的实现客户的接口
Class<?>[] interfaces = obj.getClass().getInterfaces();
// 3,具体实现这件事的过程
// 1.在java里,Proxy类下的静态方法(newProxyInstance(目标类加载器, 目标对象接口, 自己的接口))用来生成一个代理对象,
// 2,而这个代理对象实现了InvocationHandler接口,代表可以做任何事情
// 3,所以我们要实现这个接口也即是实现目标对象的需求,即我们要定义一个类去实现这个接口。
// 我们需要创建3.3这个类的对象。
// myInvocationHandler myHandler = new myInvocationHandler();
// 我们也需要将目标对象传进去,才能知道目标对象的需求。
myInvocationHandler myHandler = new myInvocationHandler(obj);
// 然后我们的条件足够了,产生代理对象去执行需求
Object o = Proxy.newProxyInstance(classLoader, interfaces, myHandler);
// 之后将这个代理对象返回
return o;
}
}
class myInvocationHandler implements InvocationHandler{
// 该接口里就提供了一个实现任何需求的方法,而我们具体要实现什么需求,就要通过反射的方式去获取目标对象有什么需求。
// 当我们调用代理对象时,就会自动调用如下方法去实现具体需求。
// 那么我们要通过反射实现。1,要知道是什么目标对象,由于这里上面没有传实参,所以我们得声名。
Object object;
// 通过构造器赋值得知是什么目标对象
public myInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// args:既然是反射机制,我们自然要知道反射的方法的形参数,而这个参数可能是空的,也可能是多个,不知道是什么类型,所以是个Object数组
Object invoke = method.invoke(object, args);//获取了目标对象里的方法,即需求
return invoke;
}
}
public class DynamicProxyTest {
public static void main(String[] args) {
// 产生一个目标对象
NewTarget newTarget = new NewTarget();
// 找到代理市场,产生一个代理对象
// Object o = ProxyFactory.ProxyAnythingMethod(newTarget);
// 这个是Object类型肯定是没有错的,但具体类型是接口,不是NewTarget,因为它实现是接口中的方法,即客户的方法。
NewCustomer o = (NewCustomer) ProxyFactory.ProxyAnythingMethod(newTarget);
o.DoSomething();
//我挺忙的,但也没有固定代理,我立马去找一个代理帮你做!
//代理已经帮你做完了!
}
}
- 为了体现动态性,我们可以将上面的静态代理改为动态代理,即我们不用去描述具体的代理类了。
Target target = new Target();
Customer o1 = (Customer) ProxyFactory.ProxyAnythingMethod(target);
o1.doSomething();
// 没问题,我叫我代理去为你完成这些事情!
// 代理已经做好了这些事情!
-
所以,我们可以引入这样的思考:
在构建项目的时候,有很多大体实现都一样,但具体细节不同而要造很多方法的情况,极大地造成了代码的冗余,为了解决这种方法,我们也可以引用上面动态处理的思想。
我们都知道上面的代理市场可以实现任何事情,那么我们不妨让代理市场做这些大体实现。
-
我们先缔造一个类,表明这是通用方法。
class AllMethod{ public void test1(){ System.out.println("通用方法一!"); } public void test2(){ System.out.println("通用方法二!"); } }
-
然后在代理市场里的具体实现任何事情的方法调用
AllMethod allMethod = new AllMethod(); allMethod.test1(); // args:既然是反射机制,我们自然要知道反射的方法的形参数,而这个参数可能是空的,也可能是多个,不知道是什么类型,所以是个Object数组 Object invoke = method.invoke(object, args);//获取了目标对象里的方法,即需求 allMethod.test2(); return invoke;
-
然后我们看一下输出
通用方法一! 我挺忙的,但也没有固定代理,我立马去找一个代理帮你做! 代理已经帮你做完了! 通用方法二! 通用方法一! 没问题,我叫我代理去为你完成这些事情! 代理已经做好了这些事情! 通用方法二!
我们可以发现,这也如同,无论我们是造NewTarget对象还是Target对象,都共用了AllMethod方法。
-
建议
矛盾
- 既然反射可以调用私有结构,那是不是破坏了封装性?
- 不矛盾,封装性是建议你的调不调的问题,而反射反应的是我能不能调。
- 当然,反射破没破坏封装性,没有官方的语言,但是反射和封装都可以存在。
- 为了解读我的观点,你也可以这样想,封装只是一种思想,类里面的私有和公有属性只是在表达给外部建议不建议用的关系,不存在破不破坏的思想。
- 总的来说,封装只是一种规范,若是反射真的破坏了,但那也只是一种规范,有时规范是要打破的。
最后
以上就是平常小丸子为你收集整理的JAVA高级-反射反射的全部内容,希望文章能够帮你解决JAVA高级-反射反射所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复