注解
元注解:注解上的注解;
@Target(ElementType.TYPE)
//target就是元注解,无target时,note_1注解可以放到任何地方,类,方法,成员属性均可以
//target可以规定注解可以放在什么地方,可以反正Type(类),Field(字段),Method(方法),Constructor(构造方法)等等,可以多个叠加,如@Target(ElementType.TYPE,ElementType.Field)
@Retention(RetentionPolicy.SOURCE)// 标记的注解仅保留在源级别,并被编译器忽略
public @interface note_1 {
String value() default "note_1";
}
要注意若注解只有value,使用的时候,无需加上value=" ";其他的(包括多个属性)均需要列出完整的赋值代码;
@Node_1(id="OnCreate")
@target(如上)
@Retention(保留注解到什么时候) 保留级别
A)SOURCE:保留到源码阶段,经过javac编译就会被抹除掉;
B)CLASS:保留到class文件;但在JVM加载的时候会忽略掉;
C)RUNTIME:标记的注解由JVM保留,在运行环境中可以使用,获取;(通过反射技术获取)
SOURCE<CLASS<RUNTIME
不同级别注解的使用场景:
**SOURCE级别:**即源码级别,运用于APT(Annotation Processor Tools)技术(注解处理器);在编译期获取注解于注解声明的类包括类中的所有成员的信息,一般用于生成额外的辅助类;
注解处理器的运行:
运行在编译阶段;注解处理程序是由javac调用的
javac将.java文件转换成.class文件时会采集到所有的注解信息,再将其包装成Element节点,交给注解处理程序
.java -> javac ->.class
通过@Intdef元注解进行语法检查
@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface IntDef {
/** Defines the allowed constants for this element */
int[] value() default {};
/** Defines whether the constants can be used as a flag, or just as an enum (the default) */
boolean flag() default false;
/**
* Whether any other values are allowed. Normally this is
* not the case, but this allows you to specify a set of
* expected constants, which helps code completion in the IDE
* and documentation generation and so on, but without
* flagging compilation warnings if other values are specified.
*/
boolean open() default false;
}
CLASS:即字节码级别,运用于字节码增强技术(如;热修复技术)【可以通过ASM生成】
字节码增强:也就是在字节码中写代码,即在.class文件中写。(要了解.class的格式 数据按照特定的方式记录与排列)
将注解保留到class文件,便于进行选择性进行代码注入,比如对于加了注解的那些方法进行代码注入;
javap:用于反编译;
RUNTIME:即运行级别;运用于反射技术;通过在运行时,只知道某个类的信息,不需要有这个类的引用;反射是基于class的
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Node_1 {
// @IdRes int value() default 10;
@IdRes int value() default 10;//加@idres注解的原因在于明白value对应的是资源的id
int size() default 20;
}
public class InjectUtils {
public static void injectView(Activity activity){
Class<? extends Activity> cls = activity.getClass();//获取字节码码文件
// try {
// cls.getMethod("showDrawingToolsMenu");//获取指定方法
// cls.getField("drawingView");//可以获取自己+父类的成员(不包括private,只能是public)
Field[] drawingViewFields = cls.getDeclaredFields();//只能获取自己的成员(不包括父类,但可以获取全部作用域的)
for(Field field:drawingViewFields){
if(field.isAnnotationPresent(Node_1.class)) {//判断该属性是否加了注解
Node_1 injectview=field.getAnnotation(Node_1.class);//获取注解
int size =injectview.size();
// 获取注解中设置的id
int id =injectview.value();
View view =activity.findViewById(id);
//反射设置属性的值:
field.setAccessible(true);//设置访问权限,使得可以操作private属性
try {
field.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// } catch (NoSuchFieldException e) {
// e.printStackTrace();
// }
// Method[] clsMethods = cls.getMethods();//获取所有方法;
}
}
json是一种数据类型,gson是操作json的一种数据框架;
Java序列化与反序列化的含义
序列化指的是:将Java对象转为字节流
反序列指的是:将字节流转换为java 对象
序列化和反序列化不仅可以用于网络传输和本地保存,还可以用于Java对象的深度复制。通过将对象序列化为字节流,然后再将字节流反序列化为一个新的对象,就可以实现对象的深度复制,从而避免了手动复制对象的繁琐过程。
浅拷贝与深拷贝
浅拷贝:【拷贝方法;重写clone()方法;】
a)对于基本数据类型的成员变量(存放在栈里),浅拷贝会直接进行值传递;即将属性值复制一份给新的对象;简单来说,这是两份数据,对某一对象的属性值进行修改,不会影响另一个对象拷贝的值;
b)对于引用数据类型的成员变量(如:类,接口,数组等,存放在堆里),浅拷贝会进行引用传递,也就是将成员变量的引用地址复制给新的对象,那么对于一份数据的修改,另一份拷贝的数据也会被修改;
clone方法:
在类内重写clone方法
class Fruit implements Cloneable{
public Object clone() {
Object obj=null; //调用Object类的clone方法,返回一个Object实例
try {
obj= super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
Fruit apple_2=(Fruit)apple1.clone();
深拷贝:
无论是基本数据类型还是引用数据类型都是重新创建,因此修改原来那份的内容,都不会影响到拷贝后的那份;
缺点很明显:较于浅拷贝速度较慢并且花销较大。
通常通过对象序列化实现深拷贝;
对于要进行深拷贝的类及其中设计的其他类的对象均继承Serializable接口,
class Fruit implements Serializable{
//...
}
//使用
Fruit apple1=new Fruit(...);
//通过序列化方法实现深拷贝
bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(apple1);
oos.flush();
ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Fruit apple2=(Fruit)ois.readObject();