zoukankan      html  css  js  c++  java
  • 0033 Java学习笔记-反射-初步1

    先看看通过反射能干嘛

    • 示例:修改对象的private实例变量
    package testpack;
    import java.lang.reflect.Field;
    public class Test1 {  
        public static void main(String[] args)throws Exception{ 
        	Person per=new Person("Java",21);
        	System.out.println("现在的per对象是:"+per);   //[name= Java , age= 21 ]
        	
        	Class<Person> perClazz=Person.class;           //获取Person类的Class对象
        	
        	Field fName=perClazz.getDeclaredField("name"); //获取Person类的名为“name”的变量,即使是private修饰
        	fName.setAccessible(true);                     //取消该变量的访问权限检查
        	fName.set(per, "C++");                         //将per对象的name变量改为“C++”
        	
        	Field fAge=perClazz.getDeclaredField("age");
        	fAge.setAccessible(true);
        	fAge.set(per, 33);                             //将per对象的age变量改为“33”
        	
        	System.out.println("private的实例变量被修改了,还是那个per对象:"+per); //[name= C++ , age= 33 ]
        }
    }
    class Person{
    	private int age;
    	private String name;
    	public Person(String n,int a){
    		name=n;
    		age=a;
    	}
    	public String toString(){
    		return "[name= "+name+" , age= "+age+" ]";
    	}
    }
    
    • 上面的示例中,虽然age和name被private修饰,但还是被修改了,那这岂不是很不安全,违背了封装的初衷?我也不知道

    java.lang.class

    • 有一个类很特别,它是所有类的类,它就是java.lang.class
    • 要使用一个类的时候,类加载器找到并加载这个类,同时返回其Class对象;也就是说只要一个类被加载了,那么就一定存在它的Class对象
    • 如何获得一个类的Class对象?以String类为例
      • Class.forName("java.lang.String"):用Class类的静态方法forName("包名+类名")来获取
      • String.class:通过调用一个类的class属性来获取
        • 一般用这种方式
        • 代码更安全。程序在编译阶段就可以检查要访问的Class对象是否存在。?不懂
        • 程序性能更好。因为无须调用方法。
      • String的实例.getClass():通过Object类的一个实例方法getClass()方法获取
    • 获取一个类的Class对象后,就可以调用其方法获得该对象和该类的真实信息了

    Class主要方法

    • 构造器:以下用“para”代表Class<?>...parameterTypes,这是个数可变的形参列表
      • Constructor getConstructor(para):返回该Class对象对应类的、带指定形参的public构造器
      • Constructor<?>[] getConstructors():返回对应类的所有public构造器
      • Constructor getDeclaredConstructor(para):返回对应类的、带指定形参列表的构造器,不论是什么访问权限
      • Constructor<?>[] getDeclaredConstructors():返回对应类的所有构造器,不论访问权限
    • 方法:
      • Method getMethod(String name,para):返回对应类的、指定方法名、指定形参列表的public方法
      • Method[] getMethods():返回指定类的所有public方法
      • Method getDeclaredMethod(String name,para):返回对应类的、指定方法名、指定形参列表的方法,不论访问权限
      • Method[] getDeclaredMethods():返回对应类的所有方法,不论访问权限
    • 成员变量
      • Field getField(String name):返回对应类的、指定名称的public成员变量
      • Filed[] getFields():返回对应类的所有public成员变量
      • Field getDeclaredField(String name):返回对应类的、指定名称的成员变量,不论访问权限
      • Field[] getDeclaredFields():返回对应类的所有成员变量,不论访问权限
    • 注解
      • <A extends Annotation> A getAnnotation(Class<A>AnnotationClass):获取对应类的指定的注解,不存在则返回null
      • <A extends Annotation> A getDeclaredAnnotation(Class<A>AnnotationClass):获取直接修饰该对应类的、指定的注解,不存在则返回null
      • Annotation[] getAnnotations():返回对应类上的所有注解
      • Annotation[] getDeclaredAnnotations():返回直接修饰该对应类的所有注解
      • <A extends Annotation> A[] getAnnotationsByType(Class<A>AnnotationClass):针对重复注解功能,返回修饰该对应类的、指定类型的多个注解
      • <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A>AnnotationClass):针对重复注解功能,获取直接修饰对应类的、指定类型的注解
    • 内部类
      • Class<?>[] getDeclaredClasses():返回对应类里包含所有内部类
    • 外部类:
      • Class<?> getDeclaringClass():返回对应类的所在的外部类
    • 接口:
      • Class<?> getInterfaces():返回对应类所实现的所有接口
    • 父类:
      • Class<?super T> getSuperclass():返回对应来的父类的Class对象
    • 修饰符:
      • int getModifiers():返回对应类或接口的所有修饰符对应的常量,应使用Modifier工具类的方法解码,才能获得真实的修饰符
    • 所在包:
      • Package getPackage():获取对应类所在的包
    • 类名:
      • String getName():返回对应类的名称,全局限定名(即包含包名)
      • String getSimpleName():返回对应类的名称,不包含包名的类名
    • is方法
      • boolean isAnnotation:是不是注解类型
      • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):对应类是否使用了Annotation修饰
      • boolean isAnonymousClass():对应类是否是一个匿名类
      • boolean isArray():对应类是否是一个数组
      • boolean isEnum():对应类是否是一个枚举
      • boolean isInterface():对应类是否是一个接口
      • boolean isInstance(Object obj):判断该obj是不是对应类的实例,可以完全替代instanceof
    • 相关方法示例:以Strin类为例
    package testpack;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test1  {  
        public static void main(String[] args)throws Exception{ 
        	Class clazz=String.class;
        	
        	System.out.println("---------------------------------下面是String的成员变量部分---------------------------------");
        	System.out.println("-----------所有的public成员变量-----------");
        	Field[] pfs=clazz.getFields();
        	for (Field f:pfs) {
        		System.out.println(f);
        	}
        	System.out.println("-----------所有成员变量-----------");
        	Field[] fs=clazz.getDeclaredFields();
        	for (Field f:fs) {
        		System.out.println(f);
        	}
        	
        	System.out.println("---------------------------------下面是String的构造器部分---------------------------------");
        	System.out.println("String的无参构造:"+clazz.getConstructor(null));
        	System.out.println("String以byte[]为参数的构造器:"+clazz.getConstructor(byte[].class));
        	System.out.println("String以StringBuffer为参数的构造器:"+clazz.getConstructor(StringBuffer.class));
        	System.out.println("---------------所有构造器-----------------");
        	Constructor[] cs=clazz.getDeclaredConstructors();
        	for(Constructor c:cs){
        		System.out.println(c);
        	}
        	
        	System.out.println("---------------------------------下面是String的方法部分---------------------------------");
        	System.out.println("String的名为intern的无参方法:"+clazz.getMethod("intern",null));
        	System.out.println("String的名为valueOf的参数为int的方法:"+clazz.getMethod("valueOf",int.class));
        	System.out.println("--------------所有方法--------------------");
        	Method[] ms=clazz.getDeclaredMethods();
        	for (Method m:ms) {
        		System.out.println(m);
        	}
        	System.out.println();
        	
        	System.out.println("---------------------------------下面是String的注解部分---------------------------------");
        	System.out.println("---------下面是String的所有注解---------------");
        	Annotation[] as=clazz.getAnnotations();
        	for (Annotation a:as) {
        		System.out.println(a);                      //没有输出:因为String类没有注解(但String类内部的一些元素有注解)
        	}
        	System.out.println("---------------------------------下面是String的所有内部类---------------------------------");
        	Class[] css=clazz.getDeclaredClasses();
        	for (Class c:css) {
        		System.out.println(c);
        	}
        	System.out.println("---------------------------------下面是String实现的所有接口---------------------------------");
        	Class[] is=clazz.getInterfaces();
        	for (Class i:is) {
        		System.out.println(i);
        	}
        	System.out.println("---------------------------------其他---------------------------------");
        	System.out.println("String的直接父类:"+clazz.getSuperclass());
        	System.out.println("String的修饰符:"+clazz.getModifiers());
        	System.out.println("String所在的包:"+clazz.getPackage());
        	System.out.println("String的全局限定名:"+clazz.getName());
        	System.out.println("String的类名:"+clazz.getSimpleName());
        }
    }
    
    

    关于参数的反射:since1.8

    • 构造方法和方法中包含形参列表,Java1.8增加了Parameter类来描述参数
    • 上面Class对象关于构造器和方法的返回值分别是:Constructor和Method,这两个类是Executable类的子类
    • Executable的主要方法有:
      • boolean isVarArgs():是否包含可变数量的形参
      • int getModifiers():获取修饰符
      • int getParameterCount():获取形参数量
      • Parameter[] getParameters():获取所有形参
    • Parameter的主要方法
      • int getModifiers():获取形参的修饰符
      • String getName():获取形参名
      • Type getParameterizedType():获取带泛型的形参类型
      • Class<?> getType():获取形参类型
      • boolean isNamePresent():所在类的class文件中是否包含了形参名信息;
        • 一般情况下,编译的时候都不包含形参名,除非加上“-parameters”选项
      • boolean isVarArgs():该参数是否为个数可变的形参
    • 见示例:
    package testpack;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Parameter;
    
    public class Test1  {  
        public static void main(String[] args)throws Exception{ 
        	Class clazz=String.class;
        	Constructor c=clazz.getConstructor(byte[].class,int.class,int.class);
        	System.out.println("该构造器的形参个数:"+c.getParameterCount());
        	Parameter[] ps=c.getParameters();
        	for (Parameter p:ps) {
        		System.out.println("该参数是:"+p);
        		System.out.println("该参数的修饰符:"+p.getModifiers());
        		System.out.println("该参数的形参名:"+p.getName());
        		System.out.println("形参类型:"+p.getType());
        		System.out.println("是否有形参名信息:"+p.isNamePresent());
        		System.out.println("是否是个数可变的形参:"+p.isVarArgs());
        		System.out.println("--------------------------");
        	}
        }
    }
    
  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/sonng/p/6116693.html
Copyright © 2011-2022 走看看