注解Annotation
什么是注解
- 作用
- 对程序做出解释
- 可以被其他程序(比如编译器)读取
- 格式
- 注解是以"@注释名"在代码中存在的,还可以添加一些参数值
- 例如:@SuppressWarnings(value=“unchecked”)
- 在哪里使用
- 附加在package,class,method,field等上面,可以通过反射机制编程实现对这些元数据的访问
内置注解
- @override:重写
- @SuppressWarinings(“”):镇压警告 all 所有,unchecked 未检查 或者加多个值
- @Deprecated:不推荐程序员使用,但可以使用
- @FunctionaInterface:指定接口必须式函数式接口
- @SafeVarargs:一直“堆污染警告”
元注解meta-annotation
-
@Target:注解作用范围
public class ZiDingYi { @MyAnnotation public void test(){ } } @Target(value={ElementType.METHOD,ElementType.ANNOTATION_TYPE}) @interface MyAnnotation{ } @MyAnnotation @interface My{ }
-
@Retention:SOURCE<CLASS<RUNTIME
-
@Documented:包含在javadoc中
-
@Inherited:子类可以继承父类中的注解
自定义注解
-
@interface用来声明一个注解,格式:public @interface 注解名{}
-
其中的每一个方法实际上式声明了一个配置参数,例如ElementType[] value()
-
方法的名称就是参数的名称
-
返回值类型就是参数的类型,只能基本类型,Class,String,enum(枚举)
-
如果只有一个参数成员,一般参数名为value
-
注解元素必须有值,我们定义注解元素时,经常使用空字符串,0为默认
-
public class Demo01 { @MyAnnotation2(name="nihao",schools="憨批") public void test(){} } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ String name() default""; int age() default 0; int id() default -1;//如果默认值为-1,代表不存在 String[] schools() default {"憨批","hape"}; }
反射机制Reflection
反射概述
- Reflection(反射)java动态语言的关键,允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
- Class c=Class.forName(“java.lang.String”)
- 在加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象,这个对象就包含了完整的类的接口信息。
获得反射对象
- 运行时判断任意一个对象所属的类
- —构造任意一个类的对象
- —判断任意一个类具有的成员变量和方法
- —获取泛型信息
- —调用任意一个对象的成员变量和方法
- —处理注解
- 生成动态代理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49nUNfZQ-1606403200880)(C:\Users\wuvcky\AppData\Roaming\Typora\typora-user-images\image-20201126110209809.png)]
-
try { Class c1=Class.forName("user"); System.out.println(c1); } catch (ClassNotFoundException e) { e.printStackTrace(); }
获得class对象
-
Class本身也是一个类,Class对象由系统建立
-
一个加载的类在JVM中只有唯一一个Class实例
-
一个Class对象对应的是一个加载到JVM中的一个.class文件
-
每一个类都会记得自己由哪个Class实例生成
-
通过Class可以完整得到一个类中的所有被加载的结构
-
Class类的常用方法
-
返回指定类名name的Class对象
Class c1=Class.forName("user");
System.out.println(c1);
- 调用缺省构造函数,返回Class对象的一个实例
Class c1=user.class;
Object n=c1.newInstance();
- 返回当前Class对象的父类的Class对象
Class c2=c1.getSuperclass();
- 获取当前Class对象的接口
Class[] c3=c1.getInterfaces();
- 获得该类的类加载器
ClassLoader c4=c1.getClassLoader();
-
Class类的创建方式
- Class clasz=Person.class; 最安全可靠,程序性能高
- Class clasz=person.getClass(); 通过类的实例获得类的Class对象
- 通过Class类的静态方法forName()获取
- Class c1=Class.forName(“path”);
Person person=new Student(); System.out.println("这个人是"+person.name); Class c1=person.getClass(); System.out.println(c1.hashCode()); Class c2=Class.forName("Student"); System.out.println(c2.hashCode()); Class c3=Student.class; System.out.println(c3.hashCode());
三个Class对象会打印出同个hashcode
所有类型的Class对象
-
Class:外部类,成员内部类,静态内部类,局部内部类,匿名内部类 interface:接口 []:数组 enmu:枚举 annotation:注解@interface primitive type:基本数据类型 void
-
Class c1=Object.class; Class c2=Comparable.class;//接口 Class c3=String[].class; Class c4=int[][].class; Class c5=Override.class; Class c6= ElementType.class;//枚举类型 Class c7=Integer.class; Class c8=void.class; Class c9=Class.class;
类的加载过程
-
Java内存分为堆、栈、方法区,方法区是堆里一个特殊的区域
-
在堆里面,存放一些new的对象和数组,堆可以被所有的线程共享,不会存放别的对象引用
-
在栈里面,存放基本变量类型,包含基本类型的具体数值,引用对象的变量(存放这个引用在堆里面的具体地址)
-
在方法区内,可以被所有的线程共享,包含了所有的class和static变量
-
类的加载过程:当程序主动使用某个类时,经过三个步骤
-
类的加载--------------------》类的链接-------------------------》类的初始化
-
(load) (Link) (Initialize)
-
将类的class文件读入内存,并创建一个java.lang.Class对象,由类加载器完成
-
将类的二进制数据合并到JRE中
-
JVM负责类的初始化
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TQ6YiEbL-1606403200882)(C:\Users\wuvcky\Desktop\图片\image-20201126154007138.png)]
什么时候发生类的初始化
-
当虚拟机启动,先初始化main方法所在的类
-
new
-
调用类的静态成员和静态方法
-
反射调用
-
初始化类会先初始化父类
-
当访问一个静态域时,只有真正声明这个域的类才会被初始化
-
通过数组定义类引用,不会触发此类的初始化 Person[] person=new Person[10]
-
引用常量不会触发此类的初始化
类加载器的作用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nZM7qRBB-1606403200883)(C:\Users\wuvcky\AppData\Roaming\Typora\typora-user-images\image-20201126162610386.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1skRs57e-1606403200885)(C:\Users\wuvcky\AppData\Roaming\Typora\typora-user-images\image-20201126162646036.png)]
获取运行时类的对象
- get()
如何使用
-
通过Class对象的newInstance()创建一个对象
类必须有一个无参数的构造器 类的构造器访问权限必须要够
-
通过反射获得构造器,通过构造器创建一个对象
-
Class c1=Class.forName("A"); A a=(A)c1.newInstance(); Constructor cc=c1.getConstructor(int.class); A aa=(A)cc.newInstance(19);
-
通过反射获得方法
-
Method show=c1.getDeclaredMethod("nihao"); show.invoke(a);
-
通过反射获得属性
-
Field ccc=c1.getDeclaredField("m"); ccc.set(a,1000); System.out.println(a.m);
-
Field ccc=c1.getDeclaredField("m"); ccc.setAccessible(true); ccc.set(a,1000); System.out.println(a.getM()); //操作私有属性 setAccessible
-
setAccessible
Method和Field、Constructor对象都有setAccessible方法 启动和禁用访问安全检查的开关 true关闭 可以提高反射的效率
通过反射操作泛型
通过Fan.class.getDecLaredMethod获得方法
通过方法c1.getGenericParameterTypes获得泛型数组
如果是参数化类型 强转成参数化类型再输出
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Fan {
public void fan1(Map<String,user> map, List<String> list, Set<Object> set){
System.out.println("test1");
}
public Map<String,user> nihao(){
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method c1=Fan.class.getDeclaredMethod("fan1",Map.class,List.class,Set.class);
Type[] genericParameterTypes = c1.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if(genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("-----------------------------------");
Method c2 = Fan.class.getDeclaredMethod("nihao");
Type genericReturnType = c2.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
通过反射操作注解
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
public class Table {
public static void main(String[] args) throws NoSuchFieldException {
Class c1=StudentTable.class;
//获取类的对象,反射获得类的注解 强转成注解类型
myAno myano=(myAno)c1.getAnnotation(myAno.class);
//将注解的value转成String,打印
String value = myano.value();
System.out.println(value);
System.out.println("--------------------------");
//获取类的属性
Field f = c1.getDeclaredField("id");
//通过属性反射出注解 强转成注解类型
myAnoo annotation = f.getAnnotation(myAnoo.class);
System.out.println(annotation.len());
System.out.println(annotation.name());
System.out.println(annotation.type());
}
}
@myAno("db_Student")
class StudentTable{
@myAnoo(name = "id", type = "int", len = 10)
int id;
@myAnoo(name = "age", type = "int", len = 10)
int age;
@myAnoo(name = "name", type = "String", len = 10)
String name;
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface myAno{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface myAnoo{
String name();
String type();
int len();
}