类加载器
什么是类加载器,作用是什么?
类加载器就加载字节码文件(.class)
类加载器
类加载器的种类
类加载器有三种,不同类加载器加载不同的
图片.png
- BootStrap:引导类加载器:加载都是最基础的文件
- ExtClassLoader:扩展类加载器:加载都是基础的文件
- AppClassLoader:应用类加载器:三方jar包和自己编写java文件
//获得字节码对象
Class<ClassLoaderLesson> lessonClass = ClassLoaderLesson.class;
//获得字节码文件的类加载器
ClassLoader loader = lessonClass.getClassLoader();
//获得classPath下的任何的资源
URL url = loader.getResource("test");
//获得资源文件的路径
String path = url.getPath();
加载顺序是从上到下加载
注解 @xxx
什么是注解,注解作用
-
注解就是符合一定格式的语法 @xxxx
-
注解作用:
- 注释:在阅读程序时清楚----给程序员看的
- 注解:给jvm看的,给机器看的
-
注解在目前而言最主流的应用:代替配置文件
关于配置文件与注解开发的优缺点:
* 注解优点:开发效率高 成本低
* 注解缺点:耦合性大 并且不利于后期维护
jdk5提供的注解
@Override:告知编译器此方法是覆盖父类的
@Deprecated:标注过时
@SuppressWarnings:压制警告 可以放到类上 字段上 属性方法上
不同的注解只能在不同的位置使用(方法上、字段上、类上)
自定义注解
编写一个注解
关键字:@interface
- 注解的属性:
语法:返回值 名称();
注意:如果属性的名字是value,并且注解的属性值有一个 那么在使用注解时可以省略value
图片.png
注解属性类型只能是以下几种
1.基本类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
使用注解
-
在类/方法/字段 上面是@XXX
图片.png
解析使用了注解的类
元注解:代表修饰注解的注解,作用:限制定义的注解的特性
#### @Retention 注解的可见级别
* SOURCE: 注解在源码级别可见
* CLASS:注解在字节码文件级别可见
* RUNTIME:注解在整个运行阶段都可见(整个生命周期)
![范围图示](https://img.haomeiwen.com/i6052465/aea0ec4a839cab39.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### @Target 代表注解修饰的范围:类上使用,方法上使用,字段上使用
* FIELD:字段上可用此注解
* METHOD:方法上可以用此注解
* TYPE:类/接口上可以使用此注解
- 我们看一个api注解的源码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})//代表注解的修饰范围
@Retention(RetentionPolicy.SOURCE)//代表注解的可见级别
public @interface SuppressWarnings {
/**
* The set of warnings that are to be suppressed by the compiler in the
* annotated element. Duplicate names are permitted. The second and
* successive occurrences of a name are ignored. The presence of
* unrecognized warning names is <i>not</i> an error: Compilers must
* ignore any warning names they do not recognize. They are, however,
* free to emit a warning if an annotation contains an unrecognized
* warning name.
*
* <p>Compiler vendors should document the warning names they support in
* conjunction with this annotation type. They are encouraged to cooperate
* to ensure that the same names work across multiple compilers.
*/
String[] value();
}
解析注解
我们可以使用字节码对象来对注解作用的地方进行解析
- 注解
//元注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
String value();
int age() default 20;
}
- 注解作用的地方
public class MyAnnoTest {
@MyAnno("xxx")
public void show() {
System.out.println("show running...");
}
}
- 注解的解析
@SuppressWarnings("all")
public static void main(String[] args) {
//获得注解作用的函数的字节码对象
Class<MyAnnoTest> myAnnoTestClass = MyAnnoTest.class;
try {
Method show = myAnnoTestClass.getMethod("show", null);
//获得show方法上的注解
MyAnno myAnno = show.getAnnotation(MyAnno.class);
System.out.println(myAnno.age());
System.out.println(myAnno.value());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
动态代理
什么是代理(中介)
目标对象/被代理对象
代理对象
执行代理对象方法的对象
- 抽象:调用对象----->代理对象------>目标对象
来个🌰(栗子)
- 接口
package com.probuing.proxy;
public interface TargetInterface {
public void method1();
String method2();
}
- 目标对象 目标对象实现接口
/**
* 目标对象
*/
public class Target implements TargetInterface {
@Override
public void method1() {
System.out.println("method1");
}
@Override
public String method2() {
System.out.println("method2 running");
return "it's method2";
}
}
- 创建调用
@Test
public void test1() {
//获得动态对象——在运行中动态创建代理对象
TargetInterface targetInterface = (TargetInterface) Proxy.newProxyInstance(Target.class.getClassLoader(), new Class[]{TargetInterface.class}, new InvocationHandler() {
/**
* 代表执行代理对象的方法
*
* @param proxy 代理对象的引用
* @param method 代表目标对象的方法的字节码对象
* @param args 代表目标对象的响应的方法的参数
* @return 定义的接口的返回值 最终返回的值会给到代理对象
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("run method before");
// TODO: 2018/4/12 执行目标方法前的逻辑
String invoke = (String) method.invoke(Target.class.newInstance(), null);
// TODO: 2018/4/12 执行目标方法之后的逻辑
System.out.println("run method after");
return invoke;
}
});
//执行目标对象的方法
targetInterface.method1();
String s = targetInterface.method2();
System.out.println(s);
}
动态代理
动态代理:不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时 的内存中动态生成代理对象。------字节码对象级别的代理对象
动态代理的API:
在jdk的API中存在一个Proxy中存在一个生成动态代理的的方法newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
类<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
Proxy.newProxyInstance因为与IllegalArgumentException相同的原因而Proxy.getProxyClass 。
参数
loader - 类加载器来定义代理类
interfaces - 代理类实现的接口列表
h - 调度方法调用的调用处理函数
结果
具有由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例
-
返回值:Object就是代理对象
-
参数:loader:代表与目标对象相同的类加载器-------目标对 象.getClass().getClassLoader()
-
interfaces:代表与目标对象实现的所有的接口字节码对象数组
-
h:具体的代理的操作,InvocationHandler接口
注意:JDK的Proxy方式实现的动态代理 目标对象必须有接口 没有接口不能实现jdk版动态代理
网友评论