zoukankan      html  css  js  c++  java
  • java基础学习_反射、装饰模式、JDK新特性_day27总结

    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     @Override
    43     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         // 方式A
    29         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); // false
    36         System.out.println(c == c2); // true
    37 
    38         // 方式B
    39         Class c3 = Person.class;
    40         // int.class;
    41         // String.class;
    42         System.out.println(c == c3); // true
    43 
    44         // 方式C
    45         // ClassNotFoundException 需要类的全路径(带包名的路径)
    46         Class c4 = Class.forName("cn.itcast_01.Person");
    47         System.out.println(c == c4); // true
    48     }
    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<T> getConstructor(Class<?>... parameterTypes) 获取单个的公共构造方法
    39         // Class类的成员方法:public Constructor<T> 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<T> 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.Worker
    2 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  *                 className
    17  *                 methodName
    18  * 
    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<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?)
     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<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?)
    10  */
    11 public class ArrayListDemo {
    12     public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
    13             IllegalArgumentException, InvocationTargetException {
    14 
    15         // 创建集合对象
    16         ArrayList<Integer> array = new ArrayList<Integer>();
    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方法,传入的值是hello
    31         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     @Override
    34     public String toString() {
    35         return name + "---" + age;
    36     }
    37 }
    38 
    39 class Dog {
    40     char sex;
    41     float price;
    42 
    43     @Override
    44     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     @Override
    11     public void delete() {
    12         System.out.println("删除功能");
    13     }
    14 
    15     @Override
    16     public void update() {
    17         System.out.println("修改功能");
    18     }
    19 
    20     @Override
    21     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     @Override
    11     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     @Override
    14     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     @Override
    10     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     @Override
    16     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     @Override
    15     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     @Override
    13     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     @Override
    13     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> T valueOf(Class<T> 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新特性之接口中也可以有方法了(有默认方法和静态方法)
    =============================================================================
  • 相关阅读:
    springboot2 pagehelper 使用笔记
    springboot2 config_toolkit 并且设置全局获取数据GlobalUtil
    springboot2 redis
    Python问题汇总
    MAC安装Win10系统安装相关问题
    DEDE开发网站总部
    DEDE 调用文章中略缩图的原图
    塑形动作
    dede初学
    打印机维护经验
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/8810983.html
Copyright © 2011-2022 走看看