您的位置:首页 > 编程语言 > Java开发

Java基础进阶_day18_(类加载器,反射,动态代理)

2017-05-16 12:39 441 查看

Java基础进阶_day18_(类加载器,反射,动态代理)

1. 类加载器

/*
* 类加载器:
*  类的加载:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化.
*      1.加载
*          就是指将class文件读入内存,并为之创建一个Class对象。 任何类被使用时系统都会建立一个Class对象。
*      2.连接
*          A:验证  是否有正确的内部结构,并和其他类协调一致;
*          B:准备  负责为类的静态成员分配内存,并设置默认初始化值;
*          C:解析  将类的二进制数据中的符号引用替换为直接引用.
*      3.初始化
*          就是我们以前讲过的初始化步骤.
*  类的初始化时机:
*      1.创建类的实例;
*      2.访问类的静态变量,或者为静态变量赋值;
*      3.调用类的静态方法;
*      4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象;
*      5.初始化某个类的子类;
*      6.直接使用java.exe命令来运行某个主类.
*
*  类加载器:负责将.class文件加载到内在中,并为之生成对应的Class对象,获取到Class对象后结合反射进行使用.
*  类加载器分为三种:
*      Bootstrap ClassLoader:根类加载器
*          也称为引导类加载器,负责Java核心类的加载;
*          比如System,String等,在JDK中JRE的lib目录下rt.jar文件中;
*      Extension ClassLoader:扩展类加载器
*          负责JRE的扩展目录中jar包的加载.
*          在JDK中JRE的lib目录下ext目录.
*      Sysetm ClassLoader:系统类加载器
*          负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径.
*/
public class My_ClassLoader_Demo01 {
public static void main(String[] args) {
}
}


2.反射

2.1 反射概述

/*
* 反射:
*      JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
*      对于任意一个对象,都能够调用它的任意一个方法和属性;
*      这种动态获取的信息以及动态调用对象的方法的功能.
* 反射使用的前提是先获取类的字节码对象Class,使用Class中方法进行类的解析.
*
* 获取Class对象的三种方式:常用第三种
*      A:通过类.class获取
*      B:通过对象.getClass()方法获取
*      C:通过Class的forName(类的完全限定名)获取
*/
public class My_Reflect_Demo01 {
public static void main(String[] args) throws Exception {
// 类的Class对象的获取
// A:通过类.class获取
Class c1 = My_Reflect_Demo01.class;
System.out.println(c1);
// B:通过对象.getclass()方法获取
My_Reflect_Demo01 mrd = new My_Reflect_Demo01();
Class c2 = mrd.getClass();
System.out.println(c2);
// C:通过Class的forName(类的全名)获取
Class c3 = Class.forName("com.itheima.reflect01.My_Reflect_Demo01");
System.out.println(c3);
}
}


2.2 反射获取构造方法

package com.itheima.reflect02;
/*
* 自定义类,反射测试用
*/
public class Person {
// 私有的属性
private String name;
// 默认的属性
int age;
// 无参构造方法
public Person() {
}
// 有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 私有的构造方法
private Person(int age) {
this.age = age;
}
// 公共的成员方法
public void show(String s) {
System.out.println("show:" + s);
}
// 私有的成员方法
private String show2(String s) {
return "私有的成员方法";
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

import java.lang.reflect.Constructor;
/*
* 反射获取构造方法:
*  Class类的方法:获取构造方法的参数是对应数据类型的.class对象
*      public Constructor[] getConstructors():获取所有的公共的构造方法;
*      public Constructor[] getDeclaredConstructors():获取所有的构造方法,包括私有的构造方法;
*      public Constructor getConstructor(Class... parameterTypes):获取指定参数个数和类型的公共的构造方法,没有参数时获取空参构造;
*      public Constructor getDeclaredConstructor(Class... parameterTypes):获取指定参数个数和类型的所有的构造方法,没有参数时获取空参构造;
*  创建类对象:Class类的方法
*      public T newInstance(Object ... initargs):创建类的对象,参数为空时代表无参
*          当获取的是私有的构造方法时,创建对象前先调用setAccessible(boolean flag),将访问权限设为true.
*/
public class My_Reflect_Demo01 {
public static void main(String[] args) throws Exception {
// 获取类的Class对象
Class c1 = Class.forName("com.itheima.reflect02.Person");
// 获取所有公共的构造方法
Constructor[] cs = c1.getConstructors();
for (int i = 0; i < cs.length; i++) {
System.out.println(cs[i]);
}
// 获取所有的构造方法
Constructor[] cns = c1.getDeclaredConstructors();
for (Constructor cn : cns) {
System.out.println(cn);
}
// 获取单个构造方法,并创建对象
Constructor cns1 = c1.getConstructor();
Object obj = cns1.newInstance();
// 获取私有的构造方法,并创建对象
Constructor cns2 = c1.getDeclaredConstructor(int.class);
cns2.setAccessible(true);
Object obj2 = cns2.newInstance(23);
System.out.println(obj2); // Person [name=null, age=23]
}
}


2.3 反射获取成员属性

package com.itheima.reflect02;
/*
* 自定义类,反射测试用
*/
public class Person {
// 私有的属性
private String name;
// 默认的属性
int age;
// 无参构造方法
public Person() {
}
// 有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 私有的构造方法
private Person(int age) {
this.age = age;
}
// 公共的成员方法
public void show(String s) {
System.out.println("show:" + s);
}
// 私有的成员方法
private String show2(String s) {
return "私有的成员方法";
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
* 反射获取类的成员属性:Class类的功能
*      public Field[] getFields():获取类的公共的成员属性;
*      public Field[] getDeclaredFields():获取类的所有的成员属性;
*      public Field getField(String name):获取类的指定字段名的公共的成员属性;
*      public Field getDeclaredField(String name):获取类的指定字段名的成员属性(可以是私有的属性).
*  设置属性的值:Field类的功能
*      public void set(Object obj,Object value):设置指定obj对象变量的此field表示的字段值设为value;
*
*/
public class My_Reflect_Demo02 {
public static void main(String[] args) throws Exception {
// 获取类的Class对象
Class c1 = Class.forName("com.itheima.reflect02.Person");
// 获取构造方法,并创建对象
Constructor cns = c1.getDeclaredConstructor(int.class);
cns.setAccessible(true);
Object obj = cns.newInstance(34);
// 获取公共的成员属性
Field[] fields = c1.getFields();
// 获取所有的成员属性
Field[] fields2 = c1.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
// 获取制定字段名的属性,并设置新的值
Field field = c1.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "java");
System.out.println(obj);
}
}


2.4 反射获取成员方法

package com.itheima.reflect02;
/*
* 自定义类,反射测试用
*/
public class Person {
// 私有的属性
private String name;
// 默认的属性
int age;
// 无参构造方法
public Person() {
}
// 有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 私有的构造方法
private Person(int age) {
this.age = age;
}
// 公共的成员方法
public void show(String s) {
System.out.println("show:" + s);
}
// 私有的成员方法
private String show2(String s) {
return "私有的成员方法";
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
* 反射获取类的成员方法:Class类的方法
*      public Method[] getMethods():获取所有的成员方法,包括由该类或接口声明的以及从超类和超接口继承的那些的类或接口的公共成员方法;
*      public Method getMethod(String name,Class... parameterTypes):获取该类指定名称及指定参数个数及类型的所有公共的方法,包括该类之上的所有类及接口的公共方法。
*      public Method[] getDeclaredMethods():获取本类所有的成员方法;
*      public Method getDeclaredMethod(String name,Class... parameterTypes):获取本类指定名称和指定参数个数及参数类型方法.
*  调用方法:Method类的方法
*      public Object invoke(Object obj,Object... args):调用obj对象变量的该方法,参数是Object类型的数组,返回值是object类型.
*/
public class My_Reflect_Demo03 {
public static void main(String[] args) throws Exception {
// 获取类的Class对象
Class c1 = Class.forName("com.itheima.reflect02.Person");
// 获取构造方法,创建对象
Constructor cns = c1.getDeclaredConstructor();
Object obj = cns.newInstance();
// 获取所有的成员方法
Method[] methods = c1.getMethods();
// Method[] methods = c1.getDeclaredMethods();
// 获取指定参数的成员方法
Method method = c1.getDeclaredMethod("show2", String.class);
method.setAccessible(true);
Object result = method.invoke(obj, "你好");
System.out.println(result); // 私有的成员方法
}
}


2.5 反射案例1

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* ArrayList<Integer>的一个对象,在集合中存储字符串数据
*/
public class My_Reflect_Test01 {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(89);
// 获取Class对象
Class c1 = list.getClass();
// 获取add方法,该方法的默认参数是E泛型,则是object的之类,将方法的参数设为object类型
Method method = c1.getDeclaredMethod("add", Object.class);
// 向集合中添加字符串数据
method.invoke(list, "java");
// 输出结果
System.out.println(list);
}
}


2.6 反射案例2

import java.lang.reflect.Field;
/*
* 写一个方法public void setProperty(Object obj, String propertyName, Object value){},
* 此方法可将obj对象中名为propertyName的属性的值设置为value。
*/
public class My_Reflect_Test02 {
public static void main(String[] args) throws Exception {
Person p = new Person();
MyTool mt = new MyTool();
mt.setProperty(p, "name", "张三");
System.out.println(p);
}
}
// 自定义类
class MyTool {
// 定义方法
public void setProperty(Object obj, String propertyName, Object value) throws Exception {
// 获取对象的class对象
Class c = obj.getClass();
// 获取属性值的字段
Field field = c.getDeclaredField(propertyName);
// 将属性的访问权限设为true
field.setAccessible(true);
// 将obj对象的某个字段值设为value
field.set(obj, value);
}
}


3. 动态代理

/*
* 动态代理:
*      代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象.
*      动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,
*          动态代理其实就是通过反射来生成一个代理.
*  在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,
*      通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理.
*  Proxy类中的方法创建动态代理类对象
*      public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
*      最终会调用InvocationHandler的方法
*  nvocationHandler
*      Object invoke(Object proxy,Method method,Object[] args)
*
* Proxy类中创建动态代理对象的方法的三个参数:
*      ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载;
*      Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,
*          如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了;
*      InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上;;
*  每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,
*      当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用.
*
* InvocationHandler接口中invoke方法的三个参数:
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*
* Proxy.newProxyInstance:
*      创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,
*      也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,
*      以$开头,proxy为中,最后一个数字表示对象的标号,
*      System.out.println(u.getClass().getName()).
*/
public class My_Proxy_Demo01 {
public static void main(String[] args) {
}
}


案例代码:

// 学生操作的dao类
public interface StudentDao {
// 登陆功能
public abstract void login();
// 注册功能
public abstract void regist();
}
// 学生操作dao的实现类
public class StudentDaoImpl implements StudentDao {
@Override
public void login() {
System.out.println("登录功能");
}
@Override
public void regist() {
System.out.println("注册功能");
}
}
// 定义实现InvocationHandler的类,用于执行被代理对象的方法
public class MyInvocationHandler implements InvocationHandler {
private Object target; // 目标对象
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("权限校验");
Object result = method.invoke(target, args);
System.out.println("日志记录");
return result; // 返回的是代理对象
}
}
// 测试类
public class Test {
public static void main(String[] args) {
// 为用户登陆的和方法添加权限校验和日志记录功能
StudentDao sd = new StudentDaoImpl();
MyInvocationHandler handler2 = new MyInvocationHandler(sd);
StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()
.getClassLoader(), sd.getClass().getInterfaces(), handler2);
proxy2.login(); // 输出权限校验--登陆功能--日志记录
proxy2.regist(); // 输出权限校验--注册功能--日志记录
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐