注解
注解 Annotation ==》给人看 也给程序看 也可被其他程序读取
什么是注解?
Annotation是从JDK5.0开始引入的新技术。
Annotation其实就是代码里的特殊标记, 它用于替代配置文件,
也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,
开发人员可以通过注解告诉类如何运行。
在Java技术里注解的典型应用是:
可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
Annotation的作用:
- 不是程序本身,可以对程序作出解释。
(这一点和注释(comment)没什么区别) - 可以被其他程序(比如:编译器等)读取。
Annotation的格式:
➢注解是以"@注释名"在代码中存在的,还可以添加一些参数值,
例如:@SuppressWarnings(value=“unchecked”). .
Annotation在哪里使用?
- 可以附加在package , class , method,field等上面,
相当于给他们添加了额外的辅助信息,
我们可以通过反射机制编程实现对这些元数据的访问
内置注释:
- @Override (重写的注解):
定义在java.lang.Override中,此注释只适用于修辞方法。
表示一个方法声明打算重写超类中的另一个方法声明。
- @Deprecated :
定义在java.lang.Deprecated中,
此注释可以用于修辞方法,属性,类,
表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择。
- @SuppressWarnings :
定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
与前两个注释有所不同,你需要添加一个参数才能正确使用,
这些参数都是已经定义好了的, 我们选择性的使用就好了。
@SuppressWaingsl(all")
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked” “deprecation”)
public class Tset01 extends Object{ @Override public String toString() { return super.toString(); } //Deprecated 不推荐程序员使用,但是可以使用,或者存在更好的方式 @Deprecated public static void test(){ System.out.println("Deprecated"); } @SuppressWarnings("all") //把警告的信息清除 public void test02(){ List list = new ArrayList(); } public static void main(String[] args) { test();//Deprecated } }
元注解
元注解的作用: 负责注解其他注解 ,
Java定义了4个标准的meta-annotation类型,
他们被用来提供对其他annotation类型作说明。
这些类型和它们所支持的类在java.lang.annotation包中可以找到。
( @Target , @Retention,@documented , @Inherited )
-
@Target:
用于描述注解的使用范围(即:被描述的注解可以用在什么地方) -
@Retention:
表示需要在什么级别保存该注释信息,用于描述注解的生命周期
(SOURCES < CLASS < RUNTIME) 源码级别《 编译时《 运行时
反射只能通过RUNTIME获得注解(运行时)
-
@document:说明该注解将被包含在javadoc中
-
@Inherited:说明子类可以继承父类中的该注解
import java.lang.annotation.*; //测试元注解 @MyAnnotation public class test01 { public void test(){ } } //定义一个注解 //Target表示我们的注解可以用在哪些地方 //可以在方法和类上使用 如下。 @Target(value = {ElementType.METHOD,ElementType.TYPE}) //Retention 表示我们的注解在什么地方还有效。 //Runtime > class > sources @Retention(value = RetentionPolicy.RUNTIME) //documented 表示是否将我们的注解生成在JAVAdoc中 @documented //Inherited 子类可以继承父类的注解 @Inherited @interface MyAnnotation{ }
自定义注解
使用@interface自定义注解时,
自动继承了java.lang.annotation.Annotation接口
分析:
-
@ interface用来声明一个注解,
格式: public @ interface 注解名{定义内容}
其中的每一个方法实际上是声明了一个配置参数。 -
方法的名称就是参数的名称。
-
返回值类型就是参数的类型
(返回值只能是基本类型,Class , String , enum ) -
可以通过default来声明参数的默认值
-
如果只有一个参数成员,一般参数名为value
比如String value(); 可以不写value,只能是value -
注解元素必须要有值,我们定义注解元素时,
经常使用空字符串,0作为默认值.
(无顺序)
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //自定义注解 public class Test02 { //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值 @MyAnnotation2(age = 18,name = "张伞") public void test(){} @MyAnnotation3("下载") public void test2(){} } @Target({ElementType.TYPE,ElementType.METHOD})//可以在类和方法上写该注解 @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ //注解的参数:参数类型 + 参数名(); String name() default ""; //String name(); 那么上面的test方法name必须有个值 @MyAnnotation2(name = "xx") // 有默认值就可以不用加 ==》 default "" default来表示一个默认值 int age(); int id() default -1;//如果默认值为-1,代表不存在 String[] schools() default {"北京大学","清华大学"}; //也可以直接在这边加 不一定要在方法上加 } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ String value(); //如果一个注解只有一个值 并用value命名的情况下 上面方法可以省略value = }
注意点:
Servlet==》
使用注解@MultipartConfig意思是:将一个Servlet标识为支持文件上传
反射
1.Java反射机制概述
1.1 Reflection (反射)是被视为动态语言的关键,
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,
并能直接 *** 作任意对象的内部属性及方法。
1.2 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象
(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。
我们可以通过这个对象看到类的结构。这个对象就像一面镜子,
透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
1.3 动态语言vs 静态语言
动态语言是一类在运行时可以改变其结构的语言:
例如新的函数、对象、甚至代码可以被引进,
已有的函数可以被删除或是其他结构上的变化。
通俗点说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:
Object-C、 C#、Javascript、 PHP、Python、 Erlang。
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。
如Java、C、C++。
Java不是动态语言,但Java可以称之为“准动态语言”。
即Java一定的动态性,
我们可以利用反射机制、字节码 *** 作获得类似动态语言的特性。
Java的动态性让编程的时候更加灵活!
1.4 Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
1.5 Java反射优点和缺点
优点:
可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
对性能有影响。使用反射基本上是一种解释 *** 作,
我们可以告诉JVM,我们希望做什么并且它满足我们的要求。
这类 *** 作总是慢于直接执行相同的 *** 作。
1.6 反射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器
…
问题:
疑问1:
通过直接new的方式或反射的方式都可以调用公共的结构,
开发中到底用那个? ==》建议:直接new的方式。
疑问2:
什么时候会使用:反射的方式?
==》 反射的特征: 动态性
疑问3:
反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。相当于防君子不防小人,一种提示。
2. 理解Class类并获取Class实例(重点)
Class是描述类的类
关于java.Lang.Class类的理解
1.类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
接着我们使用java.exe命令对某个字节码文件进行解释运行。
相当于将某个字节码文件加载到内存中。此过程就称为类的加载。
加载到内存中的类,我们就称为运行时类,
此运行时类,就作为Class的一个实例。
2. 换句话说,Class的实例就对应着一个运行时类。
3. 加载到内存中的运行时类,会缓存一定的时间。
在此时间之内,我们可以通过不同的方式来获取此运行时类。
举例:
有个Person类,省略
获取class的实例的方式(前三种最重要)
package com.a.java; import org.junit.Test; public class ReflectionTest { @Test public void test1() throws ClassNotFoundException { //方式一:调用运行时类的属性:.class Class aClass = Person.class;//赋给大的Class变量 System.out.println(aClass); //方式二:通过运行时类的对象,调用getClass() Person p1 = new Person(); Class bClass = p1.getClass();//获取这个对象是哪个类造的 System.out.println(bClass); //方式三:调用Class的静态方法:forName(String classPath) Class cClass = Class.forName("com.a.java.Person"); //Class.forName方法此方法含义是:加载参数指定的类,并且初始化它。 System.out.println(cClass); //类的全类名 以包包含内的全部路径的 //方式四:使用类的加载器:ClassLoader 不常用 了解 ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class DClass4 = classLoader.loadClass("com.a.java.Person"); System.out.println(DClass4); } }
四个的地址都是一样的,指向同一个对象
==》class com.a.java.Person
调用hashCode方法四个的hashcode值都一样
哪些类型可以有Class对象?
(1) class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2) interface: 接口 ==>Class c = Comparable.class;
(3) []: 数组
Class c = String[].class;
Class c = int[ ][ ].class;
注意:
只要数组的元素类型与维度一样,就是同一个Class
(4) enum: 枚举
(5) annotation:注解@interface
(6)primitivetype:基本数据类型
(7) void
Class c1 = Class.class 也是
Class类的常用方法
- static ClassforName(String name)
返回指定类名name的Class对象 - Object newInstance()
调用缺省构造函数,返回Class对象的一个实例 - getName()
返回此Cass对象所表示的实体(类,接口,数组类或vold)的名称。 - Class getSuperClass()
返回当前Cass对象的父类的Class对象 - ClassI getinterfaces()获取当前Class对象的接口
- ClassLoader getClassLoader()返回该类的类加载器
- Constructorl getConstructors()
返回一个包含某些Constructor对象的数组 - Field[] getDeclaredFields()返回Field对象的一个数组
3. 类的加载与ClassLoader的理解
类的加载过程(了解)
初始化的时候,静态代码块和显式赋值谁后写后执行。
类的加载器
类加载器的作用是用来把类(class)装载进内存的。
JVM规范定义了如下类型的类的加载器
自定义加载器–系统类加载器–扩展类加载器–引导类加载器
系统类加载器是最常用的加载器,那些自定义的类
扩展类加载器负责jar包
引导类加载器
c++编写,是JVM自带的类加载器,负责java平台核心库,
用来装载核心类库。该加载器无法直接获取
案例: test2是重点
在工程下创建jdbc.properties,并复制一份到src下。
使用配置文件的时候,把勾勾上,防止出现读取乱码。
Setting –》Editor -》File Encodings
import org.junit.Test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class ClassLoaderTest { @Test public void test1(){//了解 //对于自定义的类,使用系统类加载器进行加载 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); System.out.println(classLoader); // sun.misc.Launcher$AppClassLoader@18b4aac2 //调用系统类加载器的getParent():获取扩展类加载器 ClassLoader classLoader1 = classLoader.getParent();//上一层 System.out.println(classLoader1); // sun.misc.Launcher$ExtClassLoader@54bedef2 // 调用扩展类加载器的getParent():无法获取引导类加载器 // 引导类加载器主要负责加载java的核心类库,无法加载自定义类的 ClassLoader classLoader2 = classLoader1.getParent(); System.out.println(classLoader2); //null 没有办法直接获取到 引导类加载器 所以呢 也不可能主动地去加载自定义的类 // 举个例子 String获取大的class然后获得类的加载器 此时就是引导类加载器 // 但结果还是null 说明String类是引导类加载器加载的 但还是获取不到的! ClassLoader classLoader3 = String.class.getClassLoader(); System.out.println(classLoader3); } @Test public void test2() throws IOException { Properties pros = new Properties(); // 此时的文件默认在当前的module(工程)下 //读取配置文件的方式一: // FileInputStream fis = new FileInputStream("jdbc.properties");//相对路径 //下面是获取src下的配置文件 // FileInputStream fis = new FileInputStream("src\jdbc1.properties"); // pros.load(fis); //读取配置文件的方式二:使用ClassLoader //配置文件默认识别为:当前module的src下 不然你会报空指针异常 //如果还是不行,记得重启 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc1.properties"); // 以流的方式获取资源 返回个输入流 pros.load(is); String user = pros.getProperty("user"); String password = pros.getProperty("password"); System.out.println("user = " + user + ",password =" + password); //user = 爬,password =abc12 } }
4. 创建运行时类的对象(重点)
import org.junit.Test; import java.util.Random; //通过发射创建对应的运行时类的对象 public class NewInstanceTest { @Test public void test1() throws Exception { Classa = Person.class; //只要是造对象,都得是用构造器来造,只是形式不一样 //有的直接new+构造器 或调方法 Person o = a.newInstance();//Person类的对象 // 类的泛型决定了上面这个方法的返回值 不用强转了 System.out.println(o); } //体会反射的动态性 @Test public void test2(){ for (int i = 0; i < 5; i++) { int num = new Random().nextInt(3);//0 1 2 String classPath = ""; switch (num){ case 0: classPath = "java.util.Date"; break; case 1: classPath = "java.lang.Object"; break; case 2: classPath = "com.a.java.Person"; break; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } } //创建一个指定类的对象。 classPath:指定类的全类名 public Object getInstance(String classPath) throws Exception { Class a = Class.forName(classPath); return a.newInstance(); } }
5. 获取运行时类的完整结构(了解)
1.创建Creature
import java.io.Serializable; public class Creatureimplements Serializable { private char gender; public double weight; private void breath(){ System.out.println("生物呼吸"); } public void eat(){ System.out.println("生物吃东西"); } }
2.创建注解
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String[] value() default "hello"; }
3.创建个接口
public interface MyInterface { void info(); }
4.Person类
@MyAnnotation(value = "hi") public class Person extends Creatureimplements Comparable ,MyInterface { private String name; int age; public int id; public Person(){} @MyAnnotation(value = "abc") private Person(String name){ this.name = name; } Person(String name, int id) { this.name = name; this.id = id; } @Override public int compareTo(String o) { return 0; } @Override public void info() { System.out.println("我是一个人"); } @MyAnnotation private String show(String nation){ System.out.println("我的国籍是:" + nation); return nation; } public String display(String interests,int age) throws NullPointerException,ClassCastException{ return interests + age; } private static void showDesc(){ System.out.println("我是一个可爱的人"); } @Override public String toString() { return "Person{" + "name='" + name + ''' + ", age=" + age +", id=" + id + '}'; } }
FieldTest
import com.a.java1.Person; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class FieldTest { @Test public void test1(){ Class aClass = Person.class;//大的Class的实例 //获得属性结构 //getFields():获取当前运行时类及其父类中声明为public访问权限的属性 Field[] fields = aClass.getFields();//用数组去接收 for (Field f : fields) { System.out.println(f); } System.out.println(); //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中的声明的属性) Field[] declaredFields = aClass.getDeclaredFields(); for (Field f : declaredFields) { System.out.println(f); } } // 上面只是输出, 如果你想获得属性里面具体的某个结构 //权限修饰符 数据类型 变量名 @Test public void test2(){ Class aClass = Person.class; Field[] declaredFields = aClass.getDeclaredFields(); for (Field f : declaredFields) { //1.权限修饰符 int modifier = f.getModifiers(); // modifier 2 private 0默认 1 public System.out.print(Modifier.toString(modifier) + "t"); //三个值 private 默认 public //2.数据类型 Class type = f.getType(); //getType() 当前变量是哪个类的 System.out.print(type.getName() + "t");//获取当前Class的名 //java.lang.String int int 自己也可以定义一个类为String 得和lang包下得区分开 //3.变量名 String FName = f.getName(); System.out.println(FName); // name age id } } }
MothodTest
import com.a.java1.Person; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class MethodTest { @Test public void test1(){ Class aClass = Person.class; //getMethods():获取当时运行时类及其所有父类中声明为public权限的方法 Method[] methods = aClass.getMethods(); for (Method m : methods ) { System.out.println(m); } System.out.println(); //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法) Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method m : declaredMethods ) { System.out.println(m); } } //省略 //@Xxx 注解只有runtime才能拿到 运行时 //权限修饰符 返回值类型 方法名(参数类型1 形参名1,。。。 )throws XxxExeption{} @Test public void test2(){ Class aClass = Person.class; Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method m: declaredMethods ) { //1.获取方法声明的注解 Annotation[] annos = m.getAnnotations(); for (Annotation a:annos) { System.out.println(a); } //2.权限修饰符 System.out.print(Modifier.toString(m.getModifiers()) + "t"); //3.返回值类型 System.out.print(m.getReturnType().getName() + "t"); //4.方法名 System.out.print(m.getName()); System.out.print("("); //5.形参列表 Class[] parameterTypes = m.getParameterTypes(); if (!(parameterTypes == null && parameterTypes.length == 0)){ for (int i = 0; i < parameterTypes.length; i++) { if (i == parameterTypes.length -1){ System.out.print(parameterTypes[i].getName() + " args_" + i); break; } System.out.print(parameterTypes[i].getName() + " args_" + i + ","); } } System.out.print(")"); //6.抛出的异常 Class[] exceptionTypes = m.getExceptionTypes(); if (exceptionTypes.length > 0){ System.out.print("throws "); for (int i = 0; i < exceptionTypes.length; i++) { if (i == exceptionTypes.length-1){ System.out.print(exceptionTypes[i].getName()); break; } System.out.print(exceptionTypes[i].getName() + ","); } } System.out.println(); } } }
OtherTest
import com.a.java1.Person; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public class OtherTest { //获取构造器结构 @Test public void test1(){ Class aClass = Person.class; //getConstructors():获取当前运行时类中声明为public的构造器 Constructor[] constructors = aClass.getConstructors(); for (Constructor c: constructors) { System.out.println(c); } System.out.println(); //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器 Constructor[] de = aClass.getDeclaredConstructors(); for (Constructor c: de) { System.out.println(c); } } //获取运行时类的父亲 @Test public void test2(){ Class aClass = Person.class; Class superclass = aClass.getSuperclass(); System.out.println(superclass); } //获取运行时类的带泛型的父类 @Test public void test3(){ Class aClass = Person.class; Type genericSuperclass = aClass.getGenericSuperclass(); System.out.println(genericSuperclass); } //获取运行时类的带泛型的父类的泛型 //代码: 逻辑性代码 vs 功能性代码 @Test public void test4(){ Class aClass = Person.class; Type genericSuperclass = aClass.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType)genericSuperclass; //获取泛型类型 Type[] actualTypeArguments = paramType.getActualTypeArguments(); System.out.println(actualTypeArguments[0].getTypeName()); //等价于下面的 //System.out.println(((Class)actualTypeArguments[0]).getName()); } //获取运行时类实现的接口 @Test public void test5(){ Class aClass = Person.class; Class[] interfaces = aClass.getInterfaces(); for (Class c : interfaces) { System.out.println(c); } System.out.println(); //获取运行时类的父类实现的接口 Class[] interfaces1 = aClass.getSuperclass().getInterfaces(); for (Class c : interfaces1) { System.out.println(c); } } //获取运行时类所在的包 @Test public void test6(){ Class aClass = Person.class; Package pack = aClass.getPackage(); System.out.println(pack); } //获取运行时类声明的注解 @Test public void test7(){ Class aClass = Person.class; Annotation[] annotations = aClass.getAnnotations(); for (Annotation annos : annotations) { System.out.println(annos); } } }
6. 调用运行时类的指定结构 (重点)
import com.a.java1.Person; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionTest { //通常不采用此方法 不需要掌握 @Test public void testField() throws Exception { Class aClass = Person.class; //创建运行时类的对象 Person p = (Person)aClass.newInstance(); //获取指定的属性:要求运行时类中的属性声明为public Field id = aClass.getField("id"); //设置当前属性的值 set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少 id.set(p,1001); //获取当前属性的值 //get():参数1:获取哪个对象的当前属性值 int pId = (int)id.get(p); System.out.println(pId); } //结果 1001 //使用这种方法 如何 *** 作运行时类中的指定的属性(需掌握哦) @Test public void testField1() throws Exception { Class aClass = Person.class; Person p = (Person)aClass.newInstance(); //1.getDeclaredField(String fieldName): //获取运行时类中指定变量名的属性 Field name = aClass.getDeclaredField("name"); //2.保证当前属性是可访问的 name.setAccessible(true); //3.获取、设置指定对象的此属性值 name.set(p,"Tom"); System.out.println(name.get(p)); } //结果 Tom //如何 *** 作运行时类中的指定的方法(需掌握哦) @Test public void testMehod() throws Exception { Class aClass = Person.class; // 非静态的方法一定要有运行时类的对象 Person p = (Person)aClass.newInstance(); //1.获取指定的某个方法 //getDeclaredMethod(): //参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表 //show这个方法可能有很多,所以告诉我用的是哪个参数的 Method show = aClass.getDeclaredMethod("show", String.class); //2.保证当前属性是可访问的 show.setAccessible(true); //3.调用方法的invoke(): //参数1:方法的调用者 参数2:给方法形参赋值的实参 //invoke()的返回值即为对应类中调用的方法的返回值 Object returnValue = show.invoke(p,"CHN"); System.out.println(returnValue); System.out.println("********************如何调用静态方法*****************************"); //private static void showDesc() Method showDesc = aClass.getDeclaredMethod("showDesc"); showDesc.setAccessible(true); //如果调用的运行时类中的方法没有返回值,则此invoke()返回null Object returnVal = showDesc.invoke(Person.class); //但因为是静态方法 aClass知道你调的是啥 直接调就行 只有非静态方法需要知道你是哪个对象的 // 静态方法每个对象调都一样 // Object returnVal2 = showDesc.invoke(null); System.out.println(returnVal);//null } //如何 *** 作运行时类中的指定的构造器(不重要) @Test public void testConstructor() throws Exception { //private Person(String name) Class aClass = Person.class; //1.获取指定的构造器 //getDeclaredConstructor():参数:指明构造器的参数列表 Constructor constructor = aClass.getDeclaredConstructor(String.class); //2. 保证此构造器是可访问的 constructor.setAccessible(true); //3.调用此构造器创建运行时类的对象 Person per = (Person)constructor.newInstance("Tom"); System.out.println(per); } } //结果 Person{name='Tom', age=0, id=0}
7. 反射的应用:动态代理
代理设计模式的原理:
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。
任何对原始对象的调用都要通过代理。
代理对象决定是否以及何时将方法调用转到原始对象上。
静态代理:
代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
同时,每一个代理类只能为一个接口服务,
这样一来程序开发中必然产生过多的代理。
最好以通过一个代理类完成全部的代理功能。
动态代理
指客户通过代理类来调用其它对象的方法,
并且是在程序运行时根据需要动态创建目标类的代理对象。
动态代理使用场合: 调试 远程方法调用
动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到
调用处理器一个集中的方法中处理,
这样,我们可以更加灵活和统一的处理众多的方法。
静态代理举例
特点: 代理类和被代理类再编译期间,就确定下来了。
interface ClothFactory{ void produceCloth(); } //代理类 class ProxyClothFactory implements ClothFactory { private ClothFactory factory;//用被代理类对象进行实例化 public ProxyClothFactory(ClothFactory factory){ //对上面的属性进行初始化 里面的参数作用 this.factory=factory; } @Override public void produceCloth() { System.out.println("代理工厂做一些准备工作"); factory.produceCloth(); System.out.println("代理工厂做一些后续的收尾工作"); } } //被代理类 class NikeClothFactory implements ClothFactory { @Override public void produceCloth() { System.out.println("Nike工厂生产一批运动服"); } } public class StaticProxyTest { public static void main(String[] args) { //创建被代理类的对象 ClothFactory nike = new NikeClothFactory(); //创建代理类的对象 ClothFactory proxyClothFactory = new ProxyClothFactory(nike); proxyClothFactory.produceCloth(); } }
结果:
代理工厂做一些准备工作
Nike工厂生产一批运动服
代理工厂做一些后续的收尾工作
动态代理类 目前太难,跳过
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Human{ String getBelief(); void eat(String food); } //被代理类 class SuperMan implements Human { @Override public String getBelief() { return "I believe I can fly!"; } @Override public void eat(String food) { System.out.println("我喜欢吃" + food); } } 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); //获得类的加载器 代理类和被代理类实现的接口是一样的 } } class MyInvocationHandler implements InvocationHandler { private Object obj; public void bind(Object obj){ this.obj=obj; } //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke() //将被代理类要执行的方法a的功能就声明再invoke()中 // 回答问题2 @Override //代理类的对象 调什么方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法 // obj:被代理对象 Object returnValue = method.invoke(obj,args); //上诉方法的返回值就作为当前类中的invoke()的返回值。 return returnValue; } } public class ProxyTest { public static void main(String[] args) { SuperMan superMan = new SuperMan(); //proxyInstance:代理类对象 Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法 String belief = proxyInstance.getBelief(); System.out.println(belief); proxyInstance.eat("四川火锅"); System.out.println("******"); NikeClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory ProxyClothFactory = (ClothFactory)ProxyFactory.getProxyInstance(nikeClothFactory);//代理类的对象 动态造的 ProxyClothFactory.produceCloth(); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)