反射reflect

Class对象的获取:

有三个方法:
1、对象的getClass()方法;
2、类的.class(最安全/性能最好)属性
3、运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用)

从Class中获取信息

获取内容方法签名
构造器Constructor<T> getConstructor(Class<?>… parameterTypes)
包含的方法Method getMethod(String name, Class<?>… parameterTypes)
包含的属性Field getField(String name)
包含的Annotation<A extends Annotation > A getAnnotation(Class<A> annotationClass)
内部类Class<?>[] getDeclaredClasses()
外部类Class<?> getDeclaringClass()
所实现的接口Class<?>[] getInterfaces()
修饰符int getModifiers()
所在包Package getPackage()
类名String getName()
简称String getSimpleName()

一些判断类本身的消息

判断内容方法签名
注解类型?boolean isAnnotation()
使用了该Annotation修饰?boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
匿名类?boolean isAnonymousClass()
数组?boolean isArray()
枚举?boolean isEnum()
原始类型?boolean isPrimitive()
接口?boolean isInterface()
obj是否是该Class的实例boolean isInstance(Object obj)



使用反射生成并操作对象

Method Constructor Field这些类都实现了java.lang.reflect.Member接口,程序可以通过Method对象来执行相应的方法,通过Constructor对象来调用对应的构造器创建实例,通过Filed对象直接访问和修改对象的成员变量值.

创建对象

1、使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器);

2、先使用Class对象获取指定的Constructor对象, 再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例);

调用方法

当获取到某个类对应的Class对象之后, 就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.
私有方法要用getDeclareMethod来获取,还要打破类的封装

访问成员变量

getXXX、setXXX,

1、getXxx(Object obj): 获取obj对象的该成员变量的值, 此处的Xxx对应8中基本类型,如果该成员变量的类型是引用类型, 则取消get后面的Xxx;

2、setXxx(Object obj, Xxx val): 将obj对象的该成员变量值设置成val值.此处的Xxx对应8种基本类型, 如果该成员类型是引用类型, 则取消set后面的Xxx;

3、getDeclaredXxx方法可以获取所有的成员变量,无论private/public;

使用反射获取泛型信息

类型含义
ParameterizedType一种参数化类型, 比如Collection<String>
GenericArrayType一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable各种类型变量的公共接口
WildcardType一种通配符类型表达式, 如? ? extends Number ? super Integer


使用功能”.class”来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象

编译器将检查类型向下转型是否合法,如果不合法将抛出异常。向下转换类型前,可以使用instanceof判断。

class Base { }
class Derived extends Base { }

public class Main {
    public static void main(String[] args) {
        Base base = new Derived();
        if (base instanceof Derived) {
            // 这里可以向下转换了
            System.out.println("ok");
        }
        else {
            System.out.println("not ok");
        }
    }
}

Class是模板,Object是具体,Type是Class的父类(接口),So Everything is Class

数组:

//创建一个int类型的数组,长度为3 
int[] intArray = (int[])Array.newInstance(int.class,3); 
//通过反射的形式,给数组赋值 
for (int i = 0 ;i < intArray.length;i++){ 
Array.set(intArray,i,i + 2); 
} 
//通过反射的形式,得到数组中的值 
for (int i = 0 ; i < intArray.length;i++){ 
System.out.println(Array.get(intArray,i));
}

上述就是创建数组,访问数组中的值利用反射方式。
对于得到一个数组的Class对象,简单的可以用int[].class,或者利用Class.forName的形式得到,写法比较奇怪:

Class clz = Class.forName("[I"); 
System.out.println(clz.getTypeName());

结果为:int[]

这个forName中的字符串,[表示是数组,I表示是int,float就是F,double就是D等等,如果要得到一个普通对象的数组,则用下面的形式:

Class stringClz = Class.forName("[Ljava.lang.String;");

[表示是数组,L的右边是类名,类型的右边是一个;

这种方式获取数组的Class对象实在是太繁琐了。

在得到数组的Class对象之后,就可以调用他的一些独特的方法,比如调用getComponentType来得到数组成员的类型信息,如int数组就是成员类型就是int。

System.out.println(clz.getComponentType().getTypeName());

结果为int

静态方法属性:

//创建类 
Class<?> class1 = Class.forName("com.app.Util"); 
//获取 nameField 属性 
Field nameField = class1.getDeclaredField( "name" ) ; 
//获取 nameField 的值 
String name_ = (String) nameField.get( nameField ) ;
//没有返回值,没有参数 
Method getTipMethod1 = class1.getDeclaredMethod( "getTips" ) ; 
getTipMethod1.invoke( null ) ; 

//有返回值,没有参数 
Method getTipMethod2 = class1.getDeclaredMethod( "getTip" ) ; 
String result_2 = (String) getTipMethod2.invoke( null ) ; 

//没有返回值,有参数 
Method getTipMethod3 = class1.getDeclaredMethod( "getTip" , String.class ) ; 
String result_3 = (String) getTipMethod3.invoke( null , "第三个方法" ) ; 

//有返回值,有参数 
Method getTipMethod4 = class1.getDeclaredMethod( "getTip" , int.class ) ; 
String result_4 = (String) getTipMethod4.invoke( null , 1 ) ; 

static方法调用时,不必得到对象示例,如下:

Class cls = Class.forName("chb.test.reflect.Student"); 

Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);  

staticMethod.invoke(cls,20,"chb");//这里不需要newInstance  

//staticMethod.invoke(cls.newInstance(),20,"chb");  

从属于类,不从属于对象

当参数是 int 类型 和 Integer 类型,反射获取方法不一样:分别是int.class和Integer.class

一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射

public native boolean isInstance(Object obj);

利用反射创建数组

public static void testArray() throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.lang.String");
        Object array = Array.newInstance(cls,25);
        //往数组里添加内容
        Array.set(array,0,"hello");
        Array.set(array,1,"Java");
        Array.set(array,2,"fuck");
        Array.set(array,3,"Scala");
        Array.set(array,4,"Clojure");
        //获取某一项的内容
        System.out.println(Array.get(array,3));
    }

其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:

public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException {
        return newArray(componentType, length);
    }

如果是基本类型的包装类,则可以通过调用包装类的Type属性来获得该包装类的Class对象。
例如:

Class<?> clazz = Integer.TYPE;









参考1:JAVA中的反射机制
参考2:深入理解Java反射
参考3:Java 反射
参考4:java反射详解
参考5:java中的反射总结
参考6:详解Java反射各种应用
参考7:Java 反射 使用总结
参考8:通过Java反射调用方法
参考9:java 反射详解通俗易懂
参考10:Java反射机制
参考11:Java Reflection(一):Java反射指南
参考12:学习java应该如何理解反射?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值