• 反射




    1. 反射


    定义:程序在运行状态中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性

    加载流程:假设我们写了一个User类,这个User类加载进内存jvm会为这种类创建唯一的对应的Class类实例,注意这里的Class是一个类型,所有User类都共享同一个对应的Class类,这个Class类包含包名,类名,属性,方法等种种信息



    2.Class类

    获取Class有三种方法

    Class cls = User.class;				//通过类名.class
    
    Class cls = user.getClass();		//通过实例.getClass()
    
    Class cls = Class.forName("User");	//通过Class.forName("全限定类名")
    
    • Class实例是唯一的存在,所以上面获取的Class都是同一个。但这注意 instance of 匹配的是本类及其子类,而Class只匹配本类,不包括子类

    Class常用方法

    方法 解释
    newInstance() 创建由此类对象表示的类的新实例
    forName(String className) 返回与给定字符串名称的类或接口相关联的类对象
    getClassLoader() 返回类的类加载器
    getPackage() 获取此类的包
    getResourceAsStream(String name) 查找具有给定名称的资源(返回类型为InputStream)
    getDeclaredField(Srting name) 反映此表示的类或接口的指定已声明字段类对象
    getDeclaredMethod(String name, Class<?>... p) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象
    getDeclaredConstructor(Class<?>... p) 返回Constructor对象
    • Class.newInstance()只能调用public的无参数构造方法


    3. Field类

    获取字段的方法

    方法名 解释
    getField(String name) 根据字段名获取某个public的field(包括父类)
    getDeclaredField(String name) 根据字段名获取当前类的某个field(不包括父类)
    getFields() 获取所有public的field,返回数组(包括父类)
    getDeclaredFields() 获取当前类的所有field,返回数组(不包括父类)
    • 其中,没有Declared的能获取父类,本类public的field,而有Declared的只能访问本类的所有field

    字段常用方法

    方法 解释
    get(Object obj) 返回该所表示的字段的值Field ,指定的对象上
    set(Object obj, Object value) 将指定对象参数上的此 Field对象表示的字段设置为指定的新值
    getName() 返回由此Field对象表示的字段的名称
    getType() 返回一个 类对象标识了此表示的字段的声明类型 Field对象
    getModifiers() 返回由该 Field对象表示的字段的Java语言修饰符,作为整数

    操作(这里准备了UserExtends类)

    public class UserExtends {
    	
    	private int id = 1;
    	public String email;
    	
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    }
    

    具体操作

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    	
    	Class cls = UserExtends.class;
    	
    	//可以获取字段
    	System.out.println(cls.getDeclaredField("id"));
    	
    	System.out.println("----------------------------------");
    	
    	//可以获取字段的名字,类型,修饰符
    	Field f = cls.getDeclaredField("id");
    	System.out.println(f.getName());
    	System.out.println(f.getType());
    	int m = f.getModifiers();
    	System.out.println(Modifier.isPrivate(m)); //Modifiers是一个类,不同数值代表不同修饰符
    	
    	System.out.println("-------------------------------------");
    	
    	//获取私有字段的值,需要改变一些方法 1. 字段改为public 2.用f.setAccessible(true);
    	//SecurityManager,可以防止private属性访问,所以不用说设置private包装那有什么用了
    	f.setAccessible(true);
    	
    	UserExtends ue = new UserExtends();
    	ue.setId(2);
    	
    	//获取参数对象的字段值
    	Object value = f.get(ue);
    	System.out.println(value);
    	
    	//修改参数对象的字段值
    	f.set(ue, 3);
    	System.out.println(ue.getId());
    }
    

    输出

    private int reflectionfield.UserExtends.id
    ----------------------------------
    id
    int
    true
    -------------------------------------
    2
    3
    


    4. Method

    获取方法的方法

    方法 解释
    getMethod(name, Class...) 获取某个public的Method(包括父类)
    getDeclaredMethod(name, Class...) 获取当前类的某个Method(不包括父类)
    getMethods() 获取所有public的Method(包括父类)
    getDeclaredMethods() 获取当前类的所有Method(不包括父类)

    常用方法

    方法 解释
    getName() 返回方法名称
    getReturnType() 返回方法返回值类型
    getParameterTypes() 返回方法的参数类型
    getModifiers() 返回方法的修饰符,返回一个整形
    invoke(Object obj, Object... args) 在具有指定参数的 方法对象上调用此 方法对象表示的底层方法

    操作(准备了PersonExtends类,里面有两个方法)

    public class PersonExtends extends Person{
    	
    	public int getScore(String type) {
            return 99;
        }
        private int getGrade(int year) {
            return 1;
        }
    }
    
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    	
        //获取类类型
    	Class cls = PersonExtends.class;
    	
    	//获取方法,第一个参数为方法名,第二个为参数类型的类类型
    	System.out.println(cls.getDeclaredMethod("getGrade", int.class));
    	
    	//方法的基本信息
    	Method md = cls.getDeclaredMethod("getGrade", int.class);	
    	md.getName();
    	md.getReturnType();
    	md.getParameters();  //返回的是Class数组
    	md.getModifiers();
    	
    	//invoke第一个参数是实例对象,对二个填写参数,就是正常调用时方法的参数
        PersonExtends ps = new PersonExtends();
    	System.out.println( md.invoke(ps,123) );
    	
    	// 静态方法,第一个参数对象就写null
    	Method med = Integer.class.getMethod("parseInt", String.class);
    	System.out.println( med.invoke(null, "123"));
    	
    	//本类的私有方法
    	//m.setAccessible(true);
    	//任然遵循多态,反射父类方法,方法传入子类对象,调用的是子类方法
    }
    
    private int reflectionmethod.PersonExtends.getGrade(int)
    1
    123
    
    • 方法支持多态,反射父类方法,方法传入子类对象,调用的是子类方法


    5. Constructor

    获取构造方法也是那四种,就不写了

    操作(准备了User类,里面含有无参及有参构造函数)

    public class User {
    	
    	public int id = 1;
    	public String name = "Howl";
    	
    	public User(){
    	}
    	
    	public User(int id, String name) {
    		this.id = id;
    		this.name = name;
    	}
    	
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
    	
    	//Class的newInstance只支持public的无参构造函数
    	User user = User.class.newInstance();
    	System.out.println(user.getId());
    	System.out.println(user.getName());
    	
    	//与Method不同,这里的Constructor直接返回一个实例对象
        //参数直接填写参数的类类型,实现重载
    	Constructor  cst =  User.class.getConstructor(int.class,String.class);
    	User user1 = (User) cst.newInstance(2,"Howlet");
    	System.out.println(user1.getId());
    	System.out.println(user1.getName());
    }
    
    1
    Howl
    2
    Howlet
    
    • 构造函数不支持多态,只能调用本类的构造函数


    6. 反射实现动态代理

    在编译时期不写接口的实现类,反而在运行时期创建接口的实例,这就叫做动态代理

    interface类型的变量总是通过向上转型并指向某个实例,在反射中有体现,比如有个接口叫User,某个实现了接口的类叫做UserImp,那么他们转型可以这样写

    User user = new UserImp();
    


    具体还可以了解代理模式,请戳这里 代理模式



  • 相关阅读:
    Android Library projetcts cannot be exported.
    技术阅读记录(一)
    ASP.NET MVC Model绑定(五)
    Linux 高速操作IOport
    This version of the rendering library is more recent than your version of IntelliJ IDEA.
    WPF使用RoutedCommand自己定义命令
    AutoLayout具体解释+手把手实战
    JNI之——Can&#39;t load IA 32-bit .dll on a AMD 64-bit platform错误的解决
    9.Nexus私服安装配置
    Alcatraz:管理Xcode插件
  • 原文地址:https://www.cnblogs.com/Howlet/p/12095514.html
Copyright © 2020-2023  润新知