java反射

java 反射

一 认识反射

    1.1 简介

  1.  程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
  2. 尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。
  3. 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
  4.  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

   1.2  应用场景

  • Spring框架:IOC(控制反转)
  • Hibernate框架:关联映射等
  • 白盒测试

二 反射讲解

2.1 什么是反射

可以通过类名动态的创建对象,可以根据对象获取类中所有的属性和方法。

2.2 

Class

根据字符串得到类名Class cls=Class.forName(String className);

根据对象获取类:Class =obj.getClass();

根据类获取类:Class cls =Person.class;

根据全路径来获取:Class cls=Class.forName(报名.类名);

2.3 字段

Filed

获取所有属性Filed[] filed =cls.getDeclaredFields();

获取所有公共属性: Filed[] fields=cls.getFileds();

获取指定属性:Field fields=cls.getDeclaredFiled(Stringname)

取得指定公共属性Field fields=cls.getField(String name)

2.4 方法

Method

获得所有方法:  Methodmethods=cls.getDeclaredMethods();

获取所有公共方法:Method[] methods=cls.getMethods();

取得指定的方法:Method method=cls.getDeclaredMethod(Stringname,Class[] paramsType);

获取指定公共的方法: Method method =cls.getMethod(Stringname,Class[] paramsType);

2.5 构造函数

Constructor

获得使用特殊的参数类型的公共构: Constructor constructor=cls.getConstructor(Class[]params) 

获得类的所有公共构造函数:Constructor[] constructor=cls. getConstructors()

获得使用特定参数类型的构:Constructor constructor=cls.getDeclaredConstructor(Class[]params)

获得类的所有构造函数:Constructor[] constructor=cls.getDeclaredConstructors()

2.6 执行某个方法

Method.invoke(Object target,Object[] params);

2.7 获取类

获取方式

说明

示例

object.getClass()

每个对象都有此方法

获取指定实例对象的Class

List list = new ArrayList();

Class listClass = list.getClass();

class. getSuperclass()

获取当前Class的继承类Class

List list = new ArrayList();

Class listClass = list.getClass();

Class superClass = listClass. getSuperclass();

Object.class

.class直接获取

Class listClass = ArrayList.class;

Class.forName(类名)

用Class的静态方法,传入类的全称即可

try {

Class c = Class.forName("java.util.ArrayList");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

Primitive.TYPE

基本数据类型的封装类获取Class的方式

Class longClass = Long.TYPE;

Class integerClass = Integer.TYPE;

Class voidClass = Void.TYPE;

2.8 类生成对象

 平常情况我们通过new Object来生成一个类的实例,但有时候我们没法直接new,只能通过反射动态生成。

实例化无参构造函数的对象,两种方式:

①Class. newInstance();

②Class. getConstructor (new Class[]{}).newInstance(new Object[]{})

实例化带参构造函数的对象:

clazz.getConstructor(Class<?>... parameterTypes) .newInstance(Object... initargs)

三 处理类的继承

   3.1 类与对象的父子关系判断

isAssignableFrom()方法与instanceof关键字的区别总结为以下两个点

  • isAssignableFrom()方法是从类继承的角度去判断,instanceof关键字是从实例继承的角度去判断。
  • isAssignableFrom()方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类。

 使用方法

父类.class.isAssignableFrom(子类.class)

子类实例 instanceof 父类类型

四 范型反射(Type)

         为了程序的扩展性,最终引入了Type接口作为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。这样实现了Type类型参数接受以上五种子类的实参或者返回值类型就是Type类型的参数。为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable 和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。

4.1 反射+泛型接口类型

  • java.lang.reflect.Type:java语言中所有类型的公共父接口
  • java.lang.reflect.ParameterizedType
  • java.lang.reflect.GenericArrayType
  • java.lang.reflect.WildcardType

​​​​​​​

4.2 Type直接子接口

    ParameterizedTypeGenericArrayTypeTypeVariableWildcardType四种类型的接口

  • ParameterizedType: 表示一种参数化的类型,比如Collection
  • GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable: 是各种类型变量的公共父接口
  • WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? super Integer【wildcard是一个单词:就是“通配符”】

4.3 ParameterizedType

public interface ParameterizedType extends Type {
  
  Type[] getActualTypeArguments();
   
  Type getRawType();
    
  Type getOwnerType();

}


定义测试类型

  • private List<String> list1;
  • private List list2;
  • private Map<String,Long> map1;
  • private  Map map2;
  • private  Map.Entry<Long,Short> map3;

  field.getGenericType() instanceof  ParameterizedType 判断是否范型

Field[] fields = ParameterType.class.getDeclaredFields();
for(Field field:fields){
  System.out.println(field.getGenericType() instanceof  ParameterizedType);
}

true
false
true
false
true

Type[] getActualTypeArguments() 获取范型类里面的实际类型

Field[] fields = ParameterType.class.getDeclaredFields();
for (Field field : fields) {
    if (field.getGenericType() instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType) field.getGenericType();
        Type[] types = pType.getActualTypeArguments();
        for (Type t : types) {
            System.out.print("类型:" + t.getTypeName());
        }
        System.out.println("");
    }
}
类型:java.lang.String
类型:java.lang.String类型:java.lang.Long
类型:java.lang.Long类型:java.lang.Short

Type getRawType() 获取实际的变量类型

Field[] fields = ParameterType.class.getDeclaredFields();
for (Field field : fields) {
    if (field.getGenericType() instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType) field.getGenericType();
        Type rawType = pType.getRawType();
        System.out.println(rawType.getTypeName());
    }
}

java.util.List
java.util.Map
java.util.Map$Entry

pType.getOwnerType() 返回当前内部类的父类型

Field[] fields = ParameterType.class.getDeclaredFields();
for (Field field : fields) {
    if (field.getGenericType() instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType) field.getGenericType();
        Type rawType = pType.getOwnerType();
        System.out.println(rawType);
    }
}

null
null
interface java.util.Map

4.4 GenericArrayType

public interface GenericArrayType extends Type {

    Type getGenericComponentType();
}

表示泛型数组类型。比如:void method(ArrayList[] al){…}

【注意】<>不能出现在数组的初始化中,即new数组之后不能出现<>,否则javac无法通过。但是作为引用变量或者方法的某个参数是完全可以的。

获取泛型数组中元素的类型

源码声明:Type getGenericComponentType();

【注意】无论从左向右有几个[]并列,这个方法仅仅脱去最右边的[]之后剩下的内容就作为这个方法的返回值。

为什么返回值类型是Type?

public static  E methodV(

String[] p1,

E[] p2,

ArrayList[] p3,

E[][] p4){}

{1}. 对于String[],通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是String。因此对这个参数的返回类型是 Class

{2}. 对于E[],通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是E。因此对这个参数的返回类型是 TypeVariable

{3}. 对于ArrayList[],通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是ArrayList。因此对这个参数的返回类型是 ParameterizedType

{4}. 对于E[][],通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是E[]。因此对这个参数的返回类型是 GenericArrayType

4.5 WildcardType

public interface WildcardType extends Type {
  
    Type[] getUpperBounds();

  
    Type[] getLowerBounds();
}

表示通配符类型的表达式。

比如 void printColl(ArrayListal); 中的 ? extends Number

【注意】根据上面API的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候可以指定多个上边界是不一样。但是API说了,为了保持扩展性,这里返回值类型写成了数组形式。实际上现在返回的数组的大小就是1

获取通配符表达式对象的泛型限定的上边界的类型

源码声明:Type[] getUpperBounds();

【注意】上面说了,现阶段返回的Type[ ]中的数组大小就是1个。写成Type[ ]是为了语言的升级而进行的扩展。

例如下面的方法:

{1}. public static void printColl(ArrayList< ? extends ArrayList> al){}

通配符表达式是:? extends ArrayList,这样 extends后面是?的上边界,这个上边界是ParameterizedType类型。

{2}. public static  void printColl(ArrayList< ? extends E> al){}

通配符表达式是:? extends E,这样 extends后面是?的上边界,这个上边界是TypeVariable类型

{3}.public static  voidprintColl(ArrayList< ? extends E[]> al){}

通配符表达式是:? extends E[],这样 extends后面是?的上边界,这个上边界是GenericArrayType类型

{4}.public static  void printColl(ArrayList<? extends Number> al){}

通配符表达式是:? extends Number,这样 extends后面是?的上边界,这个上边界是Class类型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值