Java反射和泛型----你真的不知道哟!

Java反射和泛型----带你通向光明顶


目录

1. Java反射---基础巩固 

1.1Class概述

1.2 Field概述

1.3Method概述

1.4 Constructor概述

2. 注解(Annotation)

2.1 Annotation概述

2.2 使用元注解

2.3 自定义注解

2.4 使用反射API读取注解

3. 泛型---基础巩固 

4. 泛型---擦拭法 

5. 泛型---通配符 

5.1 extends通配符

5.2 super通配符 

5.3 无限定通配符

6. 反射与泛型

 


1. Java反射---基础巩固 

 

1.1Class概述

Class实例比较和instanceof的差别:

Java反射和泛型----你真的不知道哟!_第1张图片

从Class实例获取class信息:

  • getName( )
  • getSimpleName( )
  • getPackage( )

从Class实例判断class类型:

  • isInsterface( )
  • isEnum( )
  • isArray( )
  • isPrimitive( ) —— 判断是否是基本类型,如int、double等

创建class实例:

  • newInstance( )

动态加载

  •  利用JVM动态加载class的特性,可以在运行期根据条件加载不同的实现类

Java反射和泛型----你真的不知道哟!_第2张图片

class总结

  • JVM为每个加载的class创建对应的Class实例来保存class的所有信息
  • 获取一个class对应的Class实例后就可以获取该class的所有信息 
  • 通过Class实例获取class信息的方法称为Reflection
  • JVM总是动态加载class,可以在运行期根据条件控制加载class

1.2 Field概述

通过Class实例获取field信息:

  • getField(name):获取某个public的field(包括父类)
  • getDeclaredField(name):获取当前类的某个field(不包括父类)
  • getFields():获取所有public的field(包括父类)
  • getDeclaredFields():获取当前类的所有field(不包括父类)

Field对象:(包含一个field的所有信息)

  • getName()
  • getType()
  • gtModifiers() —— 获取修饰类型

Java反射和泛型----你真的不知道哟!_第3张图片

获取和设置field的值:(对static类型也能操作)

  • get(Object)获取一个实例的该字段
  • set(Object,Object)设置一个实例的该字段值

Java反射和泛型----你真的不知道哟!_第4张图片

提示: setAccessibl(true)可能失败

  • 定义了SecurityManager
  • SecurityManager的规则阻止了对该Field设置accessible,例如:当规则应用于所有的java和javax开头的package的类

Field总结 

  • Field对象封装了字段的所有信息
  • 通过Class实例的方法可以获取Field实例:getField/getFields/getDeclaredField/getDeclaredFields
  • 通过Field实例可以获取字段信息:getName/getType/getModifiers
  • 通过Field实例可以读取或设置某个对象的字段:get(Object)/set(Object,Object)

1.3Method概述

通过Class实例获取method信息:

  • getMethod(name,Class...):获取某个public的method(包括父类)
  • getDeclaredMethod(name,Class...):获取当前类的某个method(不包括父类)
  • getMethods():获取所有public的method(包括父类)
  • getDeclaredMethods():获取当前类的所有method(不包含父类)

Method对象:(包含一个method的所有信息)

  • getName()
  • getReturnType()
  • getParameterType()
  • getModifiers()

Method方法调用:

  • Object invoke(Object) —— 调用无参method

Java反射和泛型----你真的不知道哟!_第5张图片

  • Object invoke(Object,Object...) —— 调用有参method

Java反射和泛型----你真的不知道哟!_第6张图片

 提示: setAccessibl(true)可能失败

Java反射和泛型----你真的不知道哟!_第7张图片

多态

从Person,class获取的Method作用于Student实例时:

  • 实际调用方法是Student覆写的方法
  • 保证了多态的正确性

Java反射和泛型----你真的不知道哟!_第8张图片

Method总结 

  • Method对象封装了方法的所有信息
  • 通过Class实例的方法可以获取Method实例:getMethod/getMehtods/getDeclaredMethod/getDeclaredMethods
  • 通过Method实例可以获取方法信息:getName/getReturnType/getParameterTypes/getModifiers
  • 通过Method实例可以调用某个对象的方法:Object invoke(Object instance,Object...parameters)
  • 通过设置setAccessible(true)来访问非publuc方法

1.4 Constructor概述

Class.newInstance()只能调用public无参数构造方法

Constructor对象包含一个构造方法得到所有信息,可以创建一个实例:

Java反射和泛型----你真的不知道哟!_第9张图片

通过Class实例获取Constructor信息

  • getConstructor(Class...):获取某个public的Constructtor
  • getDeclaredConstructor(Class...):获取某个Constructor
  • getConstructors():获取所有public的Constructor
  • getDeclaredConstructors():获取所有Constructor

 提示: setAccessibl(true)可能失败

Constructor总结

  • Constructor对象封装了构造方法的所有信息
  • 通过Class实例的方法可以获取Constructor实例:getConstructor/getConstructors/getDeclaredConstructor/getDeclaredConstructors
  • 通过Constructor实例可以创建一个实例对象:newInstance(Object...parammeters)
  • 通过设置setAccessible(true)来访问非public构造方法 

其他反射

获取父类的Class:

  • Class getSuperclass()
  • Object的父类是null
  • intrface的父类是null

获取当前类直接实现的interface:

  • Class[] getInterfaces()
  • 不包括间接实现的interface
  • 没有interface的class返回空数组
  • interface返回继承的interface

判断一个向上转型是否成立:

  • bool isAssignableFrom(Class)

Java反射和泛型----你真的不知道哟!_第10张图片

提示:Number下有多个实现类,无法转型为Integer

利用以上反射遍历指定class下的所有interfaces:

Java反射和泛型----你真的不知道哟!_第11张图片

其他反射总结

  • 通过Class对象可以获取继承关系:getSuperclass() 、getInterfaces()
  • 通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否正确

2. 注解(Annotation)

2.1 Annotation概述

  • 注解是放在Java源码的类、方法、字段、参数前的一种标签

Java反射和泛型----你真的不知道哟!_第12张图片

注解的作用:

  • 注解本身对代码逻辑没有任何影响
  • 如何使用注解由工具决定

编译器可以使用的注解:

  • @Override:让编译器检查该方法是否正确地实现类覆盖
  • @Deprecated:告诉编译器该方法已经被标记为“作废”,在其他地方引用将会出现编译警告
  • @SuppressWarnings

Java反射和泛型----你真的不知道哟!_第13张图片

注解定义配置参数:

  • 配置参数由注解类型定义
  • 配置参数可以包括:所有基本类型、String、枚举类型、数组
  • 配置参数必须为常量

Java反射和泛型----你真的不知道哟!_第14张图片

  • 缺少某个配置参数将使用默认值
  • 如果只写常量,相当于省略了value参数
  • 如果只写注解,相当于全部使用默认值

Java反射和泛型----你真的不知道哟!_第15张图片

注解概述总结

  • 注解(Annotation)是Java语言用于工具处理的标注
  • 注解可以配置参数,没有指定配置的参数使用默认值
  • 如果参数名称为value可以省略参数名称

2.2 使用元注解

使用@interface定义注解:——非元注解

  • 注解的参数类似无参数方法
  • 可以设定一个默认值(推荐)
  • 把最常用的参数命名为value(推荐)

使用@Target定义Annotation可以应用于源码的哪些位置:

  • 类或接口:ElementType.TyPE
  • 字段:ElementType.FIELD
  • 方法:ElementType.METHOD
  • 构造方法:ElementType.CONSTRUCTOR
  • 方法参数:ElementType.PARAMETER

Java反射和泛型----你真的不知道哟!_第16张图片

使用@Retention定义Annotation的生命周期:

  • 仅编译期:RetentionPolicy.SOURCE
  • 仅class文件:RetentionPolicy.CLASS
  • 运行期:RetentionPolicy.RUNTIME

Java反射和泛型----你真的不知道哟!_第17张图片

如果@Retention不存在,则该Annotation默认为CLASS;通常自定义的Annotation都是RUNTIME。

Annotation的生命周期: 

  • RetentionPolicy.SOURCE:编译器在编译时直接丢弃@Override
  • RetentionPolucy.CLASS:该Annotation仅存储在class文件中
  • RetentionPolicy.RUNTIME:在运行其可以读取该Annotation

使用@Repeatable定义Annotation是否可重复:

  • JDK>=1.8

Java反射和泛型----你真的不知道哟!_第18张图片

使用@Inherited定义子类是否可继承父类定义的Annotation

  • 仅针对@Target为TYPE类型的Annotation
  • 仅针对class的继承
  • 对interface的继承无效

Java反射和泛型----你真的不知道哟!_第19张图片


2.3 自定义注解

定义注解的步骤:

  • 用@interface定义注解
  • 用元注解(meta annotation)配置注解:Target必须设置、Retention一般设置为RUNTIME、通常不必写@Inherited和@Repeatable等
  • 定义注解参数和默认值

Java反射和泛型----你真的不知道哟!_第20张图片

举个例子

Java反射和泛型----你真的不知道哟!_第21张图片Java反射和泛型----你真的不知道哟!_第22张图片

自定义注解总结 

  • 使用@interface定义注解
  • 可定义多个参数和默认值,核心参数使用value名称
  • 必须设置@Target来指定Annotation可以应用的范围
  • 应当设置@Retention为RUNTIME便于运行期读取该Annotation

2.4 使用反射API读取注解

如何读取RUNTIME类型的注解:

  • Annotation也是class
  • 所有Annotation继承自java.lang.annotation.Annotation
  • 使用反射API

Java反射和泛型----你真的不知道哟!_第23张图片

使用反射API读取Annotation:

  • Class.isAnnotationPresent(Class)
  • Field.isAnnotationPresent(Class)
  • Method.isAnnotationPresent(Class)
  • Constructor.isAnnotationPresent(Class)

Java反射和泛型----你真的不知道哟!_第24张图片

Java反射和泛型----你真的不知道哟!_第25张图片

动态判断注解

Java反射和泛型----你真的不知道哟!_第26张图片

Java反射和泛型----你真的不知道哟!_第27张图片

反射API读注解总结

  • 可以在运行期通过反射读取RUNTIME类型的注解,不要漏写@Rentention(RetentionPolicy.RUNTIME)
  • 可以通过工具处理注解来实现相应的功能:对JavaBean的属性值按规则进行检查、JUnit会自动运行@Test注解的测试方法

3. 泛型---基础巩固 

泛型概述

泛型就是定义一种模板,例如ArrayList

  • 在代码中为用到的类创建对应的ArrayList<类型>,如:ArrayList strList=new ArrayList();
  • 编译器针对类型做检查:strList.add("hello");  strList.add(new Integer(123)); //compile error!

泛型的继承关系

  • ArrayList实现了List接口:可以向上转型

Java反射和泛型----你真的不知道哟!_第28张图片

注:不能把ArrayList向上转型为ArrayList或List,因为ArrayList和ArrayList之间没有继承关系。代码如下:

Java反射和泛型----你真的不知道哟!_第29张图片

泛型总结

  • 泛型就是编写模板代码来适应任意类型
  • 不必对类型进行强制转换
  • 编译器将对类型进行检查
  • 注意泛型的继承关系

使用泛型 

  • List list = new ArrayList<>(); 可以省略类型,编译器能自动推断出类型
  • Arrays.sort()中的排序的自定义类型需要实现Comparable泛型接口:

Java反射和泛型----你真的不知道哟!_第30张图片

总结

  • 使用泛型时,把泛型参数替换为需要的class类型:List list = new ArrayList<>();
  • 不指定泛型参数类型时,编译器会给出警告,且只能将视为Object类型

编写泛型

如何编写一个泛型类:

  • 按照某种类型编写类,例如:String
  • 标记所有的特定类型
  • 把特定的类型替换为T,并声明

Java反射和泛型----你真的不知道哟!_第31张图片

泛型类型不能用于静态方法:

  • 编译错误
  • 编译器无法在静态字段或静态方法中使用泛型类型
  • 静态方法需要单独写成“泛型”,使用另一个泛型

Java反射和泛型----你真的不知道哟!_第32张图片

泛型可以定义多种类型

  • 使用类型

Java反射和泛型----你真的不知道哟!_第33张图片

编写泛型总结

  • 编写泛型时需要定义泛型类型:public class Pair{...}
  • 静态方法不能引用泛型类型,必须定义其他类型来实现“泛型”:public static create(K first,K last){...}
  • 泛型可以同时定义多种类型:public class Pair{...}

4. 泛型---擦拭法 

擦拭法

  • 编译器把类型视为Object

Java反射和泛型----你真的不知道哟!_第34张图片

  • 编译器根据实现安全的强制转型

Java反射和泛型----你真的不知道哟!_第35张图片

擦拭法局限性

  • 无法取得带泛型的Class
  • 无法判断带泛型的Class

Java反射和泛型----你真的不知道哟!_第36张图片

  • 不能实例化T类型
  • 因为擦拭后实际上是new Object()
  • 实例话T类型必须借助Class

Java反射和泛型----你真的不知道哟!_第37张图片

分析equals方法:

泛型继承

 可以继承自泛型类:

  • 父类的类型是Pair,子类的类型是IntPair
  • 子类可以获取父类的泛型类型Integer

Java反射和泛型----你真的不知道哟!_第38张图片

注:Type继承结构

Java反射和泛型----你真的不知道哟!_第39张图片

获取父类泛型类型

Java反射和泛型----你真的不知道哟!_第40张图片

Java反射和泛型----你真的不知道哟!_第41张图片

总结

  • Java的泛型采用擦拭法实现
  • 擦拭法决定了泛型

不能是基本类型

不能获取带泛型类型的Class,如Pair.class

不能判断带泛型类型的类型,如public boolean equals(T obj) 

不能判断带泛型类型的类型,如x instanceof Pair

不能实例化T类型,如new T()

泛型方法要防止重复定义方法,如public boolean equals(T obj)

  • 子类可以获取父类的泛型类型

5. 泛型---通配符 

5.1 extends通配符

泛型的继承关系:

  • Pair不是pair的子类
  • add()不接受Pair
  • 使用使方法接收所有泛型类型为Number或Number子类的Pair类

Java反射和泛型----你真的不知道哟!_第42张图片

对Pair调用getFirst()方法:

  • 方法签名:? extends Number getFirst()
  • 可以安全赋值给Number类型的变量:Number x=p.getFirst();
  • 不可以预测实际类型就是Integer:Integer x=p.getFirst();

Java反射和泛型----你真的不知道哟!_第43张图片

的通配符:

  • 允许调用get方法获取Number的引用
  • 不允许调用set方法传入Number的引用
  • 唯一例外:可以调用setFirst(null)

Java反射和泛型----你真的不知道哟!_第44张图片

extends总结

  • 使用类似通配符作为方法参数时表示:
  1. 方法内部可以调用获取Number引用的方法Number n=obj.getXxx()
  2. 方法内部无法调用传入Number引用的方法obj.setXxx(Number n) ----(null除外)
  • 使用类似定义泛型类型时表示:泛型类型限定为Number或Number的子类

5.2 super通配符 

泛型的继承关系:

  • 使用使方法接收所有泛型类型为Integer或Integer超类的Pair类

Java反射和泛型----你真的不知道哟!_第45张图片

对Pair调用setFirst()方法:

  • 方法签名:void setFirst(? super Integer)
  • 可以安全传入Integer类型的变量:p.setFirst(new Integer(123));

Java反射和泛型----你真的不知道哟!_第46张图片

对Pair调用getFirst()方法:

  • 方法签名:?super Integer getFirst()
  • 无法赋值给Integer类型的变量

Java反射和泛型----你真的不知道哟!_第47张图片

的通配符:

  • 允许调用set方法传入Integer的引用
  • 不允许调用get方法获得Integer的引用
  • 唯一例外:可以获取Object引用Object 0 = p.getFirst();

Java反射和泛型----你真的不知道哟!_第48张图片Java反射和泛型----你真的不知道哟!_第49张图片

 

extends和super比较 

方法参数为和方法参数为的区别:

  • 允许调用方法获取T的引用
  • 允许调用方法传入T的引用

5.3 无限定通配符

的通配符:

  • 不允许调用set方法(null除外)
  • 只能调用get方法获取Object引用
  • Pair和Pair不同

 Java反射和泛型----你真的不知道哟!_第50张图片

  • 可以引入泛型参数消除通配符

Java反射和泛型----你真的不知道哟!_第51张图片

super测试Demo代码如下:

Java反射和泛型----你真的不知道哟!_第52张图片 Java反射和泛型----你真的不知道哟!_第53张图片

super&无限定通配符总结 

  • 使用类似通配符作为方法参数时表示:
  1. 方法内部可以调用传入Integer引用的方法obj.setXxx(Integer n)
  2. 方法内部无法调用获取Integer引用的方法(Object除外)
  • 使用类似定义泛型类时表示:泛型类型限定为Integer或Integer的超类
  • 无限顶通配符很少使用,可以用替换

6. 反射与泛型

部分反射API是泛型

Class是泛型:

  • T newInstance()
  • Class getSuperclass()

Java反射和泛型----你真的不知道哟!_第54张图片

Costructor是泛型:

泛型数组

可以声明带泛型的数组,但不能用new创建带泛型的数组:

必须通过强制实现带泛型的数组:

 

不安全 VS 安全使用带泛型的数组:

Java反射和泛型----你真的不知道哟!_第55张图片

带泛型的数组实际上是编译器的类型擦除:

Java反射和泛型----你真的不知道哟!_第56张图片

不能直接创建T[ ]数组:

  • 擦拭后代码变为new Object[5]
  • 必须借助Class

Java反射和泛型----你真的不知道哟!_第57张图片

利用可变参数创建T[ ]数组:

  • @SafeVarargs消除编译器警告

Java反射和泛型----你真的不知道哟!_第58张图片

总结

  • 部分反射API是泛型:Class 、Constructor
  • 可以声明带泛型的数组,但不能直接创建带泛型的数组,必须强制转型
  • 可以通过Array.newInstance(Class,int)创建T[ ]数组,需要强制转型 

感觉打开了新世界------哈哈,加油,一起在现有知识基础上学习新知识!

                                                             谢谢阅读              ----知飞翀

你可能感兴趣的:(JavaSE学习笔记)