反射与类操作

1、在反射机制的处理过程中不仅仅是实例化对象的处理操作,还有类的组成结构操作,类的组成结构:父类、父接口

包、属性、方法等

2、获取类的基本信息

获取指定类的Class对象:Class<?> cls = Person.class ;

获取类所在的包名称:public Package getPackage​()

获取父类的定义:public Class<? super T> getSuperclass​()

获取父接口的定义:public Class<?>[] getInterfaces​()

当获取了一个类的Class对象之后就可以获取这个类的所有继承结构信息。

2、反射调用构造方法

实例化方法替代: clazz.getDeclaredConstructor().newInstance()

所有类的构造方法都可以通过Class类来完成:

获取本类所有构造方法:public Constructor<?>[] getDeclaredConstructors​() throws SecurityException

获取本类指定构造方法:public Constructor<T> getDeclaredConstructor​(Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException

获取所有构造方法:public Constructor<?>[] getConstructors​() throws SecurityException

获取指定构造方法:public Constructor<T> getConstructor​(Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException

(两大类的方法实际上无区别)例:

Class<?> cls = Person.class ; //获取指定类的Class对象
Constructor<?> constructor = cls.getConstructor(String.class,int.class) ; //获取指定参数类型的构造方法
Object obj = constructor.newInstance("a",11) ; //实例化对象
System.out.println(obj) ; //调用类对象中toString()方法

虽然程序代码本身允许开发者调用有参构造处理,但是所有使用反射的类中最好提供无参构造,这样实例化可以达到统一性。

3、反射调用普通方法

在进行反射处理时,在类提供有实例化对象的前提条件下,可以通过反射来获取类中的全部方法。

在Class类中提供的方法:

获取全部方法:public Method[] getMethods​() throws SecurityException

获取指定方法:public Method getMethod​(String name,Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException

获取本类全部方法:public Method[] getDeclaredMethods​() throws SecurityException

获取本类指定方法:public Method getDeclaredMethod​(String name,Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

注意返回类型:Constructor类 和 Method类都是java.lang.reflect包中的,其信息的获取依靠的是类中提供toString()方法完成的,能够获取方法的修饰符、返回值类型、参数类型等信息。用户也可以进行自定义显示。

Method类中的一个重要方法:

反射调用类中的方法:public Object invoke​(Object obj,Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

//获取指定类的Class对象
Class<?> cls = Class.forName("com.demo.Person") ;
//调用无参构造实例化
Object obj = cls.getDeclaredConstructor().newInstance() ;
//进行方法调用要获取方法名称,参数类型
String setMethodName = "setName" ; //方法名称
Method getMethod = cls.getDeclaredMethod(setMethodName,String.class) ;
//调用方法
String value = "a" ;
getMethod.invoke(obj,value) ; //等价于:Person对象.setName(value) ;

String getMethodName = "getName" ;
Method getMethod = cls.getDeclaredMethod(getMethodName) ; //getName()方法没有参数
System.out.println(getMethod.invoke(obj));

不会产生耦合,在复杂设计中使用会非常方便。

4、反射调用成员(Field

获取本类全部成员:public Field[] getDeclaredFields​()  throws SecurityException

获取本类指定成员:public Field getDeclaredField​(String name) throws NoSuchFieldException, SecurityException

获取父类全部成员:public Field[] getFields​() throws SecurityException

获取父类指定成员:public Field getField​(String name) throws NoSuchFieldException, SecurityException

//获取父类中的公共成员信息
Field fields [] = cls.getFields() ; //获取成员
for(Field fi : fields) {
    System.out.println(fi) ;
}
//获取子类成员信息
Field fields [] = cls.getDeclaredFields() ; //获取成员
for(Field fi : fields) {
    System.out.println(fi) ;
}

在Field类中更重要的三个方法:

设置成员属性:public void set​(Object obj,Object value) throws IllegalArgumentException,IllegalAccessException

获取成员属性:public Object get​(Object obj) throws IllegalArgumentException,IllegalAccessException

解除封装:(在设置成员属性值时,往往成员是私有的并不能直接设置或或获取,此时就需要解除封装,不仅可以解除属性封装还可以是构造方法、方法)public void setAccessible​(boolean flag)

示例:

Class<?> cls = Class.forName("com.demo.Person") ;
Object obj = cls.getConstructor().newInstance() ; //实例化对象(才会分配成员空间)
Field nameField = cls.getDeclaredField("name") ; //获取成员对象name
nameField.setAccessible​(true) ; //解除封装
nameField.set(obj,"a") ; //等价于Person对象.setName("a")
System.out.println(nameField.get(obj)) ;

实际上,对成员属性的操作,常用setter和getter方法,很少使用此种反射处理。

Field类中的一个常用方法:

获取成员类型:public Class<?> getType​()

System.out.println(nameField.getType()) ; //class java.lang.String
System.out.println(nameField.getType().getName()) ; //java.lang.String
System.out.println(nameField.getType().getSimpleName()) ; //String

继承结构:

5、Unsafe类

反射是Java的一大特点,因此会有更加丰富的类设计形式。除了JVM本身支持的反射处理外,在Java中提供了一个sun.misc.Unsafe类,该类的主要特点是可以利用反射来获取对象,并且直接使用底层的C++来代替JVM执行,即可以绕过JVM的管理机制,同时项目之中也无法使用JVM的内存管理机制以及垃圾回收处理。

使用Unsafe类首先需要确认类中定义的构造方法与常量问题:

private Unsafe() {}
private static final Unsafe theUnsafe = new Unsafe() ;

在这个Unsafe类中没有提供static方法,如果想要获得这个类的对象,就必须利用反射机制来完成。

实现示例:

Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
field.setAccessible(true) ;
field.get(null) ; //static属性不需要传递实例化对象

在传统的开发之中,一个程序类必须通过实例化对象后才可以调用类中的普通方法,以单例设计模式为例(注意与传统饿汉式的区别):

import java.lang.reflect.Field ;
import sun.misc.Unsafe ;
public class BDemo {
    public static void main(String[] args) throws  Exception {
        Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
        field.setAccessible(true) ;
        Unsafe unsafeObject = (Unsafe)field.get(null) ;
        //利用Unsafe类绕过JVM的管理机制,可以在没有实例化对象的情况下获取类实例化对象
        Person instance = (Person)unsafeObject.allocateInstance(Person.class) ;
        instance.println() ; //调用方法
    }
}
class Person {
    private Person() {
        System.out.println("构造方法") ;
    }
    public void println() {
        System.out.println("普通方法") ;
    }
}

Unsafe类只能说为我们的开发提供了一些更加方便的处理机制,但是由于此种操作不受JVM的管理,所以并不建议使用,在设计单例设计模式时可以提及Unsafe类,以加深理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值