反射

来源:互联网 发布:微信扫淘宝二维码 编辑:程序博客网 时间:2024/06/05 15:29

反射

可以通过反射创建一个class的对象,并调用该类的结构。

 

调用方法:

1.        创建类对应的class类

Class clazz =Person.Class;

 

2.        创建clazz对应的运行时类Person对象

Person p = (Person)clazz.newInstance();

 

3.        获得指定的属性:

a)       获得public属性

Field f1 = clazz.getField(“name”);

f1.set(p,”Liuhua”);

b)       获得非Public属性(本身的所有属性)

f2 = clazz.getDeclareedField(“age”);

f2.setAccessable(true);

f2.set(p,20);

 

4.        获得指定方法:

Method  m = clazz.getMethod(“show” ,参数1.class, 参数2.class);

m.invoke(对象,参数1,参数2);

 

过程

1.        我们创建一个类,通过javac.classs生成对应的.class文件。

2.        之后,我们用java.exe加载(JVM加载器完成)

3.        此.class文件加载入内存之后,就是一个运行时类,存放在缓存区,那么该运行时类本身就是一个class实例。

4.        每一个运行时类只加载一次。

5.        有了class实例之后,我们可以运行如下操作:

a)       创建运行时类对象

b)       获取对应的时类的完整结构(属性、方法、构造器、内部类、父类、所在包、异常、注解)

c)        调用对应运行时类,指定的结构(属性、方法、构造器)

6.        反射的应用:动态代理

 

创建class实例(三种)

调用运行时类本身.class属性

Class clazz = Person.class;

 

System.out.println(clazz.getName());

调用运行时类的对象获取

Person p = new  Person();

Class clazz = p.getClass();

 

通过class的静态方法获取(给定类位置,创建不同类的对象)

String className  = “com.atguigu.java.Person”;

Class clazz = Class.forName(className);

 

(通过className动态地获得不同对象的class对象。)

 

(了解)通过类的加载器

ClassLoader classLoader  =this.getClass().getClassLoader();

Class clazz = classLoader.loadCl ass(className);


将类装载进内存:

1.        引导加载器:负责核心库加载(无法直接获取)

2.        扩展类加载器:负责制定目录下

3.        系统加载器:制定目录下类与jar包装入工作(常见)

 

创建对象:newInstance

创建运行时类的对象

Person p =(person)clazz.newInstance();

该方法要求:该类有足够权限的空参数构造函数,实际上它调用的就是空参的构造器(写类尽量有空参的构造函数)。(需要强转)

 

获取属性的相关信息:Field

Field f = clazz.getField(“Name”);

1.        获取每个属性修饰符:

Int I = f.getModifiers();

2.        获取属性类型

Class type = f.getType();

 

3.        获取属性名

String str = f.getName();

 

获取方法的相关信息:Method

Method m = clazz.getMethod(“show”);

 

1.        获取方法注解:

Annotation[]  ann = m.getAnnotations();

2.        获取权限修饰符

Int I = m.getModifiers();

3.        获取方法名

String str = m.getName();

4.        获取返回类型

Class returnType = m.getReturnType();

5.        获取形参表

Class[] params  = m.getParameters();

6.        获取异常类型

Class[] exps = m.getException();

 

获取构造器相关信息:Constructor

         Constructor  con = clazz.getConstructor(参数类型.class);

 Constructor<T>

getConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

 

1.        获取带泛型的父类

Type  type1 =clazz.getGenericSuperClass();

2.        获取运行时类的父类

Class superclass = clazz.getSuperClass();

3.        获取父类的泛型

Type type = clazz.getGenericSuperClass();

ParameterizedType  param = (Parameterized) type;

Type[] ars = Param.getActualTypeArguments();

4.        获取实现接口

Class[] interface =calzz.getInterfaces();

5.        获取所在包

Package pack = class.getPackge();

 

通过反射调用类中指定的方法和属性

创建对象

1.        创建运行时类的对象

Person p =(person)clazz.newInstance();

该方法要求:该类有足够权限的空参数构造函数。(需要强转)

属性:

1.        获取指定的属性 name

Field name = clazz.getFild(“name”);

2.        将运行时类指定的属性赋值

Name.set(p ,”jerry”);

若为私有属性则需要:name.setAccessible(true);

 

获取私有属性:

方法:

创建并调用方法:

Method m1 = clazz.getMethod(“show”);//( “方法名”,”参数.class”, “参数.class”)

Object returnVal  = m1.invoke(p); // 这里的返回值即show方法的返回值

 

构造器:

Constructor cons = clazz.getConstructor(String.class , int.class);

Person p = (person)cons.newInstance(“lilei”,10);

 

动态代理:

代理:在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

静态代理:

代理和目标类在编译时便确定下来,无法更改,且一个代理类只能为一个接口服务。(因此会有很多代理类)


动态代理:

客户端通过代理来调用其他对象方法,并在程序运行之时根据需要动态创建目标类的代理对象。而程序是否执行,何时执行都由代理类决定。

应用场景:假设有一组对象都实现同一个接口,实现同样的方法,但这组对象中有一部分对象需要有单独的方法,传统的笨办法是在每一个应用端都加上这个单独的方法,但是代码重用性低,耦合性高。

 

举例



1.Interface InvocationHandler

  该接口中仅定义了一个方法:

  Object invoke(Objectproxy, Method method, Object[] args) 

  在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组(无参时设置为null)。

  这个抽象方法在代理类中动态实现。

 2.Proxy

  该类即为动态代理类,作用类似于上文例子中的ProxySubject,其中主要包含如下内容:

  protected Proxy(InvocationHandler h): 构造函数,用于给内部的invocation handler赋值。

  static Class<?>getProxyClass(ClassLoader loader, Class<?>... interfaces) : loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

  static ObjectnewProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)  :返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在Subject接口中声明过的方法)。

 

Class类:

他的对象相当于一个指向运行时类的指针。运行时类的所有东西他都可以调用。

常用方法

 T

newInstance()
          创建此 Class 对象所表示的类的一个新实例。(实际上是调用了该类的空参的构造函数)

 Field

getField(String name)
     
     返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

 Field[]

getFields()
          返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

 String

getName()
          以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

 Method

getMethod(String name,Class<?>... parameterTypes)
          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

 Method[]

getMethods()
          返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

 ClassLoader

getClassLoader()
          返回该类的类加载器。

 Field[]

getDeclaredFields()
          返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

 Method[]

getDeclaredMethods()
          返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

 String

getName()
          以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

 

getMethods()  VS getDeclareMethods()

getMethods:获取本身及其父类的public方法

getDeclareMethods: 获取本身申明的所有方法

 

Field类:

常用方法:

 String

getName()
          返回此 Field 对象表示的字段的名称。

 void

set(Object obj,Object value)
          
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

 Class<?>

getType()
          
返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

 

 

Method类:

常用方法

 String

getName()
          以 String 形式返回此 Method 对象表示的方法名称。

 Object

invoke(Object obj,Object... args)
          
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

 Class<?>

getReturnType()
          
返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。

 int

getModifiers()
          
以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。

 Class<?>[]

getParameterTypes()
          
按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。

 


 



0 0