java复习-2(总结自廖雪峰)

反射相关:

  • Java反射机制是在运行状态中
  • 对于任意一个类,都能知道这个类的所以属性和方法;
  • 对于任何一个对象,都能够调用它的任何一个方法和属性;
  • 这样动态获取新的以及动态调用对象方法的功能就叫做反射。
  • 反射的基础是Class(java.lang.Class)类。

(1)、java代码在计算机里的三个时期

      class文件其实是字节码文件,也可认为是二进制文件。

      class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。注意:这里的Class类型是一个名叫Class的class。它长这样:

public final class Class { 
    private Class() {} ... //getField、getConstructor等方法皆在此处定义 
}

      三种时期都可以抽离出在某个类的Class(java.lang.Class)对象,Class对象会将java的一个类对象的内容概括为三个对象,包含所有成员变量的Field[]对象,包含所有构造函数的Constructor[]对象,包含所有成员方法的Method[]对象。

      由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。

      这种通过Class实例获取class信息的方法称为反射(Reflection)。

  • 源码阶段使用Class.forName("全包名")的方法加载,即要有src下的路径和类名,适合配置文件使用,因为这种方式是靠字符串加载类对象的。
  • Class类对象阶段使用类名.class的方法加载,多用于参数传递。
  • 运行阶段使用对象名.getClass()加载进去,适用于对象已经建立的。

   (2)设置 Class cls为从student类中抽取的Class对象。

      cls有常用的几种方法,有cls.getName()获取类名等。

      1. 针对成员变量的有(以下四种方法返回field或field[]的类型):
     

field:getField(String name) //获取类型为public名字为name的成员变量 
field[]:getFields() //获取所有类型为public的成员变量。
field:getDeclaredField(String name) //获取名字为name的成员变量,类型不限 
field[]:getDeclaredFields() //获取所有的成员变量,只要声明过的,类型不限

      对于field对象常用的有set和get方法,
     

get(Object obj) 
//该方法返回类型Object对象,实际为field所保存的成员变量的类型,因此可向下转型。
//obj为student实例化出来的对象。返回值为obj对象上字段field所表示的值。 

set(Object obj,Object value) 
//该方法返回类型为void对象。obj为student实例化出来的对象。
//value为将在obj对象的 Field 字段上所设置的新值。

      2. 针对构造方法的有(以下四种方法返回Constructor或Constructor<?>[]的类型):
     

Constructor:getConstructor(Class<?>... parameterTypes) 
//获取类型为public,参数为Class<?>... parameterTypes的构造方法,
//Class<?>... parameterTypes取值String.class、Int.class这样的类型,
//具体参数看实际构造方法。

Constructor<?>[]:getConstructors()
//获取所有类型为public的构造方法。

Constructor:getDeclaredConstructor(Class<?>... parameterTypes)
//获取参数为Class<?>... parameterTypes的构造方法,
//Class<?>... parameterTypes取值String.class、Int.class这样的类型,
//具体参数看实际构造方法。类型不限。

Constructor<?>[]:getDeclaredConstructors()
//获取所有构造方/法。类型不限。

      对于Constructor对象常用的有newInstance方法

newInstance(Object... initargs)
//该方法返回自类型为student,如果该构造函数有参数要在后面加上实参去实例化对象。

cls.newInstance()
//该方法更简单直接,但只适用于无参的构造函数实例化

      3. 针对成员方法的有(以下四种方法返回Method或Method[]的类型):

Method:getMethod(String name,Class<?>... parameterTypes)
//获取类型为public,名字为name,参数为Class<?>... parameterTypes的成员方法方法。
//Class<?>... parameterTypes取值如在获取构造函数所述。

Method[]:getMethods()
//获取获取类型为public的所有成员方法。

Method:getDeclaredMethod(String name,Class<?>... parameterTypes)
//获取名字为name,参数为Class<?>... parameterTypes的成员方法方法。
//Class<?>... parameterTypes取值如在获取构造函数所述。类型不限。

Method[]:getDeclaredMethods()
//获取所有成员方法,类型不限。

      对于Method对象常用的有invoke方法

invoke(Object obj,Object... args)
//该方法返回类型Object对象,
//实际为Method所代表的成员方法所返回的类型,因此可向下转型。
//obj为student实例化出来的对象。Object... args为传入方法的实参。
//返回值为obj执行Method后的结果,如果原方法返回值为void则返回null。

      注:AccessibleObject 类是Field、Constructor和Method都基类,因此这三者都可以通过 名字.setAccessible(true)的形式取消Java 语言访问控制检查,从而导致反射机制具有了能够更改私有变量的能力。请注意使用。有些安全框架会禁用setAccessible(true)方法,因此它也不是什么时候都能起作用的。

      4. 获取父类及接口

Class cla = Integer.class;
//获取父类的Class对象

Class n = cla.getSuperclass(); 
//获取所有继承接口的Class对象

Class[] is = s.getInterfaces();

Object n = Integer.valueOf(123);
boolean isDouble = n instanceof Double; // false
//instanceof可用来判断两个对象间是否具有继承关系

动态代理相关:

//动态代理的底层实现依靠反射
public class Main {
    public static void main(String[] args) {
        //代理的具体内容
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}
//动态代理实际上是JDK在运行期根据代理内容动态创建class字节码并加载的过程。
//从而产生接口的实例
interface Hello {
    void morning(String name);
}

      把上面的动态代理改写为静态实现类大概长这样(这个类由JDK帮我们编写):

public class HelloDynamicProxy implements Hello {
    InvocationHandler handler;
    public HelloDynamicProxy(InvocationHandler handler) {
        this.handler = handler;
    }
    public void morning(String name) {
        handler.invoke(
           this,
           Hello.class.getMethod("morning"),
           new Object[] { name });
    }
}

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值