✅作者简介:一位材料转码农的选手,希望一起努力,一起进步!
📃个人主页:@每天都要敲代码的个人主页
🔥系列专栏:JavaSE从入门到精通
💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习
目录
一:注解
1. 注解的定义和使用
(1)注解,或者叫做注释类型,英文单词是:Annotation
(2)注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件。
(3)怎么自定义注解呢?语法格式?
[修饰符列表] @interface 注解类型名{
}
(4)注解怎么使用,用在什么地方?
第一:注解使用时的语法格式是:@注解类型名
第二:注解可以出现在类上、属性上、方法上、变量上等....
注解还可以出现在注解类型上;默认注解可以出现在任意位置上!
自定义一个注解
ackage com.bjpowernode.java.annotation;
// 自定义注解:MyAnnotation
public @interface MyAnnotation {
}
注解的使用
package com.bjpowernode.java.annotation;
@MyAnnotation // 用在类上
public class AnnotationTest01 {
@MyAnnotation // 用在实例变量上
private int no;
@MyAnnotation // 用在构造方法上
public AnnotationTest01() {
}
@MyAnnotation // 用在静态方法上
public static void m1(){
@MyAnnotation // 用在局部变量上
int i = 100;
}
@MyAnnotation // 用在实例方法上
public void m2(@MyAnnotation String name,@MyAnnotation int k){ // 注解出现在形参上
}
}
@MyAnnotation // 出现在接口上
interface MyInterface{}
@MyAnnotation // 出现在枚举上
enum Season{
SPRING,SUMMARY,AUTUMN,WINTER
}
在定义一个注解OtherAnnotation,MyAnnotation注解也可以出现在注解OtherAnnotation上
package com.bjpowernode.java.annotation;
@MyAnnotation // 注解修饰注解
public @interface OtherAnnotation {
}
2. JDK内置的注解
java.lang包下的注释类型:
(1)Deprecated: 用 @Deprecated 注释的程序元素,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。 (掌握)
(2)Override: 表示一个方法声明打算重写超类中的另一个方法声明。(掌握)
(3)SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。(了解)
2.1 Override注解
关于JDK java.lang包下的Override注解
(1)源代码:
public @interface Override {
}
(2)@Override这个注解只能注解方法
(3)@Override这个注解是给编译器参考的,和运行阶段没有关系。
(4)凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错。
总结:标识性注解,给编译器做参考的;编译器看到方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法;如果没有重写,报错;这个注解只是在编译阶段起作用,和运行期无关!
package com.bjpowernode.java.annotation;
public class AnnotationTest02 {
// 我们使用快捷键重写toString方法,默认会有@Override注解
@Override // 给编译器看的,表示已经重写了方法
public String toString() {
return "AnnotationTest02{}";
}
}
2.2 Deprecated注解
(1)Deprecated表示这个注解标注的元素已过时;这个注解主要是向其它程序员传达一个信息,告知已过时,有更好的解决方案存在。
(2)源码分析:
// 表示该注解被保存在class文件中(运行时会有提示),并且可以被反射机制所读取。
@Retention(RetentionPolicy.RUNTIME)
// 出现的位置
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
package com.bjpowernode.java.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
public class AnnotationTest03 {
public static void main(String[] args) {
MethodTest m = new MethodTest();
m.doSome(); // 有横线,表示已过时
MethodTest.doOther();// 有横线,表示已过时
}
}
class MethodTest{
@Deprecated // 表示这个方法已过时
public void doSome(){
System.out.println("do something!");
}
@Deprecated // 表示这个方法已过时
public static void doOther(){
System.out.println("do otherthing");
}
}
2.3 元注解Target和Retention
(1)元注解:用来标注“注解类型”的“注解”,称为元注解。
(2)为什么Override注解只能出现在方法上,那是因为元注解的修饰限制
// Target是一个元注解,表示只能出现在方法上
@Target(ElementType.METHOD)
// Retention是一个元注解,表示“被标注的注解”最终保存在哪里
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
(3)常见的元注解有哪些? Target和Retention
(4)关于Target注解:
这个Target注解用来标注“被标注的注解”可以出现在哪些位置上@Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
表示该注解可以出现在:构造方法上 字段上 局部变量上 方法上 .... 类上...
(5)关于Retention注解:
这个Retention注解用来标注“被标注的注解”最终保存在哪里@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取
2.4 在注解中定义属性
自定义注解
package com.bjpowernode.java.Annotation2;
// 在注解中定义属性
public @interface MyAnnotation {
// 在注解中定义属性
// 注解中的属性需要加上小括号 ()
String name(); // MyAnnotation的name属性,不是方法!
String color(); // 颜色属性
int age() default 25; // 属性指定默认值
}
(1)如果一个注解当中有属性,那么使用时必须给属性赋值,不然会报错!或者给该属性使用default指定了默认值 !
(2)格式是: @注解名(属性名=属性值,属性名=属性值....)
package com.bjpowernode.java.Annotation2;
public class MyAnnotationTest {
// @MyAnnotation() 这里会报错,因为注解里有name()属性,但是没赋值
// 报错的原因:如果一个注解当中有属性,那么必须给属性赋值,或者给该属性使用default指定了默认值
// @MyAnnotation(属性名=属性值,属性名=属性值....)
@MyAnnotation(name="zhangsan",color = "red") // age属性指定了默认值,这里就可以不用写上了
public void doSome(){
}
}
2.5 属性是value时可以省略
如果一个注解的属性的名字是value,并且只有一个属性的话,在使用的时候,该属性名可以省略。
自定义属性
package com.bjpowernode.java.annotation3;
public @interface MyAnnotation {
String value(); // 只定一个value属性
}
package com.bjpowernode.java.annotation3;
public class MyAnnotationTest {
@MyAnnotation(value = "hehe") // 正常使用
public void doSome(){
System.out.println("doSome...");
}
@MyAnnotation("haha") // value省略也是可以的
public void doOther(){
System.out.println("doOther...");
}
}
2.6 注解的属性是一个数组
注解当中的属性可以是哪一种类型?
属性的类型可以是:byte short int long float double boolean char String Class 枚举类型以及以上每一种的数组形式。
定义一个枚举类型
package com.bjpowernode.java.annotation4;
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER
}
属性的类型
package com.bjpowernode.java.annotation4;
public @interface MyAnnotation {
int value1();
int[] value3();
String value2();
String[] value4(); // Strin类型及数组
Season value5();
Season[] value6(); // 枚举类型及数组
Class parameterType();
Class[] parameterTypes(); // Class类型及数组
}
当属性是数组时写法和用法
当使用数组时需要使用大括号,如果数组当中只有一个元素,那么大括号可以省略!
package com.bjpowernode.java.annotation4;
public @interface OtherAnnotation {
int age(); // 年龄属性
String[] emails(); // 邮箱属性,支持多个
Season[] seasonArray();
}
package com.bjpowernode.java.annotation4;
public class OtherAnnotationTest {
// 数组是大括号
@OtherAnnotation(age = 25, emails = {"zhangsan@123.com", "zhangsan@sohu.com"},seasonArray = {Season.AUTUMN,Season.SPRING})
public void doSome(){
}
// 如果数组中只有1个元素:大括号可以省略。
@OtherAnnotation(age = 25, emails = "zhangsan@123.com",seasonArray = Season.AUTUMN)
public void doOther(){
}
}
3. 注解的作用
3.1 反射注解
定义注解
package com.bjpowernode.java.annotation5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 只允许该注解标注类、方法(ElementType是一个枚举)
@Target(value = {ElementType.TYPE,ElementType.METHOD}) // value可以被省略
// 希望这个注解可以被反射
@Retention(value = RetentionPolicy.RUNTIME) // value可以被省略
public @interface MyAnnotation {
String value() default "安徽省";
}
使用注解的类
package com.bjpowernode.java.annotation5;
@MyAnnotation
public class MyAnnotationTest {
@MyAnnotation
public void doSome(){
int i;
}
}
反射类上注解的属性
package com.bjpowernode.java.annotation5;
// 反射注解
public class ReflectAnnotationTest {
public static void main(String[] args) throws Exception {
// 获取类
Class c = Class.forName("com.bjpowernode.java.annotation5.MyAnnotationTest");
// 判断类上面是否有@MyAnnotation注解
boolean b = c.isAnnotationPresent(MyAnnotation.class);
// System.out.println(b); // true
// 如果存在,获取注解
if(b){
// 获取该注解对象
// 参数是Class,返回类型是Annotation,需要强制类型转换
MyAnnotation myAnnotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
// System.out.println(myAnnotation); // @com.bjpowernode.java.annotation5.MyAnnotation(value=安徽省)
// 获取注解对象的属性
String value = myAnnotation.value();
System.out.println(value); // 安徽省
}
}
}
3.2 方法上的注解(通过反射获取注解对象属性的值)
package com.bjpowernode.java.annotation6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 只能出现在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String username(); // 用户属性
String password(); // 密码属性
}
package com.bjpowernode.java.annotation6;
import java.lang.reflect.Method;
public class MyAnnotationTest {
@MyAnnotation(username="admin",password = "123")
public void doSome(){
}
public static void main(String[] args) throws Exception {
// 获取MyAnnotationTest的doSome()方法上的注解信息
Class c = Class.forName("com.bjpowernode.java.annotation6.MyAnnotationTest");
// 获取doSome()方法
Method doSomeMethod = c.getDeclaredMethod("doSome");
// System.out.println(doSomeMethod);
// 判断方法上有没有注解
if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myAnnotation = doSomeMethod.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.username()); // admin
System.out.println(myAnnotation.password()); // 123
}
}
}
3.3 注解在实际开发中的作用
需求:假设有这样一个注解,叫做:@Id;这个注解只能出现在类上面,当这个类上有这个注解的时候,要求这个类中必须有一个int类型的id属性。如果没有这个属性就报异常。如果有这个属性则正常执行!
自定义注解
package com.bjpowernode.java.annotation7;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) // 只能出现在类上
@Retention(RetentionPolicy.RUNTIME) // 可以被反射机制读取
public @interface Id {
}
User类
package com.bjpowernode.java.annotation7;
@Id
public class User {
// 这个类上必须有int的id属性
int id;
String name;
String password;
}
异常
package com.bjpowernode.java.annotation7;
// 自定义异常,继承Exception类或者它的子类,然后编写两个构造方法
public class HasNotIdException extends RuntimeException{
public HasNotIdException(){}
public HasNotIdException(String s){
super(s);
}
}
测试
package com.bjpowernode.java.annotation7;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception{
// 获取类
Class userClass = Class.forName("com.bjpowernode.java.annotation7.User");
// 判断类上是否存在Id注解
if(userClass.isAnnotationPresent(Id.class)){
// 有Id注解,要求类中必须存在int类型的id属性
// 获取这个类的所有属性Field
Field[] fields = userClass.getDeclaredFields();
boolean isOk = false; // 给一个默认的标记
// 遍历获取每个属性Field
for(Field field :fields){
if("id".equals(field.getName()) &&
"int".equals(field.getType().getSimpleName())){
isOk = true;
break;
}
}
// 没有int类型的id属性
if(!isOk){
// 抛出异常
throw new HasNotIdException("被@Id注解标注的类中必须要有一个int类型的id属性!");
}
}
}
}
结束语
今天的分享就到这里啦!快快通过下方链接注册加入刷题大军吧!
各种大厂面试真题在等你哦!
💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习