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

简介: 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新特性之接口中也可以有方法了(有默认方法和静态方法)
=============================================================================

 

我的GitHub地址: https://github.com/heizemingjun
我的博客园地址: http://www.cnblogs.com/chenmingjun
我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】
相关文章
|
1天前
|
安全 Java 大数据
探索Java的奇妙世界:语言特性与实际应用
探索Java的奇妙世界:语言特性与实际应用
|
2天前
|
Java
【Java基础】详解面向对象特性(诸如继承、重载、重写等等)
【Java基础】详解面向对象特性(诸如继承、重载、重写等等)
6 0
|
2天前
|
Java
Java 反射
Java 反射
|
2天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
12 0
|
2天前
|
存储 Java Shell
深入剖析Java中的反射,由浅入深,层层剥离!
深入剖析Java中的反射,由浅入深,层层剥离!
9 1
|
7天前
|
监控 Java 开发者
掌握 Java 反射和动态代理
【4月更文挑战第19天】Java反射和动态代理提供强大功能和灵活性。反射允许运行时检查和操作类,获取类信息、动态调用方法,但可能带来性能损失和降低代码可读性。动态代理则用于创建代理对象,实现透明性和横切关注点分离,常用于日志、权限检查等。两者结合能实现更复杂功能。掌握这些技术能提升代码的灵活性和可扩展性,但也需注意性能和可读性。通过学习和实践,能更好地构建高效软件系统。
|
8天前
|
机器学习/深度学习 Java API
Java8中的新特性
Java8中的新特性
|
9天前
|
Oracle Java 关系型数据库
Java 开发者必备:JDK 版本详解与选择策略(含安装与验证)
Oracle Java SE 支持路线图显示,JDK 8(LTS)支持至2030年,非LTS版本如9-11每6个月发布且支持有限。JDK 11(LTS)支持至2032年,而JDK 17及以上版本现在提供免费商用许可。LTS版本提供长达8年的支持,每2年发布一次。Oracle JDK与OpenJDK有多个社区和公司构建版本,如Adoptium、Amazon Corretto和Azul Zulu,它们在许可证、商业支持和更新方面有所不同。个人选择JDK时,可考虑稳定性、LTS、第三方兼容性和提供商支持。
24 0
|
10天前
|
分布式计算 Java API
Java 8新特性之Lambda表达式与Stream API
【4月更文挑战第16天】本文将介绍Java 8中的两个重要新特性:Lambda表达式和Stream API。Lambda表达式是Java 8中引入的一种新的编程语法,它允许我们将函数作为参数传递给其他方法,从而使代码更加简洁、易读。Stream API是Java 8中引入的一种新的数据处理方式,它允许我们以声明式的方式处理数据,从而使代码更加简洁、高效。本文将通过实例代码详细讲解这两个新特性的使用方法和优势。
|
14天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
26 0