笔记:Java反射机制基础

反射在百度的解释为“一种计算机处理方式,是程序可以访问、检测和修改它本身状态或行为的一种能力”,即在运行的时候可以分析代码的内容,包括注解的内容,得到需要的信息。就像在常用的IDE如Eclipse中利用了反射实现了获取类的信息。

1.Class

java.lang.Class没有公共的构造方法,因此单独声明一个Class对象是不允许的;每个类型都有一个Class对象,这个Class对象记录了改类型的interface,field,method,annotation,generics等。任何类型,包括基础数据类型(int, short, long, float, double, char, btye, boolean)以及void类型都有对应的Class对象。

package com.test.ReflectTest;
/**
 * @author 王狗蛋 
 * @date : 2017年8月13日 上午11:42:42
 */
public class Reflect {
    public static void main(String...args) throws Exception {
        // The first method to get a class object
        // This method will throws ClassNotFoundException
        Class<String> clz = (Class<String>)Class.forName("java.lang.String");
        // The second method to get a class object
        clz = String.class;

        // Now let check the attributes of clz
        System.out.println("The name of clz is " + clz.getName());
        System.out.println("Is clz a primitive " + clz.isPrimitive());

        // Of course we can check whether an object is specific class               
        System.out.println("Is string is a String " + clz.isInstance("string"));
        // And there is another method to print info
        System.out.println(clz.toGenericString());

        // Of course we can create an instance
        String instance = clz.newInstance();
        System.out.println(instance instanceof String);
    }
}

输出结果
The name of clz is java.lang.String
Is clz a primitive fase
Is string is a String true
public final class java.lang.String
true

从结果可知,clz的类名为java.lang.String,并且clz不是一个基础类型,“string”字符串是clz的类型,Class这个类是一个public final 类,由于被final修饰,Class在创建之后不会被修改,保证了代理时的安全性

2.interface
接口不能实例化并且包含了所有继承类应包含的所有方法,但接口可以被访问,也可以调用里面的方法。调用方法会在介绍invoke方法的笔记中记录 。
我们都知道String类继承Serializable,Comparable;但String类到底都继承了那些接口呢,我们来下面代码:

        /** 这段代码接上述代码 */
        Class<?>[] inters = clz.getInterfaces();
        for (Class<?> inter: inters) {
            System.out.println(inter.toGenericString());
        }

结果如下:
public abstract interface java.io.Serializable
public abstract interface java.lang.Comparable
public abstract interface java.lang.CharSequence

这三个接口就是String类继承的接口,其中Serializable就是可序列化接口,使得该类型的对象可以通过IO输出;Comparable用于实现俩个对象之间的比较,并通过方法compareTo(T object)来制定比较规则 ;CharSequence是String和AbstractStringBuilder的接口,具体内容在String笔记中介绍(我也不知道这个笔记什么时候整理,一般String和StringBuilder就够用了)

3.Field
域就是类的属性,我们可以通过一个Class对象来获取field
首先我们先弄一个类用来演示:

package com.test.ReflectTest;

/**
 * @author 王狗蛋 
 * @date : 2017年8月13日 下午12:21:06
 */
public class DemoClass {
    public int num1 = 1;
    protected int num2 = 2;
    int num3 = 3;
    private int num4 = 4;
    public static int num5 = 5````


}

然后我们继续在main方法中演示:

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;


        Class<?> clzDemo = Class.forName("com.test.ReflectTest.DemoClass");
        Object obj = clzDemo.newInstance();
        Field field = clzDemo.getField("num1");

        System.out.println(field.toGenericString());
        System.out.println(Modifier.toString(field.getModifiers()));
        System.out.println(field.getType().toGenericString());
        field.set(obj, 10);
        System.out.println(field.get(obj));

输出结果:
public int com.test.ReflectTest.DemoClass.num1
public
int
10

首先先用clzDemo.getFIeid(“field name”)获取了name为”num1”的域
然后field.getModifiers()获取field的修饰类型,但获得的是一个int型对象,需要通过Modifier的静态方法toString(int)来输出;field.getType()获取域的数据类型;通过set方法来修改值并通过get方法获取值;

在set(Object obj, Obejct value)方法中修改对象为obj的域,但num5是一个静态属性,即在内存中只存放一个num5对象,即使创建多个对象,每个对象的num5都是引用内存中那唯一的num5域的值。
所以在set()方法时,如果该域是一个静态的域,那么在传入第一个参数时可以传入空指针null,即set(null,20);这时所有对象的num5都被改为20。

可能你会想这样一个一个域取很麻烦,当然有简单的方法:

        Field[] fields = cls.getFields();
        for (Field field: fields) {
            System.out.println(field.toString() + "\t" + field.get(obj));

        }

输出结果:
public int com.test.ReflectTest.FieldDemo.num1 1
public static int com.test.ReflectTest.FieldDemo.num5 10

诶,等等,明明有5个域,你怎么就把public的域输出出来了呢?这是因为getFields()方法只会返回public域,对于private protected 和默认类型不会输出,这时我们就需要用到另一个方法getDeclaredFields()

        fields = cls.getDeclaredFields();
        for (Field field: fields) {
            //field.setAccessible(true);
            System.out.println(field.toGenericString() + "\t" + field.get(obj));
        }

这时候一定会报一个java.lang.IllegalAccessException异常,这个异常就是说没有访问权限造成的异常,这时把注释掉那行代码加上就不会有问题了,哈哈神奇吧。
输出结果:
public int com.test.ReflectTest.FieldDemo.num1 1
0
protected int com.test.ReflectTest.FieldDemo.num2 2
int com.test.ReflectTest.FieldDemo.num3 3
private int com.test.ReflectTest.FieldDemo.num4 4
public static int com.test.ReflectTest.FieldDemo.num5 5

为什么会这样呢,Accessible = true 会忽略访问权限的限制,具体会在invoke方法介绍的笔记中介绍。

4.Method
方法就是定义在类中的所有方法,构造方法需要用构造调用

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Modifier;

        Method[] methods = clz.getMethods();
        for (Method method: methods) {
            System.out.println("-----------------------");
            System.out.println("name:" + method.getName());
            System.out.print("defaultValue:" + method.getDefaultValue());
            System.out.print("generic return type:" + method.getGenericReturnType());
            System.out.print("return type:" + method.getReturnType());
            System.out.print("modifiers:" + Modifier.toString(method.getModifiers()));
            // Parameters
            Parameter[] parameters = method.getParameters();
            System.out.print(parameters.length + "parameters:");
            for (Parameter para: parameters) {
                System.out.print("name:" + para.getName());
                System.out.print("type:" + para.getType().toString());
            }
            Class<?>[] parameterTypes = method.getParameterTypes();
            System.out.print(parameterTypes.length + "parameters:");
            for (Class<?> paraType: parameterTypes){
                print("parameter smiple name: " + paraType.getSimpleName());
                System.out.print("parameter type name: " + paraType.getName());
                System.out.print("parameter modifier:" + Modifier.toString(paraType.getModifiers()));
                System.out.print(paraType.toGenericString());
            }
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            System.out.print(exceptionTypes.length + "exception types:");
            for (Class<?> exceptionType: exceptionTypes) {
                System.out.print("exception name: " + exceptionType.getName());
                System.out.print("exception simple name: " + exceptionType.getSimpleName());
                System.out.print(exceptionType.toGenericString());
            }
            System.out.print("is accessible: " + method.isAccessible());
            System.out.print("is varArgs: " + method.isVarArgs());
        }

输出结果太多了,就是String类的所有可见方法,只弄一部分结果:
name:equals
defaultValue:null
generic return type:boolean
return type:boolean
modifiers:public
1parameters:
name:arg0
type:class java.lang.Object
1parameters:
parameter smiple name: Object
parameter type name: java.lang.Object
parameter modifier:public
public class java.lang.Object
0exception types:
is accessible: false
is varArgs: false

当然如果你想看不可见的方法,可以调用getDeclaredMethods()方法,
当然在获取一个方法对象后可以通过invoke(Object rescourse, Object…argument)方法调用,具体在invoke笔记中介绍。

6.构造器
我们可以通过类对象来获取该类的构造器

import java.lang.reflect.Constructor;

        Constructor<?>[] constructors = clz.getConstructors();
        for (Constructor<?> constructor: constructors) {
            System.out.println("constructor " + constructor.getName());
            System.out.println("number of parameters: " + constructor.getParameterCount());

            System.out.println("modifiers: " + Modifier.toString(constructor.getModifiers()));

            System.out.println(constructor.toGenericString());

            Annotation[] annotaitons = constructor.getAnnotations();

            for (Annotation annotation: annotaitons) {
                System.out.println(annotation.toString());
            }
            System.out.println();
        }

输出结果:
constructor java.lang.String
number of parameters: 3
modifiers: public
public java.lang.String(byte[],int,int)

constructor java.lang.String
number of parameters: 2
modifiers: public
public java.lang.String(byte[],java.nio.charset.Charset)

constructor java.lang.String
number of parameters: 2
modifiers: public
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException

constructor java.lang.String
number of parameters: 4
modifiers: public
public java.lang.String(byte[],int,int,java.nio.charset.Charset)

constructor java.lang.String
number of parameters: 4
modifiers: public
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException

constructor java.lang.String
number of parameters: 1
modifiers: public
public java.lang.String(java.lang.StringBuilder)

constructor java.lang.String
number of parameters: 2
modifiers: public
public java.lang.String(byte[],int)
@java.lang.Deprecated()

constructor java.lang.String
number of parameters: 4
modifiers: public
public java.lang.String(byte[],int,int,int)
@java.lang.Deprecated()

我仅仅保留了一部分结果,在代码中我要求输出可见的构造器的名字,参数,修饰类型,构造器的toGenericString(),以及构造器的注解,对于注解的含义在注解介绍笔记详细介绍,从结果看有@Deprecated注解,表示该方法被遗弃,不建议使用。

java反射机制的基础就像介绍在这里,后续将继续通过笔记介绍java反射的invoke,proxy代理等。
第一篇博客如有不足还请见谅,如有原理问题欢迎提出,共同学习。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值