注解概念
注解又叫 Java 标注,是 JDK5.0 引入的一种注释机制。注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。
Annotation的作用
- 不是程序本身 , 可以对程序作出解释.(这一点和注释(comment)没什么区别)
- 可以被其他程序(比如:编译器等)读取
Annotation的格式
- 注解是以"@注释名"在代码中存在的
- 还可以添加一些参数值 , 例如:@SuppressWarnings(value="unchecked")
Annotation在哪里使用?
- 可以附加在package , class , method , fifield 等上面 , 相当于给他们添加了额外的辅助信息
- 我们可以通过反射机制实现对这些元数据的访问
3种注解
内置注解
java自己定义的注解
-
@Override: 检查该方法是否重写,如果父类没有该方法,报错。
-
@Deprecated: 标记已过时,不推荐使用的方法。(例
functionName)。java中经常有一些方法,当你输入时,会出现类似的模式,是告诉你已过时了,不推荐使用。你自己也可以定义已过时的方法。 -
@SuppressWarnings:让编译器去忽略注解中声明的警告。比如去忽略已过时方法警告。
元注解
注解其他注解
- @Target:用于描述注解可以用在哪些地方。Target内部的值使用枚举ElementType表示。(例如{ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD} 用在属性,本地变量,方法上)。
- @Retention:表示我们的注解在什么地方有效。在什么地方可以通过反射去使用。value可以为SOURCE < CLASS < RUNTIME。如果设置的为RUNTIME,那么它在SOURCE和CLASS也是有效的。
- @Documented: 表示是否将我们的注解包含在javadoc中。
- @Inherited:说明子类可以继承父类中的该注解。
- @SafeVarargs:用在参数长度可变的方法或构造方法上,方法必须声明为static或final。也是抑制警告,比Retention更具体。
- @FunctionalInterface: 标识一个匿名函数或函数式接口。java不会强求你去使用它来标记你的接口是函数式或者是匿名函数,是一个设计上的考虑,可以让用户明显知道这是一个函数式接口或匿名函数。
- @Repeatable:标注一个注解可以在同一个地方使用多次。
自定义注解
使用@interface自定义注解
public class Test {
@myAnnotation(name="matao")
@myAnnotation2("test")
public static void test(){
}
}
@Target({ElementType.METHOD, ElementType.TYPE}) //可以使用在类或者方法上
@Retention(RetentionPolicy.RUNTIME) //在运行时有效
@interface myAnnotation{
String name() default "MAa"; //可以填写默认值,当不赋值的时候,就为默认值
int age() default 0;
int id() default -1;
String[] schools() default {"shanxidaxue","fsu"};
}
//如果@interface里只有一个值value,在用的时候可以不写value
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation2{
String value();
}
反射(Reflection)
概念:是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
因为我们不知道初始化类的对象是什么,无法用new来创建对象,可以通过反射去获得类的内部信息。(反编译)
Java 反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取或者修改任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法或属性
反射框架
Class
反射基于 Class, Class 是一个类,封装了当前对象所对应的类的信息。一个类有属性,方法,构造器等,比如说有一个 Person 类,一个 Order 类,一个 Book 类,这些都是不同的类,现在需要一个类,用来描述类,这就是 Class,它应该有类名,属性,方法,构造器等。Class 是用来描述类的类。
对于每个类,都有一个不变的 Class 类型的对象,一个 Class 对象包含了特定某个类的有关信息。一个类(不是一个对象) 在 JVM 中只会有一个 Class 实例。
获取 Class 对象的三种方式
- 通过类名获取
- 通过对象获取
- 通过全类名获取
常用方法
主要涉及类
反射技术的核心技术是Class对象,每个类在定义以后都有各自的Class对象
反射操作泛型
- Java采用泛型擦除的机制来引入泛型 , Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性
- 和免去强制类型转换问题 , 但是 , 一旦编译完成 , 所有和泛型有关的类型全部擦除
- 为了通过反射操作这些类型 , Java新增了 ParameterizedType , GenericArrayType , TypeVariable
- 和 WildcardType 几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型.
- ParameterizedType : 表示一种参数化类型,比如Collection
- GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable : 是各种类型变量的公共父接口
- WildcardType : 代表一种通配符类型表达式
代码示例
public class Test07 {
public void test01(Map<String, User> map, List<User> list){
System.out.println("test01");
}
public Map<String, User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method m = Test07.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = m.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);
}
}
}
m = Test07.class.getMethod("test02", null);
Type genericReturnType = m.getGenericReturnType(); //获取返回值类型
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
反射操作注解
主要方法:
- getAnnotations
- getAnnotation
代码示例
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Class.forName("com.ma.reflection.Student2");
//通过反射获得注解
Annotation[] annotation = c.getAnnotations();
for (Annotation annotation1 : annotation) {
System.out.println(annotation1);
}
kuangtable annotation1 = (kuangtable) c.getAnnotation(kuangtable.class);
System.out.println(annotation1.value());//获得注解的value值
//获得指定的注解
Field field = c.getDeclaredField("name");
field annotation2 = field.getAnnotation(field.class);
System.out.println(annotation2.columnName());
System.out.println(annotation2.type());
System.out.println(annotation2.length());
}
}
@kuangtable("db_student")
class Student2{
public Student2() {
}
@field(columnName = "name", type = "varchar", length = 10)
private String name;
@field(columnName = "id", type = "int", length = 10)
private int id;
@field(columnName = "age", type = "int", length = 10)
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Student2(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface kuangtable{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface field{
String columnName();
String type();
int length();
}