反射
类的加载
- 当我们的程序在运行后,第一次使用某个类的时候,会将此类的class文件读取到内存,并将此类的所有信息存储到一个Class对象中
类的加载时机
- 创建类的实例。
- 类的静态变量,或者为静态变量赋值。
- 类的静态方法。
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。
- 初始化某个类的子类对象。
- 直接使用java.exe命令来运行某个主类。
以上六种情况的任何一种,都可以导致JVM将一个类加载到方法区。
public class Test1 { public static void main(String[] args) throws Exception{ //1. 创建类的实例。 new Person(); //2. 类的静态变量,或者为静态变量赋值。 System.out.println(Person.num); //3. 类的静态方法。 Person.method(); //4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。 Class<?> c1 = Class.forName("com.itheima.demo2_类加载的时机.Person"); //5. 初始化某个类的子类对象。 new Student(); //6. 直接使用java.exe命令来运行某个主类。 // 以上六种情况的任何一种,都可以导致JVM将一个类加载到方法区。 } }
类加载器
类加载器:是负责将磁盘上的某个class文件读取到内存并生成Class的对象。
- Java中有三种类加载器,它们分别用于加载不同种类的class:
- 启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>\bin目录下的class,例如:rt.jar。
- 扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>\lib\ext目录下的class。
- 应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器。
package com.itheima.demo6_类加载器; /** * @Date: 2020/9/24 9:31 */ public class Test { public static void main(String[] args) { // 如何获取类加载器: 使用类的class对象调用getClassLoader()方法 // 获取Person类的类加载器 ClassLoader c1 = Person.class.getClassLoader(); System.out.println(c1);// ClassLoaders$AppClassLoader // 获取String类的类加载器 ClassLoader c2 = String.class.getClassLoader(); System.out.println(c2);// null //API中说明:一些实现可能使用null来表示引导类加载器。 如果此类由引导类加载器加载,则此方法将在此类实现中返回null } }
获取Class对象
- 通过类名.class获得
- 通过对象名.getClass()方法获得
- 通过Class类的静态方法获得: static Class forName(“类全名”)
- 示例代码
public class Test { public static void main(String[] args) throws Exception{ //Class.forName("全限定类名") Class<?> c1 = Class.forName("com.itheima.demo5_获取类的字节码对象.Person"); //类名.class Class<Person> c2 = Person.class; //对象名.getClass() Person p = new Person(); Class<? extends Person> c3 = p.getClass(); System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c1 == c2);// true System.out.println(c2 == c3);// true } } // 注意: 一个类只有一个Class对象,所以无论通过哪种方式获取的Class对象都是同一个对象
Class类常用方法
String getSimpleName(); 获得类名字符串:类名 String getName(); 获得类全名:包名+类名 T newInstance() ; 创建Class对象关联类的对象---相当于调用该类的空参构造方法
- 示例代码
public class Test { public static void main(String[] args) throws Exception{ // 获取Person类的Class对象 Class<Person> c = Person.class; // String getSimpleName(); 获得类名字符串:类名 System.out.println("类名: "+c.getSimpleName());// 类名: Person // String getName(); 获得类全名:包名+类名 // 类全名: com.itheima.demo6_Class类的常用方法.Person System.out.println("类全名: "+c.getName()); // T newInstance() ; 创建Class对象关联类的对象---相当于调用该类的空参构造方法 Person p = c.newInstance();// 相当于Person p = new Person(); } }
反射之操作构造方法
Constructor类概述 * 类中的每一个构造方法都是一个Constructor类的对象
通过反射获取类的构造方法
Class类的方法 1. Constructor getConstructor(Class... parameterTypes) * 根据参数类型获得对应的Constructor对象。 * 只能获得public修饰的构造方法 2. Constructor getDeclaredConstructor(Class... parameterTypes)---推荐 * 根据参数类型获得对应的Constructor对象 * 可以是public、protected、(默认)、private修饰符的构造方法。 3. Constructor[] getConstructors() 获得类中的所有构造方法对象,只能获得public的 4. Constructor[] getDeclaredConstructors()---推荐 获得类中的所有构造方法对象 可以是public、protected、(默认)、private修饰符的构造方法。
public class Test { public static void main(String[] args) throws Exception{ // 获取Person类的Class对象 Class<Person> c = Person.class; // 获得指定的构造方法: // 获取第一个构造方法对象 Constructor<Person> con1 = c.getDeclaredConstructor(); System.out.println("con1:"+con1); // 获取第二个构造方法对象 Constructor<Person> con2 = c.getDeclaredConstructor(String.class,int.class); System.out.println("con2:"+con2); // 获取第三个构造方法对象 Constructor<Person> con3 = c.getDeclaredConstructor(int.class); System.out.println("con3:"+con3); // 获取第四个构造方法对象 Constructor<Person> con4 = c.getDeclaredConstructor(String.class); System.out.println("con4:"+con4); // 获取所有的构造方法 Constructor<?>[] arr = c.getDeclaredConstructors(); for (Constructor<?> con : arr) { System.out.println(con); } } }
通过反射执行构造方法
Constructor对象常用方法 1. T newInstance(Object... initargs) 根据指定的参数创建对象 参数:被执行的构造方法需要的实际参数 2. void setAccessible(true) 设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消
示例代码
public class Person { String name; int age; // 构造方法 public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public Person(int age) { this.age = age; } private Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class Test { public static void main(String[] args) throws Exception { // 获取Person类的Class对象 Class<Person> c = Person.class; // 获得指定的构造方法: // 获取第一个构造方法对象 Constructor<Person> con1 = c.getDeclaredConstructor(); System.out.println("con1:" + con1); // 获取第二个构造方法对象 Constructor<Person> con2 = c.getDeclaredConstructor(String.class, int.class); System.out.println("con2:" + con2); // 获取第三个构造方法对象 Constructor<Person> con3 = c.getDeclaredConstructor(int.class); System.out.println("con3:" + con3); // 获取第四个构造方法对象 Constructor<Person> con4 = c.getDeclaredConstructor(String.class); System.out.println("con4:" + con4); // 获取所有的构造方法 Constructor<?>[] arr = c.getDeclaredConstructors(); for (Constructor<?> con : arr) { System.out.println(con); } System.out.println("========"); // 通过反射执行con1表示的构造方法 Person p1 = con1.newInstance(); System.out.println("p1:" + p1); // 通过反射执行con2表示的构造方法 Person p2 = con2.newInstance("张三", 18); System.out.println("p2:" + p2); // 通过反射执行con3表示的构造方法 Person p3 = con3.newInstance(19); System.out.println("p3:" + p3); // 通过反射执行con4表示的构造方法 con4.setAccessible(true);// 取消权限检查 Person p4 = con4.newInstance("王五"); System.out.println("p4:" + p4); } }
动态代理
代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者, 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)
静态代理:
public interface FindHappy { void happy(); } public class JinLian implements FindHappy{ public void happy(){ System.out.println("金莲正在happy..."); } } public class WangPo implements FindHappy { JinLian jl; public WangPo(JinLian jl) { this.jl = jl; } @Override public void happy() { System.out.println("王婆以做头发的名义,帮2人开好房间..."); jl.happy(); System.out.println("王婆打扫战场..."); } } public class Test { public static void main(String[] args) { JinLian jl = new JinLian(); //jl.happy(); WangPo wp = new WangPo(jl); wp.happy(); } }
动态代理介绍
- 概述 : 动态代理就是在程序运行期间,直接通过反射生成一个代理对象,代理对象所属的类是不需要存在的
- 动态代理的获取: jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
动态代理相关api介绍
Java.lang.reflect.Proxy类可以直接生成一个代理对象 - Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象 - 参数1:ClassLoader loader 被代理对象的类加载器 - 参数2:Class<?>[] interfaces 被代理对象的要实现的接口 - 参数3:InvocationHandler h (接口)执行处理类 - 返回值: 代理对象 - 前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法 - InvocationHandler中的Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行 - 参数1:代理对象(慎用) - 参数2:当前执行的方法 - 参数3:当前执行的方法运行时传递过来的参数 - 返回值:当前方法执行的返回值
评论 (0)