zoukankan      html  css  js  c++  java
  • Java之反射

    1. Java Reflection

    Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

    2. Java反射机制提供的功能

    1. 在运行时判断任意一个对象所属的类
    2. 在运行时构造任意一个类的对象
    3. 在运行时判断任意一个类所具有的成员变量和方法
    4. 在运行时调用任意一个对象的成员变量和方法
    5. 生成动态代理

    3. Java反射机制研究及应用

    3.1 反射相关的主要API

    java.lang.Class:代表一个类
    java.lang.reflect.Method:代表类的方法
    java.lang.reflect.Field:代表类的成员变量
    java.lang.reflect.Constructor:代表类的构造方法

    4. Class类

    4.1 Class类的常用方法

    4.2 实例化Class类对象(四种方法)

    前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
    实例:Class clazz = String.class;
    前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
    实例:Class clazz = “www.xyd.com”.getClass();
    前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
    实例:Class clazz = Class.forName(“java.lang.String”);
    其他方式(不做要求)
    ClassLoader cl = this.getClass().getClassLoader();
    Class clazz4 = cl.loadClass(“类的全类名”);

    4.3 代码

    public class Test1 {
    	public static void main(String[] args) {
    		Person p = new Person();
    		
    		//若已知具体的类,通过类的class属性获取
    		Class s0 = Person.class;
    		
    		//已知某个类的实例,调用该实例的getClass()方法获取Class对象
    		Class s1 = p.getClass();
    		System.out.println(s1.getCanonicalName());
    		
    		//通过Class的静态方法forName(String className)来获取一个类的Class实例
    		//forName(String className)方法中的参数是你要获取的Class实例的类的全路径(包名.类名)
    		try {
    			Class s2 = Class.forName("reflectionBag.Person");//这个是获取Class实例的常用方式
    		
    		}catch(ClassNotFoundException e){
    			e.printStackTrace();
    		}
    	}
    
    }
    

    5. 通过反射调用类的完整结构

    使用反射可以取得:

    5.1 实现的全部接口

    public Class<?>[] getInterfaces()
    确定此对象所表示的类或接口实现的接口。

    5.2 所继承的父类

    public Class<? Super T> getSuperclass()
    返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。

    5.3 全部的构造器

    public Constructor<T>[] getConstructors()
    返回此 Class 对象所表示的类的所有public构造方法。
    public Constructor<T>[] getDeclaredConstructors()
    返回此 Class 对象表示的类声明的所有构造方法。

    5.4 Constructor类中

    取得修饰符: public int getModifiers();
    取得方法名称: public String getName();
    取得参数的类型:public Class<?>[] getParameterTypes();

    5.5 代码

    public class Test2 {
    	public static void main(String[] args) {
    //		Student s = new Student();
    		try {
    			Class clazz = Class.forName("reflectionBag.Student");
    			Class superClazz = clazz.getSuperclass();//获取父类
    			System.out.println("父类:"+superClazz.getName());
    			
    			//获取所有实现接口名称
    			Class[] interClazz = clazz.getInterfaces();
    			for(Class c: interClazz) {
    				System.out.println("接口:"+c.getName());
    			}
    			System.out.println("==========");
    			//获取共有的构造方法
    			Constructor[] cons = clazz.getConstructors();
    			for(Constructor c:cons) {
    				System.out.println("公有的构造方法名:"+c.getName());
    				//getModifiers取得方法的修饰符,返回数字1代表public
    				System.out.println("公有的构造方法名:"+c.getName()+"方法修饰符:"+c.getModifiers());
    				//getParameterTypes()取得参数类型,需要一个数组接收
    				Class[] partypes = c.getParameterTypes();
    				for(Class p:partypes) {
    					System.out.println("公有的构造方法名:"+c.getName()+"方法修饰符:"+c.getModifiers()+"参数类型"+p.getName());
    				}
    				
    		
    			}
    			System.out.println("============================");
    			//获取所有的构造方法,包括共有、私有,返回数字2代表private
    			Constructor[] cons1 = clazz.getDeclaredConstructors();
    			for(Constructor c:cons1) {
    				System.out.println("所有的构造方法名:"+c.getName());
    				//getModifiers取得方法的修饰符,返回数组1代表public
    				System.out.println("所有的构造方法名:"+c.getName()+"方法修饰符:"+c.getModifiers());
    				//getParameterTypes()取得参数类型,需要一个数组接收
    				Class[] partypes = c.getParameterTypes();
    				for(Class p:partypes) {
    					System.out.println("所有的构造方法名:"+c.getName()+"方法修饰符:"+c.getModifiers()+"参数类型"+p.getName());
    				}
    			}
    			
    		}catch(ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    	
    }
    

    6. 通过反射调用类中的指定方法

    格式:
    Object invoke(Object obj, Object … args)
    说明:

    1. Object 对应原方法的返回值,若原方法无返回值,此时返回null
    2. 若原方法若为静态方法,此时形参Object obj可为null
    3. 若原方法形参列表为空,则Object[] args为null
    4. 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

    6.1 调用共有的无参构造

    Object obj = clazz.newInstance();//clazz.newInstance()实例化对象,相当于调用类的无参构造
    Student s = (Student)obj;//Object对象强转成Student对象
    

    6.2 调用共有的有参构造

    Constructor c = clazz.getConstructor(String.class);//指定获取一个参数为string的构造函数
    Student stu = (Student)c.newInstance("第一中学");//c.newInstance("")实例化对象,并强转为Student对象
    

    6.3 调用私有的构造方法

    Constructor c1 = clazz.getDeclaredConstructor(String.class,int.class);//指定获取参数为string和int的私有构造
    c1.setAccessible(true);//解除私有的封装,下面就可以对这个私有方法强制调用
    Student stu1 = (Student)c1.newInstance("第一中学",20);
    

    6.4 获取类的所有方法

    Method[] ms = clazz.getMethods();//获取共有的方法
    //Method[] ms = clazz.getDeclaredMethods();//获取所有方法,包括共有和私有
    			for(Method m:ms) {
    				System.out.println("方法名:"+m.getName());//获取方法的方法名
    				System.out.println("修饰符::"+m.getModifiers());//获取方法的修饰符
    				System.out.println("返回值类型:"+m.getReturnType());//获取方法的返回值类型
    				Class [] ps = m.getParameterTypes();//获取方法的参数类型,为数组,通过for each循环获取
    				if(ps!=null && ps.length>0) {
    					for(Class p:ps) {
    						System.out.println(p.getName());
    					}
    				}
    

    6.5 调用类的指定的共有方法

    Constructor c3 = clazz.getConstructor();
    Object obj = c3.newInstance();
    Method m1 = clazz.getMethod("work", int.class);//调用共有方法
    m1.invoke(obj,11);
    

    6.6 调用类的指定的私有方法

    Method m2 = clazz.getDeclaredMethod("test", String.class);//调用私有方法
    m2.setAccessible(true);//解除私有的封装,下面就可以对这个私有方法强制调用
    m2.invoke(obj, "李四");
    

    6.7 调用类的重载方法

    Method m3 = clazz.getMethod("work", int.class, String.class);
    m3.invoke(obj, 20,"李四");
    

    6.8 调用有返回值无参数的方法

    Method m4 = clazz.getMethod("getSchool");
    String school = (String)m4.invoke(obj);
    System.out.println(school);
    

    7. 通过反射调用类中的指定属性

    7.1 调用指定共有属性

    //通过反射创建一个实例
    Constructor con = clazz.getConstructor();//创建一个的构造方法
    Student stu = (Student)con.newInstance();//创建一个实例
    
    Field f = clazz.getField("school");//获取名称为school的属性
    f.set(stu, "第一中国");//设置school属性值
    String school1 = (String)f.get(stu);//获取stu对象的属性值
    System.out.println(school1);
    

    7.2 调用指定私有属性

    Field f1 = clazz.getDeclaredField("age");
    f1.setAccessible(true);//解除私有的封装,下面就可以强制的调用这个属性
    f1.set(stu, 20);//set()传入参数值
    int age = (int) f1.get(stu);//get()获取参数值
    System.out.println(age);
    

    8. 获取类所在的包

    Package p = clazz.getPackage();
    System.out.println(p.getName());
    
  • 相关阅读:
    python每日作业4/21
    socket实现并发之socketserver模块的使用
    python socket粘包问题的解决
    每日作业:4/20
    网络编程基础(socket)
    网络基础之网络协议
    异常处理
    python 作业4/15
    centos7简单安装配置mariadb
    Centos7下Firewalld防火墙配置命令
  • 原文地址:https://www.cnblogs.com/istart/p/12196392.html
Copyright © 2011-2022 走看看