一、注解
1.什么是注解
注解:又称java标注,单独说注解他的作用就是注释。只有当注解和反射、插桩等技术一起使用才会有意义。
2.什么是元注解
元注解:简单的理解就是注解的注解。(给注解添加的注解叫做元注解)
@Retention(RetentionPolicy.RUNTIME) //保留到什么时候,代码中?编译期?运行期?
@Target({ElementType.TYPE})//test注解的作用目标。(用在哪里)
public @interface test {
}
复制代码
其中@Retention和@Target就是元注解。
3.常用的元注解介绍
@Retention:标志当前注解、保留到什么时候。
1.SOURCE:编译器运行后会丢掉改注解,及编译期注解就不存在了。
2.CLASS:编译期注解存在,但是在运行期注解就没了。(在android中编译成.dex后也会消失)
3.RUNTIME:在任何时期注解都存在。
复制代码
@Target:注解作用在哪些地方
1.TYPE:类、接口、枚举
2.FIELD:字段生声明,包括枚举常量
3.METHOD:方法。
4.PARAMETER:形参上。
5.CONSTRUCTOR:构造函数上。
6.LOCAL_VARIABLE:局部变量
7.ANNOTATION_TYPE:注解上。
8.PACKAGE:包上。
9.TYPE_PARAMETER:类型参数声明。1.8
10.TYPE_USE:类型使用。
复制代码
4.默认注解
Java中的注解默认实现Annotation接口。
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
复制代码
二、注解的使用场景
1.源码级别的例子lint检查@IntDef注解
该注解用于替换枚举,因枚举的每个枚举参数都会生成一个对象占用空间大,所以通过@IntDef来进行替换。该注解只是用于lint检查,报的错误只是提醒,不会影响程序的编译和运行。
@Retention(SOURCE)//源码级别的注解
@Target({ANNOTATION_TYPE})//注解的注解。
public @interface IntDef {
int[] value() default {};
boolean flag() default false;
boolean open() default false;
}
复制代码
2.源码级别注解,APT(annotation processor tools)注解处理器
APT技术是来源于javac命令,在编译成字节码的时候,添加的插件,该插件可以生成自动生成java类。(APT不会打包进apk,只会参与编译。)
3. 编辑期的注解。字节码插桩技术(字节码增强技术)
字节码插桩技术:简单的说就是在.class中写代码。(可以跳过语法检查,在apt中生成的类,无法掉用,只能用字节码插桩跳过语法检查,把代码加入到字节码里)
4.编译期的注解。AOP切面编程。(注解和字节码插桩技术)
通过注解,有注解的加入代码,没注解的不加入。(需要登陆的代码,都要加入登陆的操作,不需要的,则不加入。)
5.运行时的注解。反射技术
面试题1:final修饰的基本类型,能通过反射修改内容么?
答案:final修饰的非基本类型是可以修改的。基本类型因为在编译期就已经确定了值是多少,因为编译期的优化导致final类型的变量都直接修改成了常量值。所以导致反射的时候修改不了结果。如果想要修改需要在构造方法里去初始化fianl的值。
面试题2:反射的速度为什么慢?(影响其实很小)
答案:1)在调用invoke方法的时候需要装箱和拆箱的操作:基本数据类型,先装箱,再转换成object的数组。最后掉用的时候有需要拆箱的操作。
2)反射需要按名字检索类和方法:遍历类去寻找。
3)检查方法:检查方法的权限,检查方法的参数,包括形参和实参。
4)编译器无法对动态掉用的代码做优化,比如内联:反射涉及到动态解析的类型,影响内敛判断且无法进行JIT.
三、动态代理
1.动态代理的使用方法
public static void main(String[] args){
jiatianlong hao = new jiatianlong();
//返回一个新对象。及动态代理生成的一个新类。
student student = (com.lzl.proces.proxy.student) Proxy.newProxyInstance(
hao.getClass().getClassLoader(),//类加载器
new Class[]{student.class},//接口数组
new ProxyInvokeHandler(hao)//代理处理程序(可以理解成回调)。
);
student.play();
}
复制代码
public class ProxyInvokeHandler implements InvocationHandler {
private Object realObject;
public ProxyInvokeHandler(Object realObject){
this.realObject = realObject;
}
/**
*
* @param o 代理对象
* @param method 调用方法
* @param objects 方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(realObject,objects);
}
}
复制代码
2.动态代理的原理
字节码生成技术:会帮你生成一个字节码(class对象),这个字节码是一个继承了proxy实现了相应接口的类。