博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java - 反射(1)
阅读量:4562 次
发布时间:2019-06-08

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

大纲:

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类的实例对象:foo11         Foo foo = new Foo();12         13         // Foo这个类也是一个实例对象,是java.lang.Class类的实例对象14         // 任何一个类都是Class类的实例对象,这个实例对象有三种表示方法15         16         // 第一种表示方法:17         // 实际告诉我们,任何一个类都有一个隐含的静态成员变量:class18         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、c226         27         // c1、c2都是同一个类(Foo)的类类型,一个类只可能是Class类的一个实例对象28         // 所以c1与c2完全相等29         System.out.println(c1 == c2);30         31         // 第三种表示方法:32         Class c3 = null;33         try34         {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         try47         {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 Foo65 {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         try12         {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         try24         {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         try47         {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 OfficeAble4 {5     public void show();6 }
View Code
1 package reflect.dynamic_load;2 3 public class Word implements OfficeAble4 {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 OfficeAble4 {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());  // 结果:double15         16         Class c3 = Double.class; // Double类的类类型17         Class c4 = String.class;18         System.out.println(c3.getName());  // 结果:java.lang.Double19         System.out.println(c4.getName());  // 结果:java.lang.String20         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
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 MethodTest0111 {12     public static void main(String[] args)13     {14         // 获取需要的方法:方法名+参数列表唯一决定一个方法15         16         // 先获取类类型17         A a = new A();18         Class c = a.getClass();19         20         // 再获取方法:方法名+参数列表21         try22         {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 A75 {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 MethodTest0211 {12     public static void main(String[] args)13     {14         ArrayList list = new ArrayList();15         ArrayList
list1 = new ArrayList
();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); // true29 30 // 验证:通过方法的反射操作绕过编译31 try32 {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 }
通过反射了解集合泛型的本质

转载于:https://www.cnblogs.com/kehuaihan/p/8453525.html

你可能感兴趣的文章
js获取select标签选中的值[转]
查看>>
mysql连接出现error node【1045】
查看>>
踩vue的bug
查看>>
Ansible安装及配置
查看>>
浅析Sql Server参数化查询
查看>>
CodeBlocks 配置
查看>>
机器学习:随机森林
查看>>
[网络流24题] 试题库问题
查看>>
面试分享:应届前端面试经历
查看>>
Essentially No Barriers in Neural Network Energy Landscape
查看>>
A pure L1-norm principal component analysis
查看>>
SVM
查看>>
Dimension reduction in principal component analysis for trees
查看>>
Deep Linear Networks with Arbitrary Loss: All Local Minima Are Global
查看>>
golang开发:类库篇(五)go测试工具goconvey的使用
查看>>
浅谈限流(下)实战
查看>>
jpa(Java Persistence API)
查看>>
spring之雜談
查看>>
vue修改启动的端口和host
查看>>
【Django】Mac 安装pip3-install-mysqlclient 报错
查看>>