博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java基础学习_反射、装饰模式、JDK新特性_day27总结
阅读量:6496 次
发布时间:2019-06-24

本文共 36282 字,大约阅读时间需要 120 分钟。

java基础学习_反射、装饰模式、JDK新特性_day27总结

==========================================================================================================================================================涉及到的知识点有:    1:反射(理解)        (1)类的加载        (2)类的初始化时机        (3)类加载器        (4)类加载器的组成        (5)反射的概述        (6)反射的使用        (7)反射的案例        (8)动态代理(中介)        (9)Java中的代理类Proxy和调用处理接口InvocationHandler        (10)代理类Proxy中的方法创建动态代理类对象        (11)调用处理接口InvocationHandler的方法        (12)动态代理案例    2:设计模式        A:模版设计模式(抽象类中用的多)        B:装饰设计模式(IO流中用的多)        C:适配器模式(GUI中用的多)    3:JDK新特性        (1)JDK5(掌握)        (2)JDK6(很少见,了解)        (3)JDK7(理解)        (4)JDK8(了解)==========================================================================================================================================================1:反射(理解)    (1)类的加载        当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三步来实现对这个类进行初始化。                加载             就是指将class文件读入内存,并为之创建一个Class对象。            任何类被使用时系统都会建立一个Class对象。        连接            验证:是否有正确的内部结构,并和其他类协调一致。            准备:负责为类的静态成员分配内存,并设置默认初始化值。            解析:将类的二进制数据中的符号引用替换为直接引用。        初始化             就是我们以前讲过的初始化步骤。                注意:Object类的方法:                public final Class getClass()    返回对象的字节码文件对象             Class类的方法:                public String getName()    以 String 的形式返回此 Class 对象所表示的实体名称。(实体包括:类、接口、数组名、基本类型或 void)                    即:可以通过Class类中的一个方法,获取对象的真实类的全名称。--------------------------------------    (2)类的初始化时机        1.创建类的实例时。        2.访问类的静态变量,或者为静态变量赋值时。        3.调用类的静态方法时。        4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象时。        5.初始化某个类的子类时。        6.直接使用java.exe命令来运行某个主类时。--------------------------------------    (3)类加载器        负责将.class文件加载到内在中,并为之生成对应的Class对象。        虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。    (4)类加载器的组成            Bootstrap ClassLoader     根类加载器            Extension ClassLoader     扩展类加载器            Sysetm ClassLoader        系统类加载器                Bootstrap ClassLoader     根类加载器            也被称为引导类加载器,负责Java核心类的加载。            比如System类,String类等。在JDK中JRE的lib目录下rt.jar文件中(JDK8以前版本中的位置,JDK9/10位置变化了)。                    Extension ClassLoader     扩展类加载器            负责JRE的扩展目录中jar包的加载。            在JDK中JRE的lib目录下ext目录。                    Sysetm ClassLoader        系统类加载器            负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。            一般我们自己写的类通过系统类加载器来加载的。                    如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件中的内容呢?--------------------------------------    (5)反射的概述        JAVA反射机制是在运行状态中,        对于任意一个类,都能够知道这个类的所有属性和方法(动态获取信息);        对于任意一个对象,都能够调用它的任意一个方法和属性(动态调用对象的方法);        这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。        简言之:通过字节码文件对象,去使用该文件中的成员变量、构造方法、成员方法。                要想解剖一个类,必须先要获取到该类的字节码文件对象。        而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。        获取class文件对象的方式:            A:Object类的getClass()方法            B:数据类型的静态属性class(任意数据类型都具备一个class静态属性)            C:Class类中的静态方法(将类名作为字符串传递给Class类中的静态方法forName)              public static Class forName(String className)            1:Person p = new Person();              Class c = p.getClass();            2:Class c2 = Person.class;              任意数据类型都具备一个class静态属性,看上去要比第一种方式简单。            3:将类名作为字符串传递给Class类中的静态方法forName()即可。              注意:需要类的全路径(带包名的路径)              Class c3 = Class.forName("Person");                            4:第三种和前两种的区别                        前两种你必须明确Person类型。                第三种需要这种类型的字符串就行(开发中用)。                这种扩展更强,不需要知道具体的类,只提供字符串,按照配置文件加载就可以了。 示例代码如下:
1 package cn.itcast_01; 2  3 public class Person { 4     private String name; 5     int age; 6     public String address; 7  8     public Person() { 9     }10 11     private Person(String name) {12         this.name = name;13     }14 15     Person(String name, int age) {16         this.name = name;17         this.age = age;18     }19 20     public Person(String name, int age, String address) {21         this.name = name;22         this.age = age;23         this.address = address;24     }25 26     public void show() {27         System.out.println("show");28     }29 30     public void method(String s) {31         System.out.println("method " + s);32     }33 34     public String getString(String s, int i) {35         return s + "---" + i;36     }37 38     private void function() {39         System.out.println("function");40     }41 42     @Override43     public String toString() {44         return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";45     }46 47 }
Person.java
1 package cn.itcast_01; 2  3 /* 4  * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。 5  *  6  *         Person p = new Person(); 7  *         p.使用; 8  *  9  * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。10  *         .class文件    -->    Class类11  *             成员变量        -->    Field类12  *             构造方法        -->    Constructor类13  *             成员方法        -->    Method类14  * 15  * 获取class文件对象的方式:16  *         A:Object类的getClass()方法17  *         B:数据类型的静态属性class(任意数据类型都具备一个class静态属性)18  *         C:Class类中的静态方法(将类名作为字符串传递给Class类中的静态方法forName)19  *             public static Class forName(String className)20  * 21  * 一般我们到底使用谁呢?22  *         A:自己玩        任选一种,第二种比较方便23  *         B:开发时        第三种24  *             为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。25  */26 public class ReflectDemo {27     public static void main(String[] args) throws ClassNotFoundException {28         // 方式A29         Person p = new Person();30         Class c = p.getClass();31 32         Person p2 = new Person();33         Class c2 = p2.getClass();34 35         System.out.println(p == p2); // false36         System.out.println(c == c2); // true37 38         // 方式B39         Class c3 = Person.class;40         // int.class;41         // String.class;42         System.out.println(c == c3); // true43 44         // 方式C45         // ClassNotFoundException 需要类的全路径(带包名的路径)46         Class c4 = Class.forName("cn.itcast_01.Person");47         System.out.println(c == c4); // true48     }49 }
ReflectDemo.java
--------------------------------------                    (6)反射的使用        // 获取字节码文件对象        Class c = Class.forName("cn.itcast_01.Person");        A:通过反射获取构造方法并使用            Constructor con = c.getConstructor(String.class, ...);     // 获取单个的公共构造方法            Constructor[] cons = c.getConstructors();                  // 获取所有的公共构造方法                        Constructor con = c.getDeclaredConstructor(String.class, ...);     // 获取单个的构造方法            Constructor[] cons = c.getDeclaredConstructors();                  // 获取所有的构造方法
1 package cn.itcast_02; 2  3 import java.lang.reflect.Constructor; 4  5 //import cn.itcast_01.Person; 6  7 /* 8  * 需求:通过反射去获取该公共无参构造方法并使用: 9  *         public Person() {10  *         }11  * 12  * 以前的做法:13  *         Person p = new Person();14  *         System.out.println(p);15  * 16  * 现在的做法如下:17  * 18  * 反射的特点:19  *         1.Class类中的静态方法forName()传入的字符串将来会做成配置信息文件,所以以后你不知道程序运行的是谁(是哪个类)。20  *         2.反射是不会看到类的任何信息的。即通过构造方法对象Constructor、成员方法对象Method,调用他们的方法返回值都是Object类型。21  *             (因为任何类型都可以用Object类型接收,基本数据类型会自动装箱为引用数据类型)。22  *         3.反射可以访问私有的东西(前提是class文件未被加密)。23  */24 public class ReflectDemo {25     public static void main(String[] args) throws Exception {26         // 获取字节码文件对象27         // Class类的静态方法:public static Class forName(String className)28         Class c = Class.forName("cn.itcast_01.Person");29 30         // 获取构造方法31         // Class类的成员方法:public Constructor[] getConstructors() 获取所有的公共构造方法32         // Class类的成员方法:public Constructor[] getDeclaredConstructors() 获取所有的构造方法33         // Constructor[] cons = c.getDeclaredConstructors();34         // for (Constructor con : cons) {35         // System.out.println(con);36         // }37 38         // Class类的成员方法:public Constructor
getConstructor(Class
... parameterTypes) 获取单个的公共构造方法39 // Class类的成员方法:public Constructor
getDeclaredConstructor(Class
... parameterTypes) 获取单个的构造方法40 // 参数表示的是:要获取的构造方法的构造参数个数和数据类型的字节码文件对象41 // 通过字节码对象获取公共无参构造方法对象42 Constructor con = c.getConstructor(); // 返回的是构造方法的对象43 44 // Person p = new Person();45 // System.out.println(p);46 // Constructor类的成员方法:public T newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例47 // 通过公共无参构造方法对象创建一个实例对象48 Object obj = con.newInstance();49 System.out.println(obj); // Person [name=null, age=0, address=null]50 51 // Person p = (Person)obj;52 // p.show();53 }54 }
通过反射去获取公共无参构造方法并使用
1 package cn.itcast_02; 2  3 import java.lang.reflect.Constructor; 4  5 /* 6  * 需求:通过反射去获取该公共带参构造方法并使用: 7  *         public Person(String name, int age, String address) { 8  *             this.name = name; 9  *             this.age = age;10  *             this.address = address;    11  *         }12  * 13  * 以前的做法:14  *         Person p = new Person("林青霞", 27, "北京");15  *         System.out.println(p);16  * 17  * 现在的做法如下:18  */19 public class ReflectDemo2 {20     public static void main(String[] args) throws Exception {21         // 获取字节码文件对象22         // Class类的静态方法:public static Class forName(String className)23         Class c = Class.forName("cn.itcast_01.Person");24 25         // 通过字节码对象获取公共带参构造方法对象26         // Class类的成员方法:public Constructor
getConstructor(Class
... parameterTypes)27 Constructor con = c.getConstructor(String.class, int.class, String.class);28 29 // 通过公共带参构造方法对象创建一个实例对象30 // Constructor类的成员方法:public T newInstance(Object... initargs)31 Object obj = con.newInstance("林青霞", 27, "北京");32 33 System.out.println(obj);34 }35 }
通过反射去获取公共带参构造方法并使用
1 package cn.itcast_02; 2  3 import java.lang.reflect.Constructor; 4  5 /* 6  * 需求:通过反射获取私有带参构造方法并使用 7  *         private Person(String name) { 8  *             this.name = name; 9  *         }10  * 11  * 以前的做法:12  *         Person p = new Person("风清扬");13  *         System.out.println(p);14  * 15  * 现在的做法如下:16  * 17  *         可以访问私有构造方法了,但是呢?是不是就不安全了。18  *         不用担心,我们可以有以下两种方式解决:19  *             1.将class文件加密,这样就还原不出来了。20  *             2.对某个数据或者字符使用位异或,这样也就还原不出来了。21  */22 public class ReflectDemo3 {23     public static void main(String[] args) throws Exception {24         // 获取字节码文件对象25         // Class类的静态方法:public static Class forName(String className)26         Class c = Class.forName("cn.itcast_01.Person");27 28         // 通过字节码对象获取私有带参构造方法对象29         // NoSuchMethodException 没有这个方法异常30         // 原因是:一开始我们使用的方法只能获取公有的构造方法,下面这种方式就可以了。即获取所有的构造方法。31         Constructor con = c.getDeclaredConstructor(String.class);32 33         // 通过私有带参构造方法对象创建一个实例对象34         // IllegalAccessException 非法的访问异常35         // 肿么办? 暴力访问36         con.setAccessible(true); // 值为true,则指示反射的对象在使用时应该取消Java语言的访问检查37         Object obj = con.newInstance("风清扬");38 39         System.out.println(obj);40     }41 }
通过反射去获取私有带参构造方法并使用
B:通过反射获取成员变量并使用            Field field = c.getField("address");    // 获取单个的公共成员变量            Field[] fields = c.getFields();         // 获取所有的公共成员变量                        Field field = c.getDeclaredField("name");   // 获取单个的成员变量            Field[] fields = c.getDeclaredFields();     // 获取所有的成员变量
1 package cn.itcast_03; 2  3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5  6 /* 7  * 需求:通过反射获取成员变量并使用 8  *  9  */10 public class ReflectDemo {11     public static void main(String[] args) throws Exception {12         // 获取字节码文件对象13         Class c = Class.forName("cn.itcast_01.Person");14          15         // Field field = c.getField("address"); // 获取单个的公共成员变量16         // Field field = c.getDeclaredField("name"); // 获取单个的成员变量17         // Field[] fields = c.getFields(); // 获取所有的公共成员变量18         // Field[] fields = c.getDeclaredFields(); // 获取所有的成员变量19         20         // for (Field field : fields) {21         // System.out.println(field);22         // }23 24         /*25          * Person p = new Person(); 26          * p.address = "北京"; 27          * System.out.println(p);28          */29 30         // 通过字节码对象获取公共无参构造方法对象31         Constructor con = c.getConstructor();32         33         // 通过公共无参构造方法对象创建一个实例对象34         Object obj = con.newInstance();35         System.out.println(obj);36         37         // 通过字节码对象获取成员变量对象38         39         // 获取单个的公共成员变量address,并对其赋值40         Field addressField = c.getField("address");41         // Field类的成员方法:public void set(Object obj, Object value) 将指定对象变量上此 Field对象表示的字段设置为指定的新值42         addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"43         System.out.println(obj);44 45         // 获取成员变量name,并对其赋值46         // NoSuchFieldException 没有这个方法异常47         Field nameField = c.getDeclaredField("name");48         // IllegalAccessException 非法的访问异常49         // 肿么办? 暴力访问50         nameField.setAccessible(true);51         nameField.set(obj, "林青霞");52         System.out.println(obj);53 54         // 获取成员变量age,并对其赋值55         Field ageField = c.getDeclaredField("age");56         ageField.setAccessible(true);57         ageField.set(obj, 27);58         System.out.println(obj);59     }60 }
通过反射获取成员变量并使用
C:通过反射获取成员方法并使用            Method method = c.getMethod("show", String.class, ...); // 获取自己单个的公共方法            Method[] methods = c.getMethods();                      // 获取自己和父类所有的公共方法                        Method method = c.getDeclaredMethod("function", String.class, ...); // 获取单个的方法            Method[] methods = c.getDeclaredMethods();                          // 获取自己所有的方法
1 package cn.itcast_04; 2  3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5  6 /* 7  * 需求:通过反射获取成员方法并使用 8  *  9  */10 public class ReflectDemo {11     public static void main(String[] args) throws Exception {12         // 获取字节码文件对象13         Class c = Class.forName("cn.itcast_01.Person");14         15         // Method method = c.getMethod("show", String.class, ...); // 获取自己单个的公共方法16         // Method method = c.getDeclaredMethod("function", String.class, ...); // 获取单个的方法17         // Method[] methods = c.getMethods(); // 获取自己和父类所有的公共方法18         // Method[] methods = c.getDeclaredMethods(); // 获取自己所有的方法19         20         // for (Method method : methods) {21         // System.out.println(method);22         // }23 24         Constructor con = c.getConstructor();25         Object obj = con.newInstance();26 27         /*28          * Person p = new Person(); 29          * p.show();30          */31 32         // Class类的成员方法:public Method getMethod(String name, Class
... parameterTypes) 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型33 // Method类的方法:public Object invoke(Object obj, Object... args) 返回值是Object类型接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数34 35 // 获取单个方法并使用36 // 获取Person类的成员方法:public void show() 37 Method m1 = c.getMethod("show");38 m1.invoke(obj); // 本质是:调用obj对象的m1方法,而obj对象是由Person对象得来的39 40 // 获取Person类的成员方法:public void method(String s)41 Method m2 = c.getMethod("method", String.class);42 m2.invoke(obj, "hello");43 44 // 获取Person类的成员方法:public String getString(String s, int i)45 Method m3 = c.getMethod("getString", String.class, int.class);46 Object objString = m3.invoke(obj, "hello", 100);47 System.out.println(objString);48 // String s = (String) m3.invoke(obj, "hello",100);49 // System.out.println(s);50 51 // 获取Person类的成员方法:private void function()52 Method m4 = c.getDeclaredMethod("function");53 m4.setAccessible(true);54 m4.invoke(obj);55 }56 }
通过反射获取成员方法并使用

      反射的特点:

        1.Class类中的静态方法forName()传入的字符串将来会做成配置信息文件,所以以后你不知道程序运行的是谁(是哪个类)
        2.反射是不会看到类的任何信息的。即通过构造方法对象Constructor、成员方法对象Method,调用他们的方法返回值都是Object类型。
          (因为任何类型都可以用Object类型接收,基本数据类型会自动装箱为引用数据类型)。
        3.反射可以访问私有的东西(前提是class文件未被加密)。

--------------------------------------    (7)反射的案例        A:通过反射运行配置文件中的内容            (即通过配置文件运行类中的方法)
1 package cn.itcast.test;2 3 public class Student {4     public void love() {5         System.out.println("爱生活,爱Java");6     }7 }
Student.java
1 package cn.itcast.test;2 3 public class Teacher {4     public void love() {5         System.out.println("爱生活,爱青霞");6     }7 }
Teacher.java
1 package cn.itcast.test;2 3 public class Worker {4     public void love() {5         System.out.println("爱生活,爱老婆");6     }7 }
Worker.java
1 className=cn.itcast.test.Worker2 methodName=love
配置文件.txt
1 package cn.itcast.test; 2  3 import java.io.FileReader; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Method; 6 import java.util.Properties; 7  8 /* 9  * 通过反射运行配置文件中的内容10  *         (通过配置文件运行类中的方法)11  * 12  * 反射的做法:13  *         需要有配置文件配合使用。14  *             假如我们用class.txt代替。15  *             并且你要知道有两个键(即你得知道键:因为键相同,值覆盖)。16  *                 className17  *                 methodName18  * 19  * 反射的作用:20  *         一旦反射的代码写定后,就不修改它了。21  *         将来只需要提供配置文件,根据配置文件就可以动态的知道执行的是谁。即反射的动态执行效果。22  * 23  *         因为只要反射的代码不执行,我就不知道执行的是谁。24  *         只有在代码的执行中,去动态的加载配置文件里面的东西。25  *         所以通过反射写的代码,代码的灵活性高很多。26  * 27  *         将来就业班学框架,用的都是反射的原理。28  */29 public class Test {30     public static void main(String[] args) throws Exception {31         // 反射前的做法(硬编码:代码写死了,写固定了,修改麻烦)32         // Student s = new Student();33         // s.love();34         // Teacher t = new Teacher();35         // t.love();36         // Worker w = new Worker();37         // w.love();38         39         // 反射后的做法(软编码:代码写活了,灵活度高)40         // 把文件中的数据加载到集合Properties中(即加载键值对数据)41         Properties prop = new Properties();42         FileReader fr = new FileReader("src//cn//itcast//test//class.txt");43         prop.load(fr);44         fr.close();45 46         // 从集合Properties中获取数据,根据键获取值47         String className = prop.getProperty("className");48         String methodName = prop.getProperty("methodName");49 50         // 反射51         // 获取字节码文件对象52         Class c = Class.forName(className);53 54         Constructor con = c.getConstructor();55         Object obj = con.newInstance();56 57         // 调用方法58         Method m = c.getMethod(methodName);59         m.invoke(obj);60     }61 }
通过反射运行配置文件中的内容
B:通过反射越过泛型检查            (即我给你ArrayList
的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?)
1 package cn.itcast.test; 2  3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.util.ArrayList; 6  7 /* 8  * 通过反射越过泛型检查 9  *         (我给你ArrayList
的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?)10 */11 public class ArrayListDemo {12 public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,13 IllegalArgumentException, InvocationTargetException {14 15 // 创建集合对象16 ArrayList
array = new ArrayList
();17 18 // 反射前的做法19 // array.add("hello"); // 报错20 // array.add(10); // 自动装箱,没问题21 22 // 其实在集合的源码里面,ArrayList集合的add(E e)方法默认的数据类型是Object类型23 // 只不过在JDK5以后,为了数据的安全,加入了泛型的机制,24 // 而该泛型机制仅仅是给编译器看的(可以通过反编译工具查看哦),真正运行加载的class文件里面放的依旧是Object类型25 26 // 反射后的做法27 Class c = array.getClass(); // 集合ArrayList的class文件对象28 Method m = c.getMethod("add", Object.class);29 30 m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello31 m.invoke(array, "world");32 m.invoke(array, "java");33 34 System.out.println(array);35 }36 }
通过反射越过泛型检查
C:通过反射给任意的一个对象的任意的属性赋值为指定的值            (即写一个方法,public void setProperty(Object obj, String propertyName, Object value) {},此方法可将obj对象中名为propertyName的属性的值设置为value)
1 package cn.itcast.test; 2  3 import java.lang.reflect.Field; 4  5 /* 6  * 通过反射给任意的一个对象的任意的属性赋值为指定的值 7  *         写一个方法,public void setProperty(Object obj, String propertyName, Object value) {}, 8  *         此方法可将obj对象中名为propertyName的属性的值设置为value。 9  */10 public class Tool {11     public void setProperty(Object obj, String propertyName, Object value)12             throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {13         14         // 根据对象获取字节码文件对象15         Class c = obj.getClass();16         // 获取该对象的propertyName成员变量17         Field field = c.getDeclaredField(propertyName);18         // 取消访问检查19         field.setAccessible(true);20         // 给对象的成员变量赋值为指定的值21         field.set(obj, value);22     }23     24 }
Tool.java
1 package cn.itcast.test; 2  3 /* 4  * 通过反射给任意的一个对象的任意的属性赋值为指定的值 5  *         写一个方法,public void setProperty(Object obj, String propertyName, Object value) {}, 6  *         此方法可将obj对象中名为propertyName的属性的值设置为value。 7  */ 8 public class ToolDemo { 9     public static void main(String[] args)10             throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {11         12         Person p = new Person();13         // p.name = "林青霞"; // 错误,因为name是私有成员变量14         // p.age = 27;    // 没问题,因为age是公共成员变量15         16         Tool t = new Tool();17         t.setProperty(p, "name", "林青霞");18         t.setProperty(p, "age", 27);19         System.out.println(p);20         System.out.println("-----------");21 22         Dog d = new Dog();23         t.setProperty(d, "sex", '男');24         t.setProperty(d, "price", 12.34f);25         System.out.println(d);26     }27 }28 29 class Person {30     private String name;31     public int age;32 33     @Override34     public String toString() {35         return name + "---" + age;36     }37 }38 39 class Dog {40     char sex;41     float price;42 43     @Override44     public String toString() {45         return sex + "---" + price;46     }47 }
通过反射给任意的一个对象的任意的属性赋值为指定的值
(8)动态代理(中介)        代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。            举例:春季回家买票让人代买        动态代理:在程序运行过程中产生的这个代理对象。            而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理。    (9)Java中的代理类Proxy和调用处理接口InvocationHandler        在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。        JDK提供的代理只能针对接口做代理。        我们有更强大的代理cglib(在学框架的时候用到)。    (10)代理类Proxy中的方法创建动态代理类对象        public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h) 最终会调用InvocationHandler的方法。 (11)调用处理接口InvocationHandler的方法 Object invoke(Object proxy, Method method, Object[] args) Proxy类中创建动态代理对象的方法的三个参数; ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。 Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。 InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler, 当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。 InvocationHandler接口中invoke方法的三个参数: proxy:代表动态代理对象。 method:代表正在执行的方法。 args:代表调用目标方法时传入的实参。 (12)动态代理案例 A:模拟给方法加权限校验和日志记录。
1 package cn.itcast_06; 2  3 /* 4  * 用户操作接口 5  */ 6 public interface UserDao { 7     public abstract void add(); 8  9     public abstract void delete();10 11     public abstract void update();12 13     public abstract void find();14 }
UserDao.java
1 package cn.itcast_06; 2  3 public class UserDaoImpl implements UserDao { 4  5     @Override 6     public void add() { 7         System.out.println("添加功能"); 8     } 9 10     @Override11     public void delete() {12         System.out.println("删除功能");13     }14 15     @Override16     public void update() {17         System.out.println("修改功能");18     }19 20     @Override21     public void find() {22         System.out.println("查找功能");23     }24 25 }
UserDaoImpl.java
1 package cn.itcast_06;2 3 public interface StudentDao {4     public abstract void login();5 6     public abstract void regist();7 }
StudentDao.java
1 package cn.itcast_06; 2  3 public class StudentDaoImpl implements StudentDao { 4  5     @Override 6     public void login() { 7         System.out.println("登录功能"); 8     } 9 10     @Override11     public void regist() {12         System.out.println("注册功能");13     }14 15 }
StudentDaoImpl.java
1 package cn.itcast_06; 2  3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5  6 public class MyInvocationHandler implements InvocationHandler { 7     private Object target; // 目标对象 8  9     public MyInvocationHandler(Object target) {10         this.target = target;11     }12 13     @Override14     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {15         System.out.println("权限校验");16         Object result = method.invoke(target, args);17         System.out.println("日志记录");18         return result; // 返回的是代理对象19     }20     21 }
MyInvocationHandler.java
1 package cn.itcast_06; 2  3 import java.lang.reflect.Proxy; 4  5 public class Test { 6     public static void main(String[] args) { 7         // 基本的用户操作 8         UserDao ud = new UserDaoImpl(); 9         ud.add();10         ud.delete();11         ud.update();12         ud.find();13         System.out.println("-----------");14         15         // 我们要创建一个动态代理对象16         // Proxy类中有一个静态方法可以创建动态代理对象17         // public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h)18 // 给目标对象ud创建一个代理对象19 MyInvocationHandler handler = new MyInvocationHandler(ud);20 UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), handler);21 proxy.add();22 proxy.delete();23 proxy.update();24 proxy.find();25 System.out.println("-----------");26 27 StudentDao sd = new StudentDaoImpl();28 MyInvocationHandler handler2 = new MyInvocationHandler(sd);29 StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass().getClassLoader(), sd.getClass().getInterfaces(), handler2);30 proxy2.login();31 proxy2.regist();32 }33 34 }
Test.java
B:用动态代理实现:计算集合ArrayList的add()方法的运行时间。-----------------------------------------------------------------------------    2:设计模式    A:模版设计模式(抽象类中用的多)        模版设计模式的概述            模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现。        优点            使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求。        缺点            如果算法骨架有修改的话,则需要修改抽象类。        示例代码如下:
1 package cn.itcast_01; 2  3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8  9 /*10  * 需求:请给计算出一段代码的运行时间11         // for循环的运行时间12         for (int x = 0; x < 10000; x++) {13             System.out.println(x);14         }15 16         // 复制视频的运行时间17         try {18             BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src//cn//itcast_01//a.avi"));19             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src//cn//itcast_01//b.avi"));20             byte[] bys = new byte[1024];21             int len = 0;22             while ((len = bis.read(bys)) != -1) {23                 bos.write(bys, 0, len);24             }25             bos.close();26             bis.close();27         } catch (IOException e) {28             e.printStackTrace();29         }30 31         // 再给我测试一个代码运行时间:集合操作的、多线程操作的、常用API操作的等等...32         // 所以说每次都要修改这个类,是不行的。肿么办?33  */34 35 /*36  * 功能抽象类37  */38 public abstract class GetTime {39     40     public abstract void code();41     42     public long getTime() {43         long start = System.currentTimeMillis();44         code();45         long end = System.currentTimeMillis();46         return end - start;47     }48 49 }
功能抽象类
1 package cn.itcast_01; 2  3 /* 4  * 具体实现类 5  *         for循环程序 6  */ 7 public class ForDemo extends GetTime { 8  9     @Override10     public void code() {11         for (int x = 0; x < 100000; x++) {12             System.out.println(x);13         }14     }15 16 }
具体实现类
1 package cn.itcast_01; 2  3 /* 4  * 测试类 5  */ 6 public class GetTimeTest { 7     public static void main(String[] args) { 8         // GetTime gt = new GetTime(); 9         // System.out.println(gt.getTime() + "毫秒");10 11         GetTime gt = new ForDemo(); // 多态12         System.out.println(gt.getTime() + "毫秒");13 14         gt = new IODemo(); // 多态15         System.out.println(gt.getTime() + "毫秒");16     }17 }
测试类
1 package cn.itcast_01; 2  3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8  9 /*10  * 具体实现类11  *         IO程序12  */13 public class IODemo extends GetTime{14 15     @Override16     public void code() {17         try {18             BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src//cn//itcast_01//a.avi"));19             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src//cn//itcast_01//b.avi"));20             byte[] bys = new byte[1024];21             int len = 0;22             while ((len = bis.read(bys)) != -1) {23                 bos.write(bys, 0, len);24             }25             bos.close();26             bis.close();27         } catch (IOException e) {28             e.printStackTrace();29         }30     }31     32 }
具体实现类
B:装饰设计模式(IO流中用的多)        装饰设计模式的概述            装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案。        优点            使用装饰模式,可以提供比继承更灵活的扩展对象的功能,它可以动态的添加对象的功能,并且可以随意的组合这些功能。        缺点            正因为可以随意组合,所以就可能出现一些不合理的逻辑。        示例代码如下:            // 复杂的装饰(多重装饰)            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));            BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));            // 简单的装饰            Scanner sc = new Scanner(System.in);
1 package cn.itcast_02;2 3 /*4  * 手机接口5  */6 public interface Phone {7     public abstract void call();8 }
手机接口
1 package cn.itcast_02; 2  3 /* 4  * 手机实现类 5  */ 6 public class IPhone implements Phone { 7  8     @Override 9     public void call() {10         System.out.println("手机可以打电话了");11     }12 13 }
手机实现类
1 package cn.itcast_02; 2  3 /* 4  * 手机装饰抽象类 5  */ 6 public abstract class PhoneDecorate implements Phone { 7  8     private Phone p; 9 10     public PhoneDecorate(Phone p) {11         this.p = p;12     }13 14     @Override15     public void call() {16         this.p.call();17     }18 }
手机装饰抽象类
1 package cn.itcast_02; 2  3 /* 4  * 彩铃手机装饰具体类 5  */ 6 public class RingPhoneDecorate extends PhoneDecorate { 7  8     public RingPhoneDecorate(Phone p) { 9         super(p);10     }11 12     @Override13     public void call() {14         System.out.println("手机可以听彩铃");15         super.call();16     }17 }
听彩铃手机装饰具体类
1 package cn.itcast_02; 2  3 /* 4  * 听音乐手机装饰具体类 5  */ 6 public class MusicPhoneDecorate extends PhoneDecorate { 7  8     public MusicPhoneDecorate(Phone p) { 9         super(p);10     }11 12     @Override13     public void call() {14         super.call();15         System.out.println("手机可以听音乐");16     }17 }
听音乐手机装饰具体类
1 package cn.itcast_02; 2  3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.InputStreamReader; 6 import java.io.OutputStreamWriter; 7 import java.util.Scanner; 8  9 /*10  * 手机测试类11  */12 public class PhoneDemo {13     public static void main(String[] args) {14         Phone p = new IPhone(); // 多态15         p.call();16         System.out.println("------------");17 18         // 需求:我想在接电话前,听彩铃19         PhoneDecorate pd = new RingPhoneDecorate(p); // 多态20         pd.call();21         System.out.println("------------");22 23         // 需求:我想在接电话后,听音乐24         pd = new MusicPhoneDecorate(p);25         pd.call();26         System.out.println("------------");27 28         // 需求:我要想手机在接电话前听彩铃,接电话后听音乐29         // 自己提供听彩铃和听音乐的装饰类,在接电话前听彩铃,在接电话后听音乐,这样做的话,不好,太麻烦了。30         // 下面这种方式可以解决问题,这就是装饰的优点:可以任意组合功能。31         pd = new RingPhoneDecorate(new MusicPhoneDecorate(p));32         pd.call();33         System.out.println("----------");34         35         // 想想我们在IO流中的使用36         // InputStream is = System.in; // 字节流37         // InputStreamReader isr = new InputStreamReader(is); // 把字节流转为字符流38         // BufferedReader br = new BufferedReader(isr); // 把基本字符流转为高效字符流39         // 复杂的装饰40         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));41         BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));42 43         // 简单的装饰44         Scanner sc = new Scanner(System.in);45     }46 }
手机测试类
C:适配器模式(GUI中用的多)        适配器设计模式的概述            将一个类的接口转换成另外一个客户希望的接口。从而使原来不能直接调用的接口变的可以调用。        优点            让本来不适合使用的接口变得适合使用。        缺点            一次只能适配一个类,使用有一定的局限性。-----------------------------------------------------------------------------        3:JDK新特性    (1)JDK5(掌握)        自动装箱和拆箱(day13)        泛型(day16)        增强for循环(day16)        静态导入(day16)        可变参数(day16)--------------------------------------        枚举(day27)            A:枚举的概述                是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。                举例:一周只有7天,一年只有12个月等。                回想单例设计模式:单例类是一个类只有一个实例。                那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。--------------------------------------                            B:通过自己定义一个枚举类来演示案例                第一版                第二版                第三版            发现自己定义一个枚举类,比较麻烦,所以,java就提供了枚举类供我们使用。            格式是:只有枚举项的枚举类                public enum 枚举类名 {                    枚举项1, 枚举项2, 枚举项3, ...;                }--------------------------------------                            C:注意事项                1.定义枚举类要用关键字enum。                2.所有枚举类都是Enum类的子类。                3.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议永远不要省略。                4.枚举类中可以有构造方法,但必须是private的,它默认也是private的。枚举项的用法比较特殊:枚举("XXX")。                5.枚举类中也可以有抽象方法,但枚举项必须重写该方法。                6.枚举在switch语句中的使用。            D:枚举类中的常见方法                public final int compareTo(E o)                public final String name()                public final int ordinal()                public String toString()                public static 
T valueOf(Class
enumType, String name) public static values() 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便。-------------------------------------- (2)JDK6(很少见,了解) (3)JDK7(理解) 二进制字面量(二进制的表现形式) JDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。 使用二进制字面量的好处是,可以使代码更容易被理解。语法非常简单,只要在二进制数值前面加0b或者0B即可。 举例: int x = ob110110;-------------------------------------- 数字字面量可以出现下划线(用_分隔数据) 为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。 JDK7提供了_对数据分隔。 举例: int x = 100_1000; 注意事项: 不能出现在进制标识和数值之间。 不能出现在数值开头和结尾。 不能出现在小数点旁边。-------------------------------------- switch语句的表达式可是用字符串(day04) 泛型简化(泛型推断(也叫菱形泛型)) 异常的多个catch合并(多catch的使用)(day19) try-with-resources 语句(自动释放资源的用法) try (必须是java.lang.AutoCloseable的子类对象) {...} 好处: 资源自动释放,不需要close()了。 把需要关闭资源的部分都定义在这里就ok了。 主要是流体系的对象是这个接口的子类(看JDK7的API)。-------------------------------------- (4)JDK8(了解) 可以去网上了解资料。 1.接口中也可以有方法了(有默认方法、静态方法、私有方法(JDK9))。
1 /* 2 JDK8新特性之 3     接口中也可以有方法了 4 */ 5 interface Inter { 6     // 抽象方法 7     public abstract void show(); 8      9     // default方法(默认方法)10     public default void defaultPrint() {11         System.out.println("defaultPrint 我爱林青霞");12     }13 14     // static方法(静态方法)15     public static void staticPrint() {16         System.out.println("staticPrint 我爱林青霞");17     }18 }19 20 // 实现类21 class InterImpl implements Inter {22     public void show() {23         System.out.println("重写接口中的方法");24     }25 }26 27 // 测试类28 public class Demo01 {29     public static void main(String[] args) {30         // Inter.defaultPrint(); // 非静态方法不能直接调用 31         Inter.staticPrint();32         33         Inter i = new InterImpl();34         i.defaultPrint();35         i.show();36     }37 }
JDK8新特性之接口中也可以有方法了(有默认方法和静态方法)
=============================================================================

 

我的GitHub地址:
我的博客园地址:
我的蚂蚁笔记博客地址:
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】
你可能感兴趣的文章
Linux常用命令
查看>>
【重磅】云栖社区2017年度内容特辑
查看>>
Java WEB开发时struts标签 显示set内容
查看>>
spring-data-elasticsearch 概述及入门(二)
查看>>
Solr启动和结束命令
查看>>
thymeleaf 知多少
查看>>
1.12 xshell密钥认证
查看>>
3.2 用户组管理
查看>>
awk
查看>>
AliOS Things SMP系统及其在esp32上实现示例
查看>>
postgresql 聚合函数 的编写
查看>>
循环遍历二叉树
查看>>
while循环 和 运算符
查看>>
MySQL压缩包安装
查看>>
SpringMVC参数绑定
查看>>
阿里云MVP:开发者的超能力,用技术创造更好世界
查看>>
云计算教学实践40:open***架构实施方案(一)跨机房异地灾备
查看>>
Vue和React的对比
查看>>
MyBatis 源码解析 —— SqlSessionFactory
查看>>
如何解决CentOS 7.*无法使用tab补全功能
查看>>