java——反射

反射

1.什么时候会发生类初始化

  1. 类的主动引用(一定会发生类的初始化)

    • 当虚拟机启动,先初始化main方法所在的类;
    • new一个类的对象;
    • 调用类的静态成员(除了final常量)和静态方法;
    • 使用java.lang.reflect包的方法对类进行反射调用;
    • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类;(包括含有default方法的接口)
    • 直接使用java虚拟机运行某一个主类,程序会初始化该主类
  2. 类的被动调用(不会发生类的初始化)

    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化,但是会导致父类的初始化
    • 通过数组定义类引用,不会触发此类的初始化;
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了);
    • Class.forName(String s,false,ClassLoader cl),可以只生成Class对象而不进行初始化

2.定义

反射:将类的各个组成部分封装为其他对象,这就是反射机制

好处:

  1. 可以在程序运行过程中,操作这些对象。
  2. 可以解耦,提高程序的可扩展性。

3.获取Class对象的方式:

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象

多用于配置文件,将类名定义在配置文件中。读取文件,加载类

  1. 类名.class:通过类名的属性class获取

多用于参数的传递

  1. 对象.getClass():getClass()方法在Object类中定义着。

多用于对象的获取字节码的方式

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

4.Class对象功能:

  1. 获取成员方法们:
   Method[] getMethods();//获得当前类以及super类的public方法

   Method getMethod(String name,<?>... parameterTypes)  
   
   Method[] getDeclaredMethods()  //获取当前类声明的所有方法,不包括父类中的

   Method getDeclaredMethod(String name,<?>... parameterTypes)  
  1. 获取全类名
    String getName()
  2. 获取成员变量们
  • Field[] getFields() :获取当前类以及super的所有public修饰的成员变量

  • Field getField(String name) 获取指定名称的public修饰的成员变量

  • Field[] getDeclaredFields() 获取当前类所有的成员变量,不考虑修饰符

  • Field getDeclaredField(String name)

  1. 获取构造方法们
  • Constructor<?>[] getConstructors() 获取类的public类型的构造方法
  • Constructor< T > getConstructor(类<?>… parameterTypes)
  • Constructor< T > getDeclaredConstructor(类<?>… parameterTypes)
  • Constructor< ? >[] getDeclaredConstructors()
  • Constructor<?>[]newInstance() 通过类的不带参数的构造方法创建这个类的一个对象

5. Field:成员变量

  1. 设置值:void set(Object obj, Object value)

  2. 获取值:get(Object obj)

    1. 忽略访问权限修饰符的安全检查:setAccessible(true):暴力反射

6.Constructor:构造方法

  • 创建对象:T newInstance(Object… initargs)

  • 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

Class.newInstance();
Class.getConstructor(new Class[]{}).newInstance(new Object[]{});

7.Method:方法对象

  1. 执行方法:Object invoke(Object obj, Object… args)

  2. 获取方法名称:String getName

8.使用方法

链接

9.动态代理类

概念
  1. 属于java.lang.reflect包,主要涉及到两个类:
    (1) Interface InvocationHandler:接口中仅定义一个方法
public object invoke(Object obj,Method method, Object[] args)//第一个参数obj指代理类,method是被代理的方法对象,args为该方法的参数数组

(2) Proxy:该类即为动态代理类,其中主要包含以下内容

protected Proxy(InvocationHandler h)//构造函数,定义调用逻辑 
static Class getProxyClass (ClassLoader loader, Class[] interfaces)//获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。 
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)//返回代理类的一个实例,返回后的代理对象可以当作被代理的类对象使用(可使用被代理类的在Subject接口中声明过的方法)
步骤
  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口
  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理对象
  4. 通过代理对象调用方法
实例
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), 
				        new Class[] { Foo.class });
//创建动态代理类的实例
Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });


//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//直接创建动态代理类的实例
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
				        new Class[] { Foo.class },
			                        handler);

特点

由Proxy类的静态方法创建的动态代理类具有以下特点:

  • 动态代理类是public、final和非抽象类型的;
  • 动态代理类继承了java.lang.reflect.Proxy类;
  • 动态代理类的名字以“$Proxy”开头;
  • 动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;
  • Proxy 类的isProxyClass(Class<?> cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;
  • 动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。

10.题目

  1. 以下说法正确的是:(ACD)

A. 动态代理类借助实现的InvocationHandler进行函数调用

B. 动态代理类对象必须与代理类具有完全相同的接口列表

C. 动态代理类只可以代理接口

D. java.lang.reflect包中的Proxy类提供了创建动态代理类的方法

  1. 下列说法正确的是(C)
    A. 泛型只在编译时有效,无法在运行期获取类的泛型声明
    B. 反射机制可以获取泛型对象的具体泛型类型
    C. 可以通过反射机制绕过编译器对泛型类型的检查

特别注意: 泛型只在编译的时候用于类型的检查,java程序加载进内存后,泛型就不存在了,而jdk的反射是模拟java运行时的环境读取和调用程序,因此,不能获得泛型的实际类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值