引导类加载器: java.lang.String -> rt.jar JDK基础类 Math、Date、System 扩展类加载器: JDK自带扩展类(现在不存在了)
应用类加载器: ClassPath 自定义类、第三方jar包 ClassPath——类路径——就是src下面的 com.zzxx.utils.DruidUtils -> 自定义类 org.apache.commons.beanutils.BeanUtils -> 自定义类 应用类加载器是可以获得到的,另外两种都是null
public class Demo01ClassLoader { public static void main(String[] args) { // 应用类加载器, 只有一个 ClassLoader loader = Demo01ClassLoader.class.getClassLoader(); ClassLoader loader2 = User.class.getClassLoader(); System.out.println(loader == loader2);//true // 引导类加载器, 和 扩展类加载器 代码获取不到 ClassLoader loader1 = String.class.getClassLoader(); System.out.println(loader1);//null }面试题:自己定义一个java.lang.String类, 能不能使用? String类在使用的时候都要先加载,引导类加载器会找到一个java.lang.String类,加载完之后就不管后面了,自己定义的类就没有机会被加载,也就咩有机会被使用
操作类的字节码对象 Class对象
.getConstructor() newInstance()
创建提供的对象
// 2.获得类的构造方法 Class cls = String.class; try { // 获得一个参数是String类型的构造器 new String("str"); Constructor constructor = cls.getConstructor(String.class); // 通过构造器对象来创建string对象,"hello" 就是调用这个构造方法传递的实际参数 String ob = (String) constructor.newInstance("hello"); System.out.println(ob);//hello } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }创建自己写的对象
// 通过反射创建user对象 // 1.获得user的字节码对象 Class cl = User.class; // 2.获得user的构造方法 Constructor con1 = cl.getConstructor(); // 3.创建对象 User u1 = (User) con1.newInstance(); System.out.println(u1); // 成员私有时, 通过反射获得构造方法需要使用 getDeclaredxx Constructor con2 = cl.getDeclaredConstructor(String.class, int.class); // 私有成员可以手动设置可见 con2.setAccessible(true); // 创建对象 User u2 = (User) con2.newInstance("lucy", 18); System.out.println(u2); // cl.newInstance(); // -- 直接通过无参构造器创建对象.getMethod() 调用方法:method.invoke()
public boolean study(String course) { System.out.println(this.name + "正在学习" + course); return true; } public static void main(String[] args) throws Exception { User user = new User("张三"); // 1.获得user的字节码对象 Class cls = User.class; // 2.获得study这个方法对象,若为私有,则cls.getDeclaredMethod,并设置方法可见 Method method = cls.getMethod("study", String.class); // 2.2设置方法可见 //method.setAccessible(true); // 3.调用方法 boolean b = (Boolean) method.invoke(user, "Java"); System.out.println(b); }通过反射,可以直接调用私有的成员变量 get() set()
User user = new User("张三"); System.out.println(user); // 1.获得user的字节码对象 Class cls = User.class; // 2.获得age属性 Field age = cls.getDeclaredField("age"); age.setAccessible(true); // 3.给user对象的age属性赋值 age.set(user, 18); // 4.获得user对象的age属性 age.get(user); System.out.println(user);@Override: 重写 只能放在方法上, 没有属性 @Deprecated: 过时的 放在属性/方法/类/构造方法/局部变量/方法参数 @SuppressWarnings: 压制警告 放在属性/方法/类/构造方法/局部变量/方法参数 必须要有属性
元注解: 标记注解的注解,规定注解的使用位置 @Target(ElementType.METHOD): 规定注解的使用位置 @Retention(RetentionPolicy.RUNTIME) SOURCE CLASS RUNTIME
注意: 注解的可见范围必须是 运行阶段 RUNTIME
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface MyAnnotation2 { // 属性语法 类型 属性名() int age() ; // 使用注解时属性必须赋值 } @MyAnnotation2(age = 1) public class Demo02 { // @MyAnnotation2(age = 1) public Demo02() { } @MyAnnotation2(age = 2) public void test01() { } } // 解析Demo02上的MyAnnotation2注解 public class Demo03 { public static void main(String[] args) { // 1.获得Demo02对应的字节码对象 Class cls = Demo02.class; // 2.获得Demo02类上的MyAnnotation2注解 MyAnnotation2 annotation = (MyAnnotation2) cls.getAnnotation(MyAnnotation2.class); // 3.获得注解中的属性值 int age = annotation.age(); System.out.println(age); }1.和被装饰者拥有相同的父接口 2.用被装饰对象来构建装饰对象 3.重写要增强的方法
和装饰者模式一样是为了做方法增强, 代理对象和被代理对象拥有相同的父接口,用被代理对象来构建代理对象 但他的代理对象并不是一个真正存在的类,而且和被代理对象没有直接联系
代理对象: 增强后的对象 被代理对象: 原来的对象
实际上作用:提取公共代码 如果一个实现类没有父接口,那么他就不能使用动态代理,就不能使用方法增强
