• Java


    大纲:
    Class类的使用:
      三种获得Class类的实例的方法;
      基本数据类型对应的类类型;
      Class类的基本API:获取类的常用(全部)信息;
    Java类加载机制:
      编译时加载(静态加载);
      运行时加载(动态加载);
    方法的反射:
    成员变量的反射:
    构造函数的反射:
    通过反射了解集合泛型的本质:

    在面向对象的世界里,万事万物皆对象;但其实静态的成员、普通的数据类型不是对象,但我们最好看做万事万物皆对象;类也是对象,类是java.lang.Class类的实例对象;任何一个类都是Clss类的实例对象;

    三种获得Class类的实例的方法:

     1 /**
     2  * Class类的使用:Class类的实例对象的三种表示方法
     3  */
     4 package reflect;
     5 
     6 public class ClassTest01
     7 {
     8     public static void main(String[] args)
     9     {
    10         // Foo类的实例对象:foo
    11         Foo foo = new Foo();
    12         
    13         // Foo这个类也是一个实例对象,是java.lang.Class类的实例对象
    14         // 任何一个类都是Class类的实例对象,这个实例对象有三种表示方法
    15         
    16         // 第一种表示方法:
    17         // 实际告诉我们,任何一个类都有一个隐含的静态成员变量:class
    18         Class c1 = Foo.class;
    19         
    20         // 第二种表示方法:已知该类的实例对象,通过getClass()方法获取
    21         Class c2 = foo.getClass();
    22         
    23         // 官网描述:c1、c2表示Foo类的类类型(class type)
    24         // 如何解释:Foo类本身就是一个实例对象,是Class类的实例对象
    25         // 以此区分:Foo类的实例对象为foo,Foo类的类类型为c1、c2
    26         
    27         // c1、c2都是同一个类(Foo)的类类型,一个类只可能是Class类的一个实例对象
    28         // 所以c1与c2完全相等
    29         System.out.println(c1 == c2);
    30         
    31         // 第三种表示方法:
    32         Class c3 = null;
    33         try
    34         {
    35             // 写出类的全量名
    36             c3 = Class.forName("reflect.Foo");
    37         } 
    38         catch (ClassNotFoundException e)
    39         {
    40             e.printStackTrace();
    41         }
    42         // c2与c3完全相等
    43         System.out.println(c2 == c3);
    44         
    45         // 可以通过一个类的类类型创建该类的实例对象
    46         try
    47         {
    48             // 前提:要有无参的构造方法
    49             Foo f1 = (Foo) c1.newInstance();
    50             // 此时可以调用类的方法了
    51             f1.display();
    52         } 
    53         catch (InstantiationException e)
    54         {
    55             e.printStackTrace();
    56         } 
    57         catch (IllegalAccessException e)
    58         {
    59             e.printStackTrace();
    60         }
    61     }
    62 }
    63 
    64 class Foo
    65 {
    66     void display()
    67     {
    68         System.out.println("abc");
    69     }
    70 }
    Class类的使用:Class类的实例对象的三种表示方法

    Class类动态加载类的用法:
      Class.forName(“类的全称”); 这种写法不仅表示了类的类类型,还表示了动态加载类;
      要区分编译和运行:
        编译时刻加载类是静态加载类、运行时刻加载类是动态加载类;
        new 创建对象:是静态加载类,在编译时刻就需要加载所有可能用到的类,不管这些类在后面是否真用到了;(通过动态加载类可以解决该问题);

    静态加载类的方式:

     1 /**
     2  * 静态加载类的方式:通过new创建对象
     3  */
     4 package reflect.static_load;
     5 
     6 public class Office
     7 {
     8     public static void main(String[] args)
     9     {
    10         // Word类,Excel类必须都存在才能运行
    11         if("Word".equals(args[0]))
    12         {
    13             // 通过new创建对象,是静态加载类,在编译时刻就需要加载所有可能使用到的类,不管你需不需要用;所以下面报错了,因为没有定义Word和Execl类;
    14             // 现在的需求是:你想用哪个就加载哪个,哪个不用就不加载它,这就涉及到动态加载;
    15             // 通过动态加载类可以解决该问题
    16             Word word = new Word();  // 这里编译报错,因为没有Word类
    17             word.start();
    18         }
    19         
    20         if("Excel".equals(args[0]))
    21         {
    22             Excel excel = new Excel();  // 这里编译报错,因为没有Excel类
    23             excel.start();
    24         }
    25     }
    26 }
    静态加载类的方式:通过new创建对象

    动态加载类的方式:

     1 /**
     2  * 动态加载类
     3  */
     4 package reflect.dynamic_load;
     5 
     6 public class OfficeBetter
     7 {
     8     public static void main(String[] args)
     9     {
    10         // 实例一
    11         try
    12         {
    13             // 动态加载类,在运行时刻加载;就算此时没有定义Execl类,编译也没有报错;只有在运行时才会报错
    14             Class c1 = Class.forName("reflect.dynamic_load.Excel");
    15         } 
    16         catch (ClassNotFoundException e)
    17         {
    18             e.printStackTrace();
    19         }
    20         
    21         // 实例二
    22         // 动态加载类,在运行时刻加载
    23         try
    24         {
    25             Class c2 = Class.forName("reflect.dynamic_load.Excel");
    26             // 如下直接创建具体类的类对象不合适,如果你想要的是Office类对象,但加载的可能是Excel类对象
    27             Word word = (Word) c2.newInstance();  // 运行时报错,因为c2是Excel类的类类型
    28             word.show();
    29             Excel excel = (Excel) c2.newInstance();
    30             excel.show();
    31         } 
    32         catch (ClassNotFoundException e)
    33         {
    34             e.printStackTrace();
    35         }
    36         catch (InstantiationException e)
    37         {
    38             e.printStackTrace();
    39         } 
    40         catch (IllegalAccessException e)
    41         {
    42             e.printStackTrace();
    43         }
    44         
    45         // 实例三
    46         try
    47         {
    48             // 动态加载类,在运行时刻加载
    49             Class c3 = Class.forName("reflect.dynamic_load.Excel");
    50             // 通过类类型创建具体类的实例对象
    51             // 统一标准,优化实例二
    52             OfficeAble oa = (OfficeAble)c3.newInstance();
    53             oa.show();
    54         } 
    55         catch (ClassNotFoundException e)
    56         {
    57             e.printStackTrace();
    58         }
    59         catch (InstantiationException e)
    60         {
    61             e.printStackTrace();
    62         } 
    63         catch (IllegalAccessException e)
    64         {
    65             e.printStackTrace();
    66         }
    67     }
    68 }
    动态加载类
    1 package reflect.dynamic_load;
    2 
    3 public interface OfficeAble
    4 {
    5     public void show();
    6 }
    View Code
    1 package reflect.dynamic_load;
    2 
    3 public class Word implements OfficeAble
    4 {
    5     public void show()
    6     {
    7         System.out.println("word...work");
    8     }
    9 }
    View Code
    1 package reflect.dynamic_load;
    2 
    3 public class Excel implements OfficeAble
    4 {
    5     public void show()
    6     {
    7         System.out.println("excel...work");
    8     }
    9 }
    View Code

    基本数据类型对应的类类型:

     1 /**
     2  * 基本数据类型和一些关键字都存在对应的类类型
     3  */
     4 package reflect;
     5 
     6 public class ClassTest02
     7 {
     8     public static void main(String[] args)
     9     {
    10         Class c1 = int.class; // int基本类型对应的类类型
    11         Class c2 = double.class;
    12         // 打印出类类型的名称
    13         System.out.println(c1.getName());  // 结果:int 
    14         System.out.println(c2.getName());  // 结果:double
    15         
    16         Class c3 = Double.class; // Double类的类类型
    17         Class c4 = String.class;
    18         System.out.println(c3.getName());  // 结果:java.lang.Double
    19         System.out.println(c4.getName());  // 结果:java.lang.String
    20         System.out.println(c4.getSimpleName());  // 结果:String,不带包名的类名称
    21         
    22         // 只要是在类里面声明的返回值啊什么的基本都有对应的类类型
    23         Class c5 = void.class; // void关键字对应的类类型
    24         System.out.println(c5.getName());
    25     }
    26 }
    基本数据类型和一些关键字都存在对应的类类型

    Class类的基本API:获取类的常用(全部)信息:

      1 /**
      2  * Class类的基本API:获取类的常用信息;
      3  * 获取类的信息,要先获取类的类类型
      4  */
      5 package reflect;
      6 
      7 import java.lang.reflect.Constructor;
      8 import java.lang.reflect.Field;
      9 import java.lang.reflect.Method;
     10 
     11 public class ClassTest03
     12 {
     13     public static void main(String[] args)
     14     {
     15         
     16     }
     17     
     18     // 获取方法的信息
     19     public static void getMethodsMessage(Object obj)
     20     {
     21         // 先获取类的类类型
     22         // 因为我们有了类的对象,所以通过这种方法获取类的类类型
     23         // 传递的是哪个子类的对象,获取的就是那个子类的类类型
     24         Class c = obj.getClass();  
     25         
     26         // 获取类的完整名称
     27         System.out.println(c.getName());
     28         
     29         // 获取类的名称(不是完整的名称)
     30         System.out.println(c.getSimpleName());
     31         
     32         // 获取类的方法
     33         // 万事万物都是对象,方法也是对象
     34         // 一个成员方法就是一个java.lang.reflect.Method类的对象,Method类里面封装了关于成员方法的操作
     35         // getMethods():获取所有的public修饰的函数,包括父类继承而来的
     36         Method[] ms = c.getMethods();
     37         // getDeclaredMethods():获取所有该类自己声明的方法,不问访问权限,不包括继承来的方法
     38         Method[] ms2 = c.getDeclaredMethods();
     39         
     40         // 下面获取方法的信息
     41         for(int i=0;i<ms.length;i++)
     42         {
     43             // 获取方法的返回值类型的类类型
     44             Class returnType = ms[i].getReturnType();
     45             // 获得方法的返回值类型的类类型的名字
     46             System.out.println(returnType.getName());
     47             
     48             // 获取方法的名称
     49             System.out.println(ms[i].getName());
     50             
     51             // 获取方法的参数列表的类型的类类型
     52             Class[] parameterTypes = ms[i].getParameterTypes();
     53             for(int j=0;j<parameterTypes.length;j++)
     54             {
     55                 // 获取方法的参数类型的类类型的名字
     56                 System.out.println(parameterTypes[j].getName());
     57             }
     58         }
     59     }
     60     
     61     // 获取成员变量的信息
     62     private static void getFieldsMessage(Object obj)
     63     {
     64         // 先获取类的类类型
     65         Class c = obj.getClass();
     66         
     67         // 成员变量也是对象,是java.lang.reflect.Field类的对象,Field类里面封装了关于成员变量的操作
     68         // getFields():获取所有的public的成员变量的信息
     69         Field[] fs = c.getFields();
     70         // getDeclaredFields():获取该类自己声明的成员变量的信息
     71         Field[] fs2 = c.getDeclaredFields();
     72         for(Field f:fs)
     73         {
     74             // 获取成员变量的类型的类类型
     75             Class fieldTypes = f.getType();
     76             // 获取成员变量的类型的类类型的名字
     77             String typeName = fieldTypes.getName();
     78             System.out.println(typeName);
     79             // 获取成员变量的名字
     80             String fieldName = f.getName();
     81             System.out.println(fieldName);
     82         }
     83     }
     84     
     85     // 获取对象的构造函数的信息
     86     public static void getConstructorMessage(Object obj)
     87     {
     88         // 先获取类的类类型
     89         Class c = obj.getClass();
     90         
     91         // 构造函数也是对象,是java.lang.reflect.Constructor类的对象,Constructor类中封装了构造函数的信息
     92         // c.getConstructors():获得所有的public的构造函数
     93         Constructor[] con = c.getConstructors();
     94         // getDeclaredConstructors():获得所有的构造函数;也可以说获得所有自己声明的构造方法,因为构造方法都是必须要自己声明的;
     95         Constructor[] con2 = c.getDeclaredConstructors();
     96         for(Constructor constr:con2)
     97         {
     98             // 获取构造函数的参数列表的类型的类类型
     99             Class[] parametersTypes = constr.getParameterTypes();
    100             for(Class parametersType:parametersTypes)
    101             {
    102                 // 获取构造函数的参数列表的类型的类类型的名称
    103                 System.out.println(parametersType.getName());
    104             }
    105             
    106             // 获取构造函数的名字
    107             System.out.println(constr.getName());
    108         }
    109     }
    110 }
    Class类的基本API:获取类的常用信息

    方法的反射的基本操作:
    1、如何获取某个方法:
      方法的名称和方法的参数列表才能唯一决定某个方法;
    2、方法反射的操作:
      method.invoke(对象,参数列表);

     1 /**
     2  * 方法的反射操作
     3  * 要获取一个方法,就是获取类的信息,获取类的信息首先要获取类的类类型
     4  */
     5 package reflect;
     6 
     7 import java.lang.reflect.InvocationTargetException;
     8 import java.lang.reflect.Method;
     9 
    10 public class MethodTest01
    11 {
    12     public static void main(String[] args)
    13     {
    14         // 获取需要的方法:方法名+参数列表唯一决定一个方法
    15         
    16         // 先获取类类型
    17         A a = new A();
    18         Class c = a.getClass();
    19         
    20         // 再获取方法:方法名+参数列表
    21         try
    22         {
    23             // 获取方法
    24             // getMethod():获取public方法
    25             // getDeclaredMethod():获取自己声明的方法
    26             Method m = c.getMethod("show", new Class[]{int.class,int.class});
    27             // 也可以这样写
    28             Method m2 = c.getMethod("show", int.class,int.class);
    29             
    30             // 获取方法后,进行方法的反射操作
    31             // 以前调用方法是这样写的,而方法的反射操作是用n对象来进行方法调用,但两者的效果是一样的
    32             // a.show(1,2);
    33             // 方法的反射操作
    34             // 方法如果没有返回值,返回null,有具体的返回值就返回具体的返回值
    35             Object o = m.invoke(a, new Object[]{1,2});
    36             // 也可以这样写
    37             Object o2 = m2.invoke(a, 1,2);
    38             
    39             Method m3 = c.getMethod("show", new Class[]{String.class,String.class});
    40             Method m4 = c.getMethod("show", String.class,String.class);
    41             Object o3 = m3.invoke(a, new Object[]{"hello",",world"});
    42             Object o4 = m4.invoke(a, "hello",",world");
    43             
    44             // 方法的形参为空场景
    45             Method m5 = c.getMethod("show", new Class[]{});
    46             // 或者没有就不传
    47             Method m6 = c.getMethod("show");
    48             Object o5 = m5.invoke(a, new Object[]{});
    49             Object o6 = m6.invoke(a);
    50         } 
    51         catch (NoSuchMethodException e)
    52         {
    53             e.printStackTrace();
    54         } 
    55         catch (SecurityException e)
    56         {
    57             e.printStackTrace();
    58         }
    59         catch (IllegalAccessException e)
    60         {
    61             e.printStackTrace();
    62         } 
    63         catch (IllegalArgumentException e)
    64         {
    65             e.printStackTrace();
    66         } 
    67         catch (InvocationTargetException e)
    68         {
    69             e.printStackTrace();
    70         }
    71     }
    72 }
    73 
    74 class A
    75 {
    76     public void show(int i,int j)
    77     {
    78         System.out.println(i + j);
    79     }
    80     
    81     public void show(String i,String j)
    82     {
    83         System.out.println(i.toUpperCase() + "," + j.toUpperCase());
    84     }
    85     
    86     public void show()
    87     {
    88         
    89     }
    90 }
    方法的反射操作

    通过反射了解集合泛型的本质:

     1 /**
     2  * 通过反射了解集合泛型的本质
     3  */
     4 package reflect;
     5 
     6 import java.lang.reflect.InvocationTargetException;
     7 import java.lang.reflect.Method;
     8 import java.util.ArrayList;
     9 
    10 public class MethodTest02
    11 {
    12     public static void main(String[] args)
    13     {
    14         ArrayList list = new ArrayList();
    15         ArrayList<String> list1 = new ArrayList<String>();
    16         
    17         list1.add("123");
    18         // 下面这样写是错误的,因为泛型限制的加入的对象类型
    19         // list1.add(23);
    20         
    21         Class c1 = list.getClass();
    22         Class c2 = list1.getClass();
    23         
    24         // 反射的操作都是编译之后(运行时)的操作
    25         // 结果为true,说明编译之后的集合的泛型是去泛型化的,就是说编译之后集合就没有泛型了
    26         // java中集合的泛型是防止错误输入的,只在编译时有效,绕过编译就无效了
    27         // 验证:通过方法的反射绕过编译
    28         System.out.println(c1 == c2);  // true
    29         
    30         // 验证:通过方法的反射操作绕过编译
    31         try
    32         {
    33             Method m = c2.getMethod("add", Object.class);
    34             m.invoke(list1, 1); // 绕过编译操作就绕过了泛型,能添加int类型数据
    35             System.out.println(list1.size());
    36             System.out.println(list1);
    37             
    38             // 现在就不能用String类型遍历了,因为有了int类型
    39         } 
    40         catch (NoSuchMethodException e)
    41         {
    42             e.printStackTrace();
    43         } 
    44         catch (SecurityException e)
    45         {
    46             e.printStackTrace();
    47         }
    48         catch (IllegalArgumentException e)
    49         {
    50             e.printStackTrace();
    51         } 
    52         catch (InvocationTargetException e)
    53         {
    54             e.printStackTrace();
    55         }
    56         catch (IllegalAccessException e)
    57         {
    58             e.printStackTrace();
    59         }
    60     }
    61 }
    通过反射了解集合泛型的本质
  • 相关阅读:
    springmvc源码分析上之HandlerMapping
    java web api接口调用
    centos6 hadoop2.7.3分布式搭建
    大话java基础知识一之为什么java的主函数入口必须是public static void
    jQuery引用
    windows 服务的卸载
    java 环境安装
    python matplotlib 折线图的制作
    python matplotlib 简单柱状图的制作
    python 安装库时 Failed building wheel for 错误处理
  • 原文地址:https://www.cnblogs.com/kehuaihan/p/8453525.html
Copyright © 2020-2023  润新知