专栏名称: 刘俊重
JAVA开发
目录
相关文章推荐
Excel之家ExcelHome  ·  流程图制作太麻烦?用AI一分钟搞定 ·  13 小时前  
Excel之家ExcelHome  ·  用AI做数据分析,更快更准更简单 ·  2 天前  
完美Excel  ·  为了华为,我放弃了郁金香 ·  昨天  
浙江大学上海校友会  ·  报名|讲座·企业资本路径规划与上市筹备 ·  昨天  
浙江大学上海校友会  ·  报名|讲座·企业资本路径规划与上市筹备 ·  昨天  
51好读  ›  专栏  ›  刘俊重

死磕java底层(三)—反射、动态代理和注解

刘俊重  · 掘金  ·  · 2017-12-28 10:59

正文

请到「今天看啥」查看全文


+ age + ", name='" + name + '\' ' + ' } '; } }

测试结果如下:

遍历之后的构造函数:
public com.catchu.me.reflect.Person(int,java.lang.String)
private com.catchu.me.reflect.Person(java.lang.String)
public com.catchu.me.reflect.Person()
Person{age=0, name='刘俊重'}

由上面可以看到我们在获得某个类的Class类类型之后,可以通过反射包中的方法获取到这个类的构造函数,进而可以创建该类的对象。

2.2操作成员变量

万物皆对象,类的成员变量是java.lang.reflect.Field类的对象,通过Class类的以下方法可以获取某个类的成员变量,值得一提的是变量是包含两部分的,变量类型和变量名:

public Field getDeclaredField(String name) // 获得该类自身声明的所有变量,不包括其父类的变量
public Field getField(String name) // 获得该类自所有的public成员变量,包括其父类变量

//具体实现
Field[] allFields = class1.getDeclaredFields();//获取class对象的所有属性 
Field[] publicFields = class1.getFields();//获取class对象的public属性 
Field ageField = class1.getDeclaredField("age");//获取class指定属性 
Field desField = class1.getField("des");//获取class指定的public属性

示例代码如下:

public class TestField {
    public static void main(String[] args) throws Exception{
        Class<Person> personClass = Person.class;
        //获取所有的成员变量,包含私有的
        Field[] allFields = personClass.getDeclaredFields();
        //获取所有公有的成员变量,包含父类的
        Field[] publicFields = personClass.getFields();
        System.out.println("所有的成员变量:");
        for(Field f : allFields){
            System.out.println(f);
        }
        //获取某个变量的值
        //创建对象的实例
        Constructor<Person> c = personClass.getDeclaredConstructor(String.class);
        c.setAccessible(true); //因为该构造函数时私有的,需要在这里设置成可访问的
        Person person = c.newInstance("刘俊重");
        //获取变量name对象
        Field field = personClass.getDeclaredField("name");
        field.setAccessible(true); //因为变量name是私有的,需要在这里设置成可访问的
        //注意对比下面这两行,官方对field.get(Object obj)方法的解释是返回对象obj字段field的值
        Object value = field.get(person);
        //String name = person.getName();
        System.out.println("获取的变量的值是:"+value);
    }
}

输出结果如下:

所有的成员变量:
private int com.catchu.me.reflect.Person.age
private java.lang.String com.catchu.me.reflect.Person.name
获取的变量的值是:刘俊重

这里要注意field.get(person)方法,我们根据对象获取属性的常规方法是通过:String name = person.getName(),反射中可以通过:字段.get(对象),这也是获取对象的某个字段,有点类似于invoke方法。

2.3操作成员方法

万物皆对象,类的成员方法是java.lang.reflect.Method的对象,通过java.lang.Class类的以下方法可以获取到类的成员方法,通过方法类Method提供的一些方法,又可以调用获取到的成员方法。

public Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 得到该类所有的方法,不包括父类的 
public Method getMethod(String name, Class<?>... parameterTypes) // 得到该类所有的public方法,包括父类的

//具体使用
Method[] methods = class1.getDeclaredMethods();//获取class对象的所有声明方法 
Method[] allMethods = class1.getMethods();//获取class对象的所有public方法 包括父类的方法 
Method method = class1.getMethod("info", String.class);//返回此class1对应的public修饰的方法名是info的,包含一个String类型变量的方法
Method declaredMethod = class1.getDeclaredMethod("info", String.class);//返回此Class对象对应类的、带指定形参列表的方法

测试代码如下:

public class TestMethod {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();
        Method[] allMethods = personClass.getDeclaredMethods();
        Method[] publicMethods = personClass.getMethods();
        System.out.println("遍历所有的方法:");
        for(Method m : allMethods){
            System.out.println(m);
        }

        //下面是测试通过反射调用函数
        //通过反射创建实例对象,默认调无参构造函数
        Person person2 = personClass.newInstance();
        //获取要调用的方法,要调用study方法,包含int和String参数,注意int和Integer在这有区别
        Method method = personClass.getMethod("study", int.class, String.class);
        Object o = method.invoke(person2, 18, "刘俊重");
    }
}

测试结果:

遍历所有的方法:
public java.lang.String com.catchu.me.reflect.Person.toString()
public java.lang.String com.catchu.me.reflect.Person.getName()
public void com.catchu.me.reflect.Person.setName(java.lang.String)
public void com.catchu.me.reflect.Person.study(int,java.lang.String)
public int com.catchu.me.reflect.Person.getAge()
public void com.catchu.me.reflect.Person.setAge(int)
我叫刘俊重,我今年18,我在学习反射

注意:Object o = method.invoke(person2, 18, "刘俊重");就是调用person2对象的method方法,格式是:方法名.invoke(对象,参数),类似于获取成员变量值时的get方法。 由上面可以看出反射的强大:通过反射我们可以获取到类类型,通过Class类型我们可以获取到构造函数,进而实例化new出一个对象;通过反射我们可以获取到成员变量和成员方法,通过实例出的对象又可以获取到这些成员变量的值或调用成员方法。这才只是反射的一部分,通过反射我们还可以判断类,变量,方法,是否包含某些特定注解,还可以通过反射来动态代理去调用其它方法,跟注解和动态代理挂起勾会有无限的想象空间,比如spring框架,底层就是通过这些原理。下面在说几个反射常用的API,最后会介绍反射跟注解和动态代理的结合使用。

2.4其它方法

  • 注解中常用的方法:
Annotation[] annotations = (Annotation[]) class1.getAnnotations();//获取class对象的所有注解 
Annotation annotation = (Annotation) class1.getAnnotation(Deprecated.class);//获取class对象指定注解 
Type genericSuperclass = class1.getGenericSuperclass();//获取class对象的直接超类的 
Type Type[] interfaceTypes = class1.getGenericInterfaces();//获取class对象的所有接口的type集合
  • 获取Class对象其它信息的方法:
boolean isPrimitive = class1.isPrimitive();//判断是否是基础类型 
boolean isArray = class1.isArray();//判断是否是集合类
boolean isAnnotation = class1.isAnnotation();//判断是否是注解类 
boolean isInterface = class1.isInterface();//判断是否是接口类 
boolean isEnum = class1.isEnum();//判断是否是枚举类 
boolean isAnonymousClass = class1.isAnonymousClass();//判断是否是匿名内部类 
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);//判断是否被某个注解类修饰 
String className = class1.getName();//获取class名字 包含包名路径 
Package aPackage = class1.getPackage();//获取class的包信息 
String simpleName = class1.getSimpleName();//获取class类名 
int modifiers = class1.getModifiers();//获取class访问权限 
Class<?>[] declaredClasses = class1.getDeclaredClasses();//内部类 
Class<?> declaringClass = class1.getDeclaringClass();//外部类
ClassLoader ClassLoader = class1.getClassLoader() 返回类加载器

getSuperclass():获取某类所有的父类  
getInterfaces():获取某类所有实现的接口

3.动态代理

代理的操作是通过java.lang.reflect.Proxy 类中实现的,通过Proxy的newProxyInstance()方法可以创建一个代理对象,如下:







请到「今天看啥」查看全文