Java反射——API常用的类

Java反射API常用的类

目录

java.lang.Class

java.lang.reflect.Constructor

java.lang.reflect.Method

java.lang.reflect.Field

java.lang.reflect.Modifier


java.lang.Class

Java是一门面向对象的语言,其中“万物皆对象”这一理念非常的重要,说到面向对象,我们第一个联想到的就是“封装”、“继承”、“多态”,说到封装,那么就是把对象相同的特征,分装成一个类,那么,类他也是一个对象,这个对象“封装”的那个类就是java.lang.Class。

Java.lang.Class一个比较特殊的点就是他的实例化的过程就比较特殊,他没有共有的构造方法,所以我们无法实现如同以下代码的实例化方法获取实例化对象

Class<Dog> c = new Class();

 所有的类在实例化的时候(如以下代码:)

Dog dog = new Dog();

 Jvm在执行该段代码的时候首先回去寻找Dog.class文件,然后将Dog.class文件读取内容,存储在内存中,在生成dog对象的内存空间的同时,如果是首次实例化,则会自动在内存中新增一个Class对象,这个Class的对象是自动创建的,并且一个类只会产生一个class对象,所以不允许自己手动实例化Class对象。

正常的加载是先通过实例化对象,如上图的new Dog();然后获取到Class对象,而反射的本质则是先获取Class对象,然后通过Class对象,去获取Dog对象的各种信息。

Class类由于不能被直接实例化,所以我们会用以下三种方法获取Class对象

Class<Dog> dogClass;
//第一种:通过类名去获取Class对象
dogClass = Dog.class;
//第二种:通过对象的getClass();方法获取Class对象
Dog dog  = new Dog();
dogClass = u.getClass();
//第三种,通过Class.forName("类的路径");获取Class对象
try {
    dogClass = Class.forName("com.entity.Dog");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

不得不说这三种方式种常用第三种,因为第一种存在需要导包的问题,如果没有导包会抛出编译错误。第二种你都有对象了,还要反射做什么。第三种,一个字符串就可以,并且这个字符串我们可以采取读配置文件等方法,比较灵活。

获取到Class类之后,可以通过对象.newInstance();方法,获取到对象,如:

//获取Dog这个Class的对象
Class<Dog> dogClass;
try {
    dogClass = Class.forName("com.entity.Dog");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
//实例化
Dog dog;
try {
   dog = dogClass.newInstance();
} catch (InstantiationException e) {
    //说明没有无参的构造方法
    e.printStackTrace();
} catch (IllegalAccessException e) {
    //说明当前没有权限调用无参构造方法
    e.printStackTrace();
}

 这个方法可以会抛2个异常,具体原因见上图解释。讲完了无参的构造方法,那么有参的构造方法要怎么用呐?我们需要讲下一个API。

java.lang.reflect.Constructor

万物皆对象,对象的类也是一个对象,那么类的构造方法是不是也会有一个对象?是的,这就是我们接下来要说的Constructor类。

Constructor就是构造器的意思。我们可以通过之前获取到的Class方法,调用它的getConstructor(Class<?>... parameterTypes);方法获取它的构造器,如:

try {
    Constructor<Dog> c = dogClass.getConstructor();
    Constructor<Dog> c1 = dogClass.getConstructor(String.class,Integer.class);
} catch (NoSuchMethodException e) {
    //未找到这个方法
    e.printStackTrace();
}

 这里给大家举了两个例子,第一个没有参数是这个类的无参构造方法,第二个是参数为一个String,一个Integer的有参构造方法,如果找不到对应的构造方法,会出现NoSuchMethodException。

获取到该方法之后可以通过Constructor的newInstance(Object... initargs);方法,获取实例化对象,如

Constructor<Dog> c;
Constructor<Dog> c1;
try {
    c = dogClass.getConstructor();
    c1 = dogClass.getConstructor(String.class,Integer.class);
} catch (NoSuchMethodException e) {
    //未找到这个方法
    e.printStackTrace();
}
//获取实例化对象
try {
    //等同于Dog dog = new Dog();
    Dog dog=c.newInstance();
    //等同于Dog dog1= new Dog("旺财",3);
    Dog dog=c1.newInstance("旺财",3);
} catch (InstantiationException e) {
    //无法实例化指定的类对象时抛出
    e.printStackTrace();
} catch (IllegalAccessException e) {
    //说明你当前无权限,可以通过
    //c.setAccessible(true);
    //上面这行代码强行获取权限
    e.printStackTrace();
} catch (InvocationTargetException e) {
    //如果你的构造方法抛出了某个异常,会在这里被捕获
    //说明你调用的构造方法抛了一个异常
    e.printStackTrace();
}

 会抛出的异常都在上面解释了,请仔细看注释。

Class类返回Constructor所有的方法:

Constructor<T>

getConstructor(<?>... parameterTypes)

返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 函数。

Constructor<?>[]getConstructors()

返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 对象。

Constructor<T>getDeclaredConstructor(<?>... parameterTypes)

返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 函数。

Constructor<?>[]getDeclaredConstructors()

返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组

Constructor<?>getEnclosingConstructor()

如果此对象表示构造函数中的本地或匿名类,则返回表示底层类的立即封闭构造函数的Constructor对象。

java.lang.reflect.Method

说完了构造方法, 那么,类的方法是不是也是一个对象呐?没错,万物皆对象,接下来我们来看看Method对象。

Method对象获取的方式依旧是依靠Class对象,具体方法见以下代码:

//省略获取dogClass和dog对象的代码,具体代码参考以上博客内容

//获取该类的所有方法
Method[] m = dogClass.getMethods();
System.out.println("------------------------");
//遍历所有的方法
for (Method method : m) {
    //输出方法的名称
    System.out.println(method.getName());
    //毕竟方法是否以set开头
    if(method.getName().startsWith("set")){
        try {
            //用第一个参数dog执行该方法,参数是一个字符串“test”
            method.invoke(dog,"test");
        } catch (IllegalAccessException e) {
            //无权限异常
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            //方法抛出异常,并没有被处理
            e.printStackTrace();
        }
    }
}

 这种方法可以获取到所有的set开头的方法,如果我们只需要获取一个明确名称、参数的方法,可以使用以下代码实现:

//省略获取dogClass和dog对象的代码,具体代码参考以上博客内容

//获取该类的所有方法
Method m = null;
try {
    //获取名为setName,参数为一个String的方法
    m = s.getMethod("setName",String.class);
} catch (NoSuchMethodException e) {
    //没有找到该方法会抛此异常
    e.printStackTrace();
}
try {
    //使用dog对象,执行这个setName方法,参数为“旺财”
    m.invoke(dog,"旺财");
} catch (IllegalAccessException e) {
    //无权限异常
    e.printStackTrace();
} catch (InvocationTargetException e) {
    //如果setName抛出异常没有被捕获,进入此处
    e.printStackTrace();
}

 某种角度看和获取构造方法以及构造方法的使用非常相似。

MethodgetDeclaredMethod(String name, <?>... parameterTypes)

返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 对象。

Method[]getDeclaredMethods()

返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。

MethodgetEnclosingMethod()

如果此对象表示方法中的本地或匿名类,则返回表示基础类的即时封闭方法的方法对象。

MethodgetMethod(String name, <?>... parameterTypes)

返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 对象。

Method[]getMethods()

返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 对象,包括那些由类或接口和那些从超类和超接口继承的声明。

java.lang.reflect.Field

众所周知,类有一个非常重要的元素,就是类的属性,那么属性也是一个对象,这个对象的类名字就是Field,这里也给大家总结一下,我们先从如何获取这个对象说起:

获取Field对象的四种方法都是以Class对象来获取的

FieldgetDeclaredField(String name)

返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 对象。

Field[]getDeclaredFields()

返回的数组 Field对象反映此表示的类或接口声明的所有字段 对象。

FieldgetField(String name)

返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 对象。

Field[]getFields()

返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 对象。 

他们区别应该很容易看到,有s则说明是返回全部的内容,存在Declared说明会获取类中所有的属性(public、protected、default、private),但不包括继承的属性,不存在就会返回获取类中public类型的属性。

比如我们的Dog类只有Name和Age这两个属性,这两个属性都是私有的(private)

//省略获取dogClass和dog对象的代码,具体代码参考以上博客内容
//获取所有共有属性
Field[] fields = dogClass.getFields();
//输出长度
System.out.println("fields.length"+fields.length);
for (Field field : fields) {
    //输出所有属性名字
    System.out.println(field.getName());
}

这个就会出现

因为你的所有属性都是私有的,共有的属性长度为0。所以我们需要调用它的 

getDeclaredField();

方法,这方法会返回所有的属性

//省略获取dogClass和dog对象的代码,具体代码参考以上博客内容
//获取所有共有属性
Field[] fields = dogClass.getDeclaredFields();
//输出长度
System.out.println("fields.length"+fields.length);
for (Field field : fields) {
    //输出所有属性名字
    System.out.println(field.getName());
}

 这时会返回长度为2,分别为name、age

Field的常用方法:

voidset(Object obj, Object value)

将指定对象参数上的此 Field对象表示的字段设置为指定的新值。

voidsetBoolean(Object obj, boolean z)

设置作为一个字段的值 boolean指定的对象上。

voidsetByte(Object obj, byte b)

设置作为一个字段的值 byte指定的对象上。

voidsetChar(Object obj, char c)

设置作为一个字段的值 char指定的对象上。

voidsetDouble(Object obj, double d)

设置作为一个字段的值 double指定的对象上。

voidsetFloat(Object obj, float f)

设置作为一个字段的值 float指定的对象上。

voidsetInt(Object obj, int i)

设置作为一个字段的值 int指定的对象上。

voidsetLong(Object obj, long l)

设置作为一个字段的值 long指定的对象上。

voidsetShort(Object obj, short s)

设置作为一个字段的值 short指定的对象上。

setXxx方法,第一个为被修改的对象,第二个为需要修改的值。

其中要特别说明一下,他们都会抛出两种异常:

IllegalAccessExceptionIllegalArgumentException

IllegalAccessException异常是因为:我们修改的那个属性是final的,无法被修改。不过由于 Field 继承AccessibleObject , 我们可以通过 AccessibleObject.setAccessible() 方法去修改变量的访问性,如field.setAccessible(true)。

IllegalArgumentException异常是因为:新value和原value的类型不一致导致。特备说明,在反射种,包装类(如Integer和int等等)他们不会自动装/拆箱,需要手动修改。

除了set方法, 还存在比较常用的方法:

booleanisEnumConstant()

如果此字段表示枚举类型的元素,则返回true ; 返回false其他。

Objectget(Object obj)

返回该所表示的字段的值 Field ,指定的对象上。

StringgetName()

返回由此 Field对象表示的字段的名称。

intgetModifiers()

返回由该 Field对象表示的字段的Java语言修饰符,作为整数。

其中看到一个方法,叫做getModifiers,此方法返回的是一个int类型,这个是修饰符的意思,那么修饰符是否也是一个类呐?我们接下来看下一个常用API。

java.lang.reflect.Modifier

没错,修饰符也是一个对象,它也有自己的类,叫做Modifier。之前我们提到的Constructor,Method,Field均存在getModifiers这个方法,这个方法会返回一个int类型,然后我们可以通过这个Modifier类,通过以下方法,将次int值作为参数可获取到你需要知道的修饰符。

static booleanisAbstract(int mod)

如果整数参数包含 abstract修饰符,则返回 truefalse返回false。

static booleanisFinal(int mod)

如果整数参数包含 final修饰符,则返回 truefalse返回false。

static booleanisInterface(int mod)

如果整数参数包含 interface修饰符,则返回 truefalse false。

static booleanisNative(int mod)

如果整数参数包含 native修饰符,则返回 truefalse返回false。

static booleanisPrivate(int mod)

如果整数参数包含 private修饰符,则返回 truefalse返回false。

static booleanisProtected(int mod)

如果整数参数包含 protected修饰符,则返回 truefalse false。

static booleanisPublic(int mod)

如果整数参数包含 public修饰符,则返回 truefalse false。

static booleanisStatic(int mod)

如果整数参数包含 static修饰符,则返回 truefalse false。

static booleanisStrict(int mod)

如果整数参数包含 strictfp修饰符,则返回 truefalse返回false。

static booleanisSynchronized(int mod)

如果整数参数包含 synchronized修饰符,则返回 truefalse返回false。

static booleanisTransient(int mod)

如果整数参数包含 transient修饰符,则返回 truefalse返回false。

static booleanisVolatile(int mod)

如果整数参数包含 volatile修饰符,则返回 truefalse返回false。

好,我说完了。 

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值