注解
注解和注释类似,注释是写给程序员看的,为了方便程序员看懂程序的代码。
而注解不单单是给程序员看,更重要的是给程序看。不同的注解有不同的功能,除了系统定义的注解以外,我们也可以自定义注解。
注解是以@开始的。
系统内置的常见注解
@Override
这个用于判断方法是否是重写放到的注解,它会检查你的方法名是不是与父类中的方法同名,如果不是会报错,如果是则不报错。@Override注解只能用于方法。
@Deprecated
单词的意思是过时的。可以用于修饰方法,表示这个方法已经过时,应该选择别的方法使用,即使用了不会报错,只是不建议用。
@SuppressWarnings
压制警告,主要的作用是消除警告。究竟要压制什么警告,写在括号中。
@SuppressWarnings("unused")
int a = 10;
@SuppressWarnings({"rawtypes","unused"})
ArrayList list = new ArrayList();
@FunctionalInterface
函数式接口,用来修饰接口,接口中只能有一个方法。
自定义注解
想要创建一个注解,语法格式如下:
public @interface 注解名 {
注解的属性
}
定义一个注解,需要指定以下信息:
-
注解能用在什么地方。(属性,方法,构造器,类…)
@Target({ElementType.FIELD, ElementType.METHOD,…})
元注解:@Target是元注解的一种。
所谓的元注解就是注解注解的注解。
@Target的取值范围:
TYPE:用于注解类,接口,枚举。
FIELD:用于注解属性。
METHOD:用于注解方法。
PARAMETER:用于注解方法的参数
CONSTRUCTOR:用于注解构造器
LOCAL_VARIABLE:用于注解局部变量
ANNOTATION_TYPE:用于注解一个注解
PACKAGE:用于注解包
TYPE_PARAMETER:用于注解类型参数
TYPE_USE:用于注解用了一个类型
-
注解的声明周期多久。(原码阶段,字节码阶段,运行期)
@Retention(RetentionPolicy.SOURCE)
@Retention也是一个元注解。
取值范围
RetentionPolicy.SOURCE:仅源代码有效,不会被编译成class文件。一般定义为SOURCE的注解,仅仅做检查用,检查是不是方法重写等。
RetentionPolicy.CLASS:会编译成class文件,但是运行期无效。
RetentionPolicy.RUNTIME:运行期有效,也就意味着,在运行期可以获取注解对象,读取注解中写入的信息。-----很有用,尤其是自己写类库的时候。
其他元注解:
@Documented用于表示注解会一起写入API文档(javadoc.exe)
@Inherited一旦一个注解定义为可继承的,注解如果加给了父类,那么之类会把注解继承过来。
-
注解有哪些属性。
注解可以包含属性,属性由3部分构成。 类型 属性名() 默认值;
属性名的写法与 无参方法相同。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface MyAnnotation {
int a();
String[] b();
double c() default 3.14;
}
注解的一些注意事项:
- 注解中的属性名后面必须要有().
- 如果注解中的属性是一个数组,使用时,如果数组只有一个值,大括号可以省略
- 如果注解只有一个属性,且属性名为value,在使用时,value可以省略不写。
public class Person {
@MyAnnotation(a = 10, b = {"hello","hehe"})
private String name;
private int age;
@MyAnnotation(a = 20, b = "world")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(a = 100, b = "lanou" ,c = 25.8)
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Deprecated
public void test() {
}
@MyAnnotation2(12)
public void test2() {
@SuppressWarnings(value = "unused")
int a = 10;
@SuppressWarnings({"rawtypes","unused"})
ArrayList list = new ArrayList();
}
}
学习注解的第一个目标:能看懂注解,看懂系统或者第三方类库中注解的含义,能会使用注解。
学习注解的终极目标:某天自己写类库,写注解,让别人用。注解往往是结合反射使用的。
反射
生活中的反射
太阳光照射到镜子上,会发生反射。反射时光的方向会发生改变(略微的反向)。
代码中的反射,改变了我们使用对象的方式。之前:对象调方法,对象设置属性。反射刚好反了一下。方法调用对象,属性调用对象。
在Java中反射是比较底层的内容,想要实现反射需要使用Class类。
什么是Class类
类是相同事物的抽象。类在描述一类事物。例如:人都有姓名,性别,年龄,还有吃饭、睡觉、打豆豆。
通过创建对象,可以形成各种不同的人。
类是由谁来描述的呢?Class就是描述类的类。类也有共性,属性,方法,构造器,父类,接口。每一个类都有对应一个Class实例。你可以认为一个Class对象对应的是一个xx.class文件。
Class没有创建方法,每个类的Class实例是在这个类的class文件加载到内存中的时候,由ClassLoader创建。我们只能获取Class类的对象。
Class类有以下几种获取方式:
- 类名.class
基本数据类型也可以获取对应的Class实例 用法是int.class double.class 普通类获取Class对象的方法:String.class Person.class
- 对象.getClass()
- Class.forName(“类的完整字符串描述”)
//获取Class对象的方式一: 类名.class
Class class1 = int.class;
System.out.println(class1);
Class class2 = String.class;
System.out.println(class2);
Class class3 = Person.class;
System.out.println(class3);
//获取Class对象的方式二: 对象.getClass();
String str = "hello";
Class class4 = str.getClass();
System.out.println(class4);
System.out.println(class4 == class2);
Person p = new Person();
Class class5 = p.getClass();
System.out.println(class5);
System.out.println(class3 == class5);
//获取Class对象的方式三: Class.forName("完整类名")
Class class6 = Class.forName("java.util.ArrayList");
System.out.println(class6);
Class class7 = Class.forName("com.lanou.lessonclass.Person");
System.out.println(class7);
反射
在Java中提供了一套机制,这种机制允许你通过Class对象来获取类的全部信息(属性,方法,构造器,接口,父类,注解等等),获取之后,你可以对他们做你想做的事情。哪怕是私有的也可以操作。
通过Class对象获取类的属性
在Java中Filed类是用于描述属性的类。
通过Class对象获取类的属性的方式有4个:
getFields() //获取类中所有的public属性(含继承链上的public属性)
getField(String name) //获取类中指定名称的public属性。(含继承链上的 public属性)
getDeclaredFields() //获取类中所有的属性(不含继承链上的属性)
getDeclaredFiled(String name) //获取类中指定名称的属性
通过Class对象获取类的构造器
在Java中Constructor类用于描述类的构造器。
通过Class对象获取类的构造器的方式有4个:
getConstructor(Class …parameterTypes) // 获取本类中指定参数的public构造器
getConstructors() //获取本类中全部的public构造器
getDeclaredConstructor(Class…parameterTypes) //获取本类中指定参数的构造器
getDeclaredConstructors() //获取本类中全部的构造器。
通过Class对象获取类的方法
在Java中Method是用于描述类的方法。
通过Class对象获取类的方法的方式有4种:
getMethods() // 获取全部的public方法(含继承链上的方法)
getMethod(String methodName, Class…parameterTypes) //获取指定名称的public方法
getDeclaredMethods() //获取本类中所有的方法
getDeclaredMethod(String methodName, Class…paremeterTypes) //获取本类中指定名称的方法。
反射的作用
反射给的第一感觉:脱了裤子放屁!
实际上反射的价值就在于能动态获取信息!
虽然写了很多很多代码,但是代码一旦写成,复用性很高。而且不需要导包!因为Class.forName(“类名”)可以以字符串的方式获取类名,再通过类名得到类的Class对象。
反射多用于写框架,几乎所有的框架底层都是靠反射实现的。