创作不易,各位看官点赞收藏.
通常对象只有有限个并且确定时,我们通常使用枚举类来表示这些类。当我们需要的定义一组常量时,强烈建议使用枚举类。
在JDK5.0
之前使用枚举类都是自定义枚举类,自己编写枚举类。
// 自定义枚举类
class Season{
// 1.定义private final的属性
private final String name;
// 2.私有构造器,并给属性赋值
private Season(String name){
this.name = name;
}
// 3.提供多个枚举对象,修饰必须是 public static final表示可以外部直接通过类进行实例化一个不可修改的对象
public static final Season SPRING = new Season("春天");
public static final Season SUMMER = new Season("夏天");
public static final Season AUTUMN = new Season("秋天");
public static final Season WINTER = new Season("冬天");
// 获取枚举类属性
public String getName() {
return name;
}
// 重写toString
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
'}';
}
}
Enum
枚举类 在JDK5.0
之后可以使用Enum
关键字来定义一个枚举类。
// 1.使用关键字enum定义一个枚举类
public enum Pay {
// 2.提供枚举对象,每个对象使用逗号隔开,最后一个对象使用分号结束
WECHAT("微信"),
ALIPAY("支付宝"), // 这里其实就是省略了自定义类中的public static final 和 new Pay
CARD("银行卡"),
CASH("现金");
// 3.定义枚举类属性
private final String type;
// 4.私有构造器,构造器自动私有,可省略private
private Pay(String type){
this.type = type;
}
// 5.获取属性值
public String getType() {
return type;
}
// 6.重写toString方法
@Override
public String toString() {
return "Pay{" +
"type='" + type + '\'' +
'}';
}
}
注意:
enum
中提供的对象,实质省略了public static final 和 new Pay
。enum
自动继承java.lang.Enum
这个类,不是继承至Object类。enum
如果没有重写toString
方法,那么打印的是对象名称。public static void main(String[] args) {
// 常用方法1:values() -> 用于获取枚举类中所有对象,返回值是一个枚举类数组
Pay[] values = Pay.values();
for (Pay value : values) {
System.out.println(value);
}
// 方法2:valueOf(),参数需要一个枚举类中对象名字的字符串,并返回这个对象,枚举类中没有字符串对应对象名称,就会报错
Pay wechat = Pay.valueOf("WECHAT");
System.out.println(wechat);
}
方式一:在枚举类中所有对象都执行至一个重写接口的方法。
interface Test{
void show();
}
public enum Pay implements Test{
@Override
public void show() {
System.out.println("所有对象执行同一个方法");
}
}
方式二:每一个枚举对象都可以重写接口中的方法,这样每一个枚举对象执行的方法就会执行自己对应不同重写方法。
// 1.使用关键字enum定义一个枚举类
public enum Pay implements Test{
// 2.提供枚举对象,每个对象使用逗号隔开,最后一个对象使用分号结束
WECHAT("微信"){
@Override
public void show() {
System.out.println("使用微信支付");
}
},
ALIPAY("支付宝"){
@Override
public void show() {
System.out.println("使用支付宝支付");
}
}, // 这里其实就是省略了自定义类中的public static final 和 new PAy
CARD("银行卡"){
@Override
public void show() {
System.out.println("使用银行卡支付");
}
},
CASH("现金"){
@Override
public void show() {
System.out.println("使用现金支付");
}
};
}
注解(annotation):不是程序的本身,但是可以对程序作出解释可以被其它程序读取,是一种特殊标记。
生成文档相关的注解。
// 文档注解
/**
* @author 开发者名称
* @version 1.0.0 版本号
* @see 参考内容
* @since 1.0.0 从哪个版本增加
*/
public class Demo01 {
/**
* @param args String[] 方法参数,可以并列写
* @exception 异常类型 说明
* @return 返回值类型 说明
*/
public static void main(String[] args) {
}
}
注解名 | 解释 |
---|---|
@Override |
注释于方法上,用于注解该方法是重写父类的方法 |
@Deprecated |
注释于类和方法上,注释该类和方法不推荐使用,但是可以使用 |
@SuppressWarnings |
用于镇压警告提示,作用于方法和类上,被注解的块中的警告提示全部消失 |
元注解:用于注解其它的注解,用来对其它的注解类型作进行说明。
注解名 | 解释 |
---|---|
@Target |
用于描述注解的作用范围,参数是一个ElementType 枚举类型的数组 |
@Retention |
用于描述注解的生命周期,参数是一个RetentionPolicy 枚举类型 |
@Documented |
设置注解是否包含到javadoc 文档中,设置就包含 |
@Inherited |
设置子类是否继承父类的注解,设置了就继承父类的注解 |
/*
ElementType.METHOD 可以用于方法上
ElementType.TYPE 可以用于class
ElementType.CONSTRUCTOR 可以用于构造方法上
ElementType.PACKAGE 可以用于包上
ElementType.FILED 可以用于属性上
*/
// 元注解设置作用范围,如果不写就是任何地方都可以使用
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.PACKAGE})
/*
RetentionPolicy.RUNTIME 注解在运行时有效
RetentionPolicy.SOURCE 注解在源码时有效
RetentionPolicy.CLASS 注解在字节码时有效(默认是这种形式)
作用范围: RUNTIME > CLASS > SOURCE
一般我们把注解的声生命周期设置为 RUNTIME
*/
// 设置注解的生命周期
@Retention(value = RetentionPolicy.CLASS)
@Documented // 设置注解是否包含到javadoc文档中,设置就包含默认是不包含的
@Inherited // 设置子类是否继承父类的注解,设置后父类使用了这个注解,子类中就会继承这个注解,相当于也使用了注解
@interface MyAnnotation{
// 自定义的注解
}
// 自定义注解
@Target({ElementType.METHOD,ElementType.TYPE}) // 能作用在方法、类、接口上
@Retention(RetentionPolicy.RUNTIME) // 生命周期是运行级别
@interface MyAnnotation1 {
// 注解的参数,格式:参数类型 参数名() default 默认值
// 参数名后面必须加括号,不是作为方法,而是参数
int id() default 100;
String name() default "张三";
String[] hobby() default {"篮球","羽毛球"};
}
注解和反射一起使用才有意义,可以通过反射获取注解中的信息。
@MyAnnotation1(id = 1,name = "李四",hobby = {"乒乓球","棒球"})
public void test(){}
注意:
enum
、注解及它们的数组形式。Java8
注解新特性可重复注解:在一个地方可以使用多个注解。
// 创建一个新注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
String name() default "";
String vale();
}
// 创建另一个注解,只有一个参数,其参数类型是注解的数组
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTests {
AnnotationTest[] value();
}
// 在注解上添加元注解 Repeatable
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(AnnotationTests.class) // jdk1.8才有的新元注解
public @interface AnnotationTest {
String name() default "";
String vale();
}
// 在同一个地方使用多个相同注解
@AnnotationTest(vale = "张三")
@AnnotationTest(vale = "李四")
public void test1(){
}
注意 AnnotationTests
除了没有Retention
注解,其它的元注解都应该和AnnotationTest
的元注解相同。
类型注解:关于
@target
注解,在jdk1.8
新增了TYPE_PARAMETER
和TYPE_USE
表示注解可以使用到变量类型上。
/*
* ElementType.TYPE_PARAMETER:表示注解可以用于类型变量的申请语句中
* ElementType.TYPE_USE:注解可以写到任何类型的语句中
*/
public void test2(){
// 用于任何类型TYPE_USE
ArrayList<@AnnotationTest(vale = "张三") String> array = new ArrayList<>();
// TYPE_PARAMETER,类型的声明语句中
class B<@AnnotationTest(vale = "李四") T>{
}
}
反射被视为
java
作为动态语言的关键,反射机制允许程序执行期间通过Reflection
取得任何类得内部信息,包括私有属性,并能直接操作任意对象的内部属性和方法。
加载完类后,在堆内存的方法区中就产生一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了类的完整结构,我们可以通过这个对象来操作这个类。
Java反射机制有什么作用?
Class:是
java.lang
包下的一个类,在虚拟机加载一个class字节码文件到内存中这称为类加载,加载到内存中的类我们称为运行时类,这个类就可以作为Class的一个实例对象。这个对象中包含了这个类的所有结构,这个类的所有实例都有一个相同的Class类对应的对象。你无论创建多少个实例,但是Class类对应实例对象只有一个。(万事万物皆对象)
哪些类型可以拥有Class类的实例对象?
// Class类的实例对应一个运行时类,下面是获取运行时类的Class对象方法
// 所有类型获取Class的实例对象
public static void main(String[] args) {
// 基本数据类型
Class<Integer> integerClass = int.class;
// void
Class<Void> voidClass = void.class;
// 注解
Class<Override> overrideClass = Override.class;
// 枚举
Class<? extends ElementType> c1 = ElementType.METHOD.getClass(); // 方式1通过枚举的实例对象获取
Class<ElementType> c2 = ElementType.class; // 方式2通过枚举类获取
Class<?> c3 = null;
try {
c3 = Class.forName("java.lang.annotation.ElementType"); //方式3通过Class类forName(),参数是类的全限定类名
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 数组,如果数组的类型和维度都相同,则也是同一个Class对象
int[] array = new int[10];
Class<int[]> c4 = int[].class; // 方式1直接数组类
Class<? extends int[]> c5 = array.getClass(); // 方式2通过实例对象获取
// 普通类、接口
Class<String> c6 = String.class; // 方式1通过类获取
Class<? extends String> c7 = new String("你好").getClass(); // 通过实例对象获取
try {
Class<?> c8 = Class.forName("java.lang.String"); // 通过Class对象获取
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 获取Class实例方法
public static void main(String[] args) {
// 方式一:通过运行时类的class属性
Class<String> c1 = String.class;
// 方式二:通过运行时类的对象的getClass()
Class<? extends String> c2 = "".getClass();
// 方式三:通过Class的静态方法forName(运行时类的全类名)
Class<?> c3 = null;
try {
c3 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 方式四:使用类的加载器,ClassLoader
ClassLoader classLoader = Demo02.class.getClassLoader(); // 通过当前类获取一个类加载器
Class<?> c4 = null;
try {
c4 = classLoader.loadClass("java.lang.String"); // 通过类加载器的loadClass(类的全限类名)
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1); // class java.lang.String
System.out.println(c2); // class java.lang.String
System.out.println(c3); // class java.lang.String
System.out.println(c4); // class java.lang.String
}
类加载器加载配置文件:
方式一的资源相对路径相对于当前项目下,而方式二的资源相对路径相对于src目录下。推荐使用第二种方式。
// 读取配置文件
public static void main(String[] args){
// 方式一:
Properties properties = new Properties();
// 通过文件流的方式,然后使用Properties.load()方法来加载一个文件,参数是文件流
try (FileInputStream inputStream = new FileInputStream("注解和反射\\src\\jdbc.properties");){
properties.load(inputStream);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
System.out.println("user: "+user+",password: "+password);
} catch (IOException e) {
e.printStackTrace();
}
// 方式二:通过一个类加载器来加载一个文件资源
ClassLoader classLoader = Demo03.class.getClassLoader(); // 获取当前类的类加载器
// 类加载器的getResourceAsStream()方法来加载一个文件资源
try ( InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");){
properties.load(resourceAsStream);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
System.out.println("user: "+user+",password: "+password);
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用反射来创建运行时类的对象
public static void main(String[] args) {
Class<String> c = String.class; // 获取String类的Class对象
try {
String s = c.newInstance(); // 通过Class对象的newInstance()方法创建一个String对象,属性值是默认的
System.out.println(s); // null
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
注意:
我们通过反射获取的Class对象中包含了这个类的所有信息,名称、属性、方法等。
// 创建一个Student类,通过反射来获取它内部结构
public class Student {
private int id;
public String name;
public Student() {}
private Student(String name){
this.name = name;
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
private void method1(){
System.out.println("我是一个没有返回值没有参数的private方法");
}
public String method2(){
System.out.println("我是一个有返回值没有参数的public方法");
return "返回值2";
}
public String method3(String value){
System.out.println(value);
System.out.println("我是一个有返回值有参数的public方法");
return "返回值3";
}
}
方法 | 解释 |
---|---|
getName() |
获取类的全限定类名。 |
getSimpleName() |
获取类的类名。 |
getField(参数) |
获取类指定的public修饰的属性,参数是属性名的字符串。返回值是Field类型。 |
getDeclaredField(参数) |
获取类的指定的属性不管是什么修饰,参数是属性名的字符串。返回值是Field类型。 |
getFields() |
获取类中的所有public修饰的属性,返回Field类型的数组。(包含继承至父类的属性) |
getDeclaredFields() |
获取类中的所有属性(任何权限),返回Field类型的数组。(不包含继承至父类的属性) |
getMethod(参数1, 参数2) |
获取类及父类中指定的public修饰的方法,参数1是方法名字符串,后面的参数是方法的参数的Class对象,可以有多个,返回值是Method类型。 |
getDeclaredMethod(参数1,参数2) |
和上个方法类似,但是这个方法的修饰不限制,但是只能获取本类的方法。 |
getMethods() |
获取类及父类中的所有public修饰的方法,返回值是一个Method的数组。 |
getDeclaredMethods() |
获得本类中的所有方法,返回值是一个Method的数组。 |
getConstructors() |
获得本类中public修饰的构造方法,返回值是一个Constructor的数组。 |
getDeclaredConstructors() |
获得本类中的所有构造方法,返回值是一个Constructor的数组。 |
获取类的属性结构:
// 获取类属性结构
public static void main(String[] args) {
Class<Student> c = Student.class;
Field[] fields = c.getFields(); // 获取所有public修饰的属性,包含继承至父类中public修饰的属性
for (Field field : fields) {
System.out.println(field); // name
}
Field[] declaredFields = c.getDeclaredFields(); // 获取声明的所有属性(任何权限),不包含父类中所有属性
for (Field field : declaredFields) {
System.out.println(field); // id name
}
// 获取到的Filed对象来获取某一个属性的结构
Field field = fields[0];
int modifiers = field.getModifiers(); // 获取属性修饰符,返回值是一个整型,一个值对应一个修饰符
System.out.println(Modifier.toString(modifiers)); // 输出对应整型对应的修饰符
Class<?> type = field.getType(); // 获取属性的类型,返回值是一个类型对应的Class对象
System.out.println(type);
String name = field.getName(); // 获取声明时的名称
System.out.println(name);
}
获取类方法结构
// 反射获取类中方法结构
public static void main(String[] args) {
Class<Student> c = Student.class;
// 获取所有及其父类中public修饰的方法
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// 获取类中所有方法(任何修饰符不包含父类)
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
Method method = declaredMethods[0];
// 获取方法的修饰符
int modifiers = method.getModifiers();
System.out.println(Modifier.toString(modifiers));
// 获取方法返回值
Class<?> returnType = method.getReturnType();
System.out.println(returnType.getSimpleName()); // 返回值类型名称
// 获取方法名称
String name = method.getName();
System.out.println(name);
// 获取方法上的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println(myAnnotation.value());
System.out.println(myAnnotation.name());
}
// 获取方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType.getSimpleName()); // 参数类型名称
}
// 获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType.getSimpleName()); // 异常类型名称
}
}
获取类构造器的结构
// 获取类中构造器结构
public static void main(String[] args) {
Class<Student> c = Student.class;
// 获取类中所有public修饰的构造方法(不包含父类)
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
// 获取类中所有构造方法(任何修饰符)
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
获取类实现的接口:
public static void main(String[] args) {
Class<Student> c = Student.class;
// 获取类实现的接口
Class<?>[] interfaces = c.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println(i);
}
// 获取类的父类的Class对象
Class<? super Student> superclass = c.getSuperclass();
System.out.println(superclass);
// 获取类所在的包
Package p = c.getPackage();
System.out.println(p);
// 获取类上的注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
// 通过反射操作运行时类的属性
public static void main(String[] args) {
Class<Student> c = Student.class;
Student student = null;
// 因为需要操作属性,所以必须有对象才能操作对象的属性
try {
student = c.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
// 获取public修饰的属性
try {
// 参数是获取属性对应的名称(只能获取public修饰的属性)
Field name = c.getField("name");
name.set(student,"张三"); // 直接设置student对象的name属性值为张三
String nameFiled = (String) name.get(student); // 获取student对应name属性的值,默认是Object
System.out.println(nameFiled);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
// 对于非public修饰的属性
try {
// 获取任何修饰的属性,参数是属性名称
Field id = c.getDeclaredField("id");
id.setAccessible(true); // 对于非public修饰的属性需要设置为true,不然不能操作这个属性
id.set(student,10001);
int idFiled = (int) id.get(student);
System.out.println(idFiled);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
// 通过反射调用方法
public static void main(String[] args) {
Class<Student> c = Student.class;
Student student = null;
try {
student = c.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
// 调用非静态方法
try {
// 获取任何修饰的某一个指定方法,参数一:方法名;参数二:是一个可变参数,方法调用时需要传递的参数类型Class对象
Method method = c.getDeclaredMethod("method1", String.class);
// 对于非public修饰的方法需要设置为true
method.setAccessible(true);
// 通过student对象来调用方法,后面是需要传递的参数,是一个可变参数
// invoke()的返回值就是方法执行完毕后的返回值,如果没有返回值就是null
Object result = method.invoke(student, "参数值");
System.out.println(result);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
// 调用静态方法,静态方法不需要对象来调用,所有不需要实例化一个对象
try {
Method method = c.getDeclaredMethod("staticMethod", String.class);
method.setAccessible(true);
// 不要要对象来调用,直接通过Student.class类对象来调用
Object result = method.invoke(Student.class, "参数值");
System.out.println(result);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
// 反射调用构造器实例化对象
public static void main(String[] args) {
Class<Student> c = Student.class;
try {
// 参数是构造器的参数列表,因为构造器名称固定,所以不需要指定名称
Constructor<Student> constructor = c.getDeclaredConstructor(String.class);
// 对于非public需要设置为true
constructor.setAccessible(true);
// 实例化一个对象,参数是构造器对应参数值
Student student = constructor.newInstance("张三");
System.out.println(student);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
代理模式:使用一个代理对象将对象包装起来,然后使用代理对象取代原始对象。任何原始对象的调用都要通过代理对象,代理对象决定了是否以及何时去调用到原始对象上。代理模式分为静态代理、动态代理。
例如客户想要租房子,他可以通过中介去租房子。这样客户就是被代理类,中介就是代理类,他们共同事情都是租房子,租房子就是这个公共的接口。
公共接口:
// 这是代理和被代理的公共接口
public interface ProxyInterface {
void rent();
}
被代理对象(顾客):
// 被代理对象,实现公共接口
public class ProxyImpl implements ProxyInterface {
// 被代理对象中实现的方法
@Override
public void rent() {
System.out.println("我是顾客,我需要租房子");
}
}
代理对象(中介):
// 这是代理类,实现公共接口
public class ProxyObject implements ProxyInterface {
// 这是代理类代理的对象,ProxyObject就是中介,ProxyImpl就是顾客
private final ProxyInterface proxyImpl;
public ProxyObject(ProxyInterface proxyImpl) {
this.proxyImpl = proxyImpl;
}
// 这是代理类实现的方法,在这个方法中代理类可以执行其他方法,也可以执行被代理类中的方法
@Override
public void rent() {
this.proxyImpl.rent(); // 执行被代理类中的方法
System.out.println("我是中介,我正在帮顾客租房子");
System.out.println("我已经帮顾客租到房子了");
}
}
代理测试:
public static void main(String[] args) {
ProxyImpl proxyImpl = new ProxyImpl(); // 这是被代理对象
// 代理对象,参数需要指定一个被代理对象
ProxyObject proxyObject = new ProxyObject(proxyImpl);
// 代理对象替被代理对象执行对应方法
proxyObject.rent();
}
静态代理是在编译期间都确定下来了,不利于程序的扩展。同时一个代理类只能为一个接口代理,如果需要多个代理对象就需要创建多个代理类。所以为了解决这个问题就产生了动态代理,使用一个代理类来完成所有代理接口,这就需要反射来实现。
创建一个类,根据传入的不同的代理对象来生成对应不同的代理对象。
// 代理对象来创建代理类,需要实现一个InvocationHandler接口
public class ProxyFactory implements InvocationHandler {
// 被代理对象,因为被代理对象类型不确定所以使用Object
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 创建一个代理类
public Object getProxyInstance(){
/**
* Proxy.newProxyInstance() 创建一个代理对象
* 参数一:被代理对象的类加载器
* 参数二:被代理类实现的接口,这样创建的代理类可以实现被代理类相同的接口
* 参数三:一个实现了InvocationHandler接口的实现类,这样创建好的代理对象去调用被代理类相同方法时,
* 就会执行实现类重新的invoke()方法
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 当代理类调用被代理类中相同方法时,就会执行这个方法
* 参数一:代理类
* 参数二:被代理类要执行的方法
* 参数三:方法执行时需要的参数数组
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类正在执行方法");
// 被代理类执行对应方法,方法返回值作为本类invoke()的返回值
Object result = method.invoke(this.target, args);
System.out.println("代理类完成代理");
return result;
}
}
创建一个租房被代理类:
// 租房接口
public interface RentInterface {
void rent();
}
// 一个需要代理的被代理类
public class RentClient implements RentInterface {
@Override
public void rent() {
System.out.println("我是顾客,我需要租房子");
}
}
创建一个衣服被代理类:
// 衣服接口
public interface ClothInterface {
String make();
}
// 衣服被代理类,实现衣服接口
public class ClothImpl implements ClothInterface {
@Override
public String make() {
System.out.println("我是衣服被代理类,我正在制造衣服");
return "ok";
}
}
动态代理测试:
public static void main(String[] args) {
// 代理类工厂,产生代理类
ProxyFactory proxyFactory = new ProxyFactory();
// 租房被代理类对象
RentInterface rentClient = new RentClient();
// 设置被代理对象
proxyFactory.setTarget(rentClient);
// 创建一个代理对象,因为代理对象和被代理对象实现了相同的接口,所以可以进行强制转换成对应接口类型
RentInterface proxy = (RentInterface) proxyFactory.getProxyInstance();
// 代理类执行被代理类相同的方法,相当于执行了invoke()
proxy.rent();
// 衣服被代理类对象
ClothImpl clothImpl = new ClothImpl();
// 重新设置被代理对象
proxyFactory.setTarget(clothImpl);
// 创建一个代理对象
ClothInterface clothProxy = (ClothInterface) proxyFactory.getProxyInstance();
// 代理类执行被代理相同方法
String make = clothProxy.make();
System.out.println(make);
}