10--面向对象OOP--05

1、代码块

如果成员变量想要初始化的值不是一个硬编码的常量值,而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值,该怎么办呢?此时,可以考虑代码块(或初始化块)。

  • 代码块(或初始化块)的作用:对Java类或对象进行初始化
  • 代码块(或初始化块)的分类:
    • 一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块(static block)
    • 没有使用static修饰的,为非静态代码块。

1.1 静态代码块

如果想要为静态变量初始化,可以直接在静态变量的声明后面直接赋值,也可以使用静态代码块。

1.1.1 语法格式

在代码块的前面加static,就是静态代码块。

【修饰符】 class 类{static{静态代码块}
}

1.1.2 静态代码块的特点

  1. 可以有输出语句。
  2. 可以对类的属性、类的声明进行初始化操作。
  3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
  4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
  5. 静态代码块的执行要先于非静态代码块。
  6. 静态代码块随着类的加载而加载,且只执行一次。
public class Chinese {//    private static String country = "中国";private static String country;private String name;{System.out.println("非静态代码块,country = " + country);}static {country = "中国";System.out.println("静态代码块");}public Chinese(String name) {this.name = name;}
}
public class TestStaticBlock {public static void main(String[] args) {Chinese c1 = new Chinese("张三");Chinese c2 = new Chinese("李四");}
}

1.2 非静态代码块

1.2.1 语法格式

【修饰符】 class 类{{非静态代码块}【修饰符】 构造器名(){// 实例初始化代码}【修饰符】 构造器名(参数列表){// 实例初始化代码}
}

1.2.2 非静态代码块的作用

和构造器一样,也是用于实例变量的初始化等操作。

1.2.3 非静态代码块的意义

如果多个重载的构造器有公共代码,并且这些代码都是先于构造器其他代码执行的,那么可以将这部分代码抽取到非静态代码块中,减少冗余代码。

1.2.4 非静态代码块的执行特点

  1. 可以有输出语句。
  2. 可以对类的属性、类的声明进行初始化操作。
  3. 除了调用非静态的结构外,还可以调用静态的变量或方法。
  4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
  5. 每次创建对象的时候,都会执行一次。且先于构造器执行。

1.3 实例变量赋值顺序

2、内部类

2.1 概述

2.1.1 什么是内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类(InnerClass),类B则称为外部类(OuterClass)

2.1.2 为什么要声明内部类呢

具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。

总的来说,遵循高内聚、低耦合的面向对象开发原则。

2.1.3 内部类的分类

根据内部类声明的位置(如同变量的分类),我们可以分为:

2.2 成员内部类

2.2.1 概述

如果成员内部类中不使用外部类的非静态成员,那么通常将内部类声明为静态内部类,否则声明为非静态内部类。

语法格式:

[修饰符] class 外部类{[其他修饰符] [static] class 内部类{}
}

成员内部类的使用特征,概括来讲有如下两种角色:

  • 成员内部类作为类的成员的角色:
    • 和外部类不同,Inner class还可以声明为private或protected;
    • 可以调用外部类的结构。(注意:在静态内部类中不能使用外部类的非静态成员)
    • Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;
  • 成员内部类作为类的角色:
    • 可以在内部定义属性、方法、构造器等结构
    • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
    • 可以声明为abstract类 ,因此可以被其它的内部类继承
    • 可以声明为final的,表示不能被继承
    • 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)

注意点:

  1. 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
  2. 成员内部类可以直接使用外部类的所有成员,包括私有的数据
  3. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

2.2.2 创建成员内部类对象

  • 实例化静态内部类
外部类名.静态内部类名 变量 = 外部类名.静态内部类名();
变量.非静态方法();
  • 实例化非静态内部类
外部类名 变量1 = new 外部类();
外部类名.非静态内部类名 变量2 = 变量1.new 非静态内部类名();
变量2.非静态方法();

2.2.3 举例

public class TestMemberInnerClass {public static void main(String[] args) {//创建静态内部类实例,并调用方法Outer.StaticInner inner = new Outer.StaticInner();inner.inFun();//调用静态内部类静态方法Outer.StaticInner.inMethod();System.out.println("*****************************");//创建非静态内部类实例(方式1),并调用方法Outer outer = new Outer();Outer.NoStaticInner inner1 = outer.new NoStaticInner();inner1.inFun();//创建非静态内部类实例(方式2)Outer.NoStaticInner inner2 = outer.getNoStaticInner();inner1.inFun();}
}
class Outer{private static String a = "外部类的静态a";private static String b  = "外部类的静态b";private String c = "外部类对象的非静态c";private String d = "外部类对象的非静态d";static class StaticInner{private static String a ="静态内部类的静态a";private String c = "静态内部类对象的非静态c";public static void inMethod(){System.out.println("Inner.a = " + a);System.out.println("Outer.a = " + Outer.a);System.out.println("b = " + b);}public void inFun(){System.out.println("Inner.inFun");System.out.println("Outer.a = " + Outer.a);System.out.println("Inner.a = " + a);System.out.println("b = " + b);System.out.println("c = " + c);//            System.out.println("d = " + d);//不能访问外部类的非静态成员}}class NoStaticInner{private String a = "非静态内部类对象的非静态a";private String c = "非静态内部类对象的非静态c";public void inFun(){System.out.println("NoStaticInner.inFun");System.out.println("Outer.a = " + Outer.a);System.out.println("a = " + a);System.out.println("b = " + b);System.out.println("Outer.c = " + Outer.this.c);System.out.println("c = " + c);System.out.println("d = " + d);}}public NoStaticInner getNoStaticInner(){return new NoStaticInner();}
}

2.3 局部内部类

2.3.1 非匿名局部内部类

语法格式:

[修饰符] class 外部类{[修饰符] 返回值类型  方法名(形参列表){[final/abstract] class 内部类{}}    
}
  • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。
    • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
  • 和成员内部类不同的是,它前面不能有权限修饰符等
  • 局部内部类如同局部变量一样,有作用域
  • 局部内部类中是否能访问外部类的非静态的成员,取决于所在的方法

举例:

public class TestLocalInner {public static void main(String[] args) {Outer.outMethod();System.out.println("-------------------");Outer out = new Outer();out.outTest();System.out.println("-------------------");Runner runner = Outer.getRunner();runner.run();}
}
class Outer{public static void outMethod(){System.out.println("Outer.outMethod");final String c = "局部变量c";class Inner{public void inMethod(){System.out.println("Inner.inMethod");System.out.println(c);}}Inner in = new Inner();in.inMethod();}public void outTest(){class Inner{public void inMethod1(){System.out.println("Inner.inMethod1");}}Inner in = new Inner();in.inMethod1();}public static Runner getRunner(){class LocalRunner implements Runner{@Overridepublic void run() {System.out.println("LocalRunner.run");}}return new LocalRunner();}}
interface Runner{void run();
}

2.3.2 匿名内部类

因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。

new 父类([实参列表]){重写方法...
}
new 父接口(){重写方法...
}

举例1:使用匿名内部类的对象直接调用方法:

interface A{void a();
}
public class Test{public static void main(String[] args){new A(){@Overridepublic void a() {System.out.println("aaaa");}}.a();}
}

举例2:通过父类或父接口的变量多态引用匿名内部类的对象

interface A{void a();
}
public class Test{public static void main(String[] args){A obj = new A(){@Overridepublic void a() {System.out.println("aaaa");}};obj.a();}
}

举例3:匿名内部类的对象作为实参

interface A{void method();
}
public class Test{public static void test(A a){a.method();}public static void main(String[] args){test(new A(){@Overridepublic void method() {System.out.println("aaaa");}});}   
}

3、枚举类

3.1 概述

  • 枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。
  • 枚举类的例子举不胜举:
    • 星期:Monday(星期一)......Sunday(星期天)
    • 性别:Man(男)、Woman(女)
    • 月份:January(1月)......December(12月)
    • 季节:Spring(春节)......Winter(冬天)
    • 三原色:red(红色)、green(绿色)、blue(蓝色)
    • 线程状态:创建、就绪、运行、阻塞、死亡
  • 若枚举只有一个对象, 则可以作为一种单例模式的实现方式。
  • 枚举类的实现:
    • 在JDK5.0 之前,需要程序员自定义枚举类型。
    • 在JDK5.0 之后,Java支持enum关键字来快速定义枚举类型。

3.2 定义枚举类(JDK5.0 之前)

在JDK5.0 之前如何声明枚举类呢?

  • 私有化类的构造器,保证不能在类的外部创建其对象
  • 在类的内部创建枚举类的实例。声明为:public static final ,对外暴露这些常量对象
  • 对象如果有实例变量,应该声明为private final(建议,不是必须),并在构造器中初始化

示例代码:

package com.suyv.enum01;
/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:14
*@Description: JDK5.0之前定义枚举类
*/
public class Season{private final String SEASONNAME;    //季节的名称private final String SEASONDESC;    //季节的描述private Season(String seasonName,String seasonDesc){this.SEASONNAME = seasonName;this.SEASONDESC = seasonDesc;}public static final Season SPRING = new Season("春天", "春暖花开");public static final Season SUMMER = new Season("夏天", "夏日炎炎");public static final Season AUTUMN = new Season("秋天", "秋高气爽");public static final Season WINTER = new Season("冬天", "白雪皑皑");@Overridepublic String toString() {return "Season{" +"SEASONNAME='" + SEASONNAME + '\'' +", SEASONDESC='" + SEASONDESC + '\'' +'}';}
}
// 测试枚举类
class SeasonTest{public static void main(String[] args) {System.out.println(Season.AUTUMN);}
}

3.3 定义枚举类(JDK5.0 之后)

3.3.1 enum关键字声明枚举
【修饰符】 enum 枚举类名{常量对象列表
}【修饰符】 enum 枚举类名{常量对象列表;对象的实例变量列表;
}

举例1:

package com.suyv.enum01;/*** @Author: 憨憨浩浩* @CreateTime: 2023-12-09 09:16* @Description: 定义星期枚举类*/
public enum Week {MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}// 测试枚举类
class TestEnum {public static void main(String[] args) {Week w = Week.MONDAY;System.out.println(w);}
}
3.3.2 enum方式定义的要求和特点
  • 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。
  • 列出的实例系统会自动添加 public static final 修饰
  • 如果常量对象列表后面没有其他代码“;”可以省略,否则不可以省略“;”。
  • 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数
  • 如果枚举类需要的是有参构造,需要手动定义,有参构造的private可以省略,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。
  • 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。
  • JDK5.0 之后switch,提供支持枚举类型,case后面可以写枚举常量名,无需添加枚举类作为限定。

举例2:

package com.suyv.enum01;/*** @Author: 憨憨浩浩* @CreateTime: 2023-12-09 09:20* @Description: 定义季节枚举类*/
public enum SeasonEnum {SPRING("春天","春风又绿江南岸"),SUMMER("夏天","映日荷花别样红"),AUTUMN("秋天","秋水共长天一色"),WINTER("冬天","窗含西岭千秋雪");private final String seasonName;private final String seasonDesc;private SeasonEnum(String seasonName, String seasonDesc) {this.seasonName = seasonName;this.seasonDesc = seasonDesc;}public String getSeasonName() {return seasonName;}public String getSeasonDesc() {return seasonDesc;}
}
// 测试季节枚举类
class SeasonEnumTest{public static void main(String[] args) {SeasonEnum season = SeasonEnum.AUTUMN;System.out.println(season);System.out.println(season.getSeasonName());System.out.println(season.getSeasonDesc());}
}

举例3:

package com.suyv.enum01;/*** @Author: 憨憨浩浩* @CreateTime: 2023-12-09 09:23* @Description: 定义星期枚举类*/
public enum Week01 {MONDAY("星期一"),TUESDAY("星期二"),WEDNESDAY("星期三"),THURSDAY("星期四"),FRIDAY("星期五"),SATURDAY("星期六"),SUNDAY("星期日");private final String description;private Week01(String description){this.description = description;}@Overridepublic String toString() {return super.toString() +":"+ description;}
}
package com.suyv.enum01;
/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:25
*@Description: 测试星期枚举类--以及Switch支持枚举类
*/
public class TestWeek {public static void main(String[] args) {Week week = Week.MONDAY;System.out.println(week);switch (week){case MONDAY:System.out.println("怀念周末,困意很浓");break;case TUESDAY:System.out.println("进入学习状态");break;case WEDNESDAY:System.out.println("死撑");break;case THURSDAY:System.out.println("小放松");break;case FRIDAY:System.out.println("又信心满满");break;case SATURDAY:System.out.println("开始盼周末,无心学习");break;case SUNDAY:System.out.println("一觉到下午");break;}}
}

开发中,当需要定义一组常量时,强烈建议使用枚举类。

3.4 enum中常用方法

String toString()

        默认返回的是常量名(对象名),可以继续手动重写该方法!

static 枚举类型[] values()

        返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法

static 枚举类型 valueOf(String name)

        可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。

String name()

        得到当前枚举常量的名称。建议优先使用toString()。

int ordinal()

        返回当前枚举常量的次序号,默认从0开始

举例:

package com.suyv.enum01;import java.util.Scanner;/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:28
*@Description: 枚举类(enum)的常用方法
*/
public class TestEnumMethod {public static void main(String[] args) {//values()Week[] values = Week.values();for (int i = 0; i < values.length; i++) {//ordinal()、name()System.out.println((values[i].ordinal()+1) + "->" + values[i].name());}System.out.println("------------------------");Scanner input = new Scanner(System.in);System.out.print("请输入星期值:");int weekValue = input.nextInt();Week week = values[weekValue-1];//toString()System.out.println(week);System.out.print("请输入星期名:");String weekName = input.next();//valueOf()week = Week.valueOf(weekName);System.out.println(week);input.close();}
}

3.5 实现接口的枚举类

  • 和普通 Java 类一样,枚举类可以实现一个或多个接口
  • 若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只要统一实现该方法即可。
  • 若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法

语法:

//1、枚举类可以像普通的类一样,实现接口,并且可以多个,但要求必须实现里面所有的抽象方法!
enum A implements 接口1,接口2{//抽象方法的实现
}//2、如果枚举类的常量可以继续重写抽象方法!
enum A implements 接口1,接口2{常量名1(参数){//抽象方法的实现或重写},常量名2(参数){//抽象方法的实现或重写},//...
}

举例:

interface Info{void show();
}//使用enum关键字定义枚举类
enum Season1 implements Info{//1. 创建枚举类中的对象,声明在enum枚举类的首位SPRING("春天","春暖花开"){public void show(){System.out.println("春天在哪里?");}},SUMMER("夏天","夏日炎炎"){public void show(){System.out.println("宁静的夏天");}},AUTUMN("秋天","秋高气爽"){public void show(){System.out.println("秋天是用来分手的季节");}},WINTER("冬天","白雪皑皑"){public void show(){System.out.println("2002年的第一场雪");}};//2. 声明每个对象拥有的属性:private final修饰private final String SEASON_NAME;private final String SEASON_DESC;//3. 私有化类的构造器private Season1(String seasonName,String seasonDesc){this.SEASON_NAME = seasonName;this.SEASON_DESC = seasonDesc;}public String getSEASON_NAME() {return SEASON_NAME;}public String getSEASON_DESC() {return SEASON_DESC;}
}

4、注解(Annotation)

4.1 注解概述

4.1.1 什么是注解

注解(Annotation)是从JDK5.0开始引入,以“@注解名在代码中存在。例如:

@Override
@Deprecated
@SuppressWarnings(value=”unchecked”)

Annotation 可以像修饰符一样被使用,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。还可以添加一些参数值,这些信息被保存在 Annotation 的 “name=value” 对中。

注解可以在类编译、运行时进行加载,体现不同的功能。

4.1.2 注解与注释

注解也可以看做是一种注释,通过使用 Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。但是,注解,不同于单行注释和多行注释。

  • 对于单行注释和多行注释是给程序员看的。
  • 而注解是可以被编译器或其他程序读取的。程序还可以根据注解的不同,做出相应的处理。
4.1.3 注解的重要性

在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。

未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,Struts2有一部分也是基于注解的了。注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式。

4.2 常见的Annotation作用

示例1:生成文档相关的注解

@author

        标明开发该类模块的作者,多个作者之间使用,分割

@version

        标明该类模块的版本

@see

        参考转向,也就是相关主题

@since

        从哪个版本开始增加的

@param

        对方法中某参数的说明,如果没有参数就不能写

@return

        对方法返回值的说明,如果方法的返回值类型是void就不能写

@exception

        对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写

package com.suyv.annotation;
/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:37
*@Description: TODO
*/
public class JavadocTest {/*** 程序的主方法,程序的入口* @param args String[] 命令行参数*/public static void main(String[] args) {}/*** 求圆面积的方法* @param radius double 半径值* @return double 圆的面积*/public static double getArea(double radius){return Math.PI * radius * radius;}
}

示例2:在编译时进行格式检查(JDK内置的三个基本注解)

@Override: 限定重写父类方法,该注解只能用于方法

@Deprecated: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择

@SuppressWarnings: 抑制编译器警告

package com.suyv.annotation;
/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:40
*@Description: TODO
*/
public class AnnotationTest{public static void main(String[] args) {@SuppressWarnings("unused")int a = 10;}@Deprecatedpublic void print(){System.out.println("过时的方法");}@Overridepublic String toString() {return "重写的toString方法()";}
}

示例3:跟踪代码依赖性,实现替代配置文件功能

  • Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署。
@WebServlet("/login")
public class LoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) { }protected void doPost(HttpServletRequest request, HttpServletResponse response) {doGet(request, response);}  
}
<servlet><servlet-name>LoginServlet</servlet-name><servlet-class>com.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>/login</url-pattern>
</servlet-mapping>
  • Spring框架中关于“事务”的管理
@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED,readOnly=false,timeout=3)
public void buyBook(String username, String isbn) {//1.查询书的单价int price = bookShopDao.findBookPriceByIsbn(isbn);//2. 更新库存bookShopDao.updateBookStock(isbn);  //3. 更新用户的余额bookShopDao.updateUserAccount(username, price);
}
<!-- 配置事务属性 -->
<tx:advice transaction-manager="dataSourceTransactionManager" id="txAdvice"><tx:attributes><!-- 配置每个方法使用的事务属性 --><tx:method name="buyBook" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"  read-only="false"  timeout="3" /></tx:attributes>
</tx:advice>

4.3 三个最基本的注解

4.3.1 @Override
  • 用于检测被标记的方法为有效的重写方法,如果不是,则报编译错误!
  • 只能标记在方法上。
  • 它会被编译器程序读取。
4.3.2 @Deprecated
  • 用于表示被标记的数据已经过时,不推荐使用。
  • 可以用于修饰 属性、方法、构造、类、包、局部变量、参数。
  • 它会被编译器程序读取。
4.3.3 @SuppressWarnings
  • 抑制编译警告。当我们不希望看到警告信息的时候,可以使用 SuppressWarnings 注解来抑制警告信息
  • 可以用于修饰类、属性、方法、构造、局部变量、参数
  • 它会被编译器程序读取。
  • 可以指定的警告类型有(了解)
    • all,抑制所有警告
    • unchecked,抑制与未检查的作业相关的警告
    • unused,抑制与未用的程式码及停用的程式码相关的警告
    • deprecation,抑制与淘汰的相关警告
    • nls,抑制与非 nls 字串文字相关的警告
    • null,抑制与空值分析相关的警告
    • rawtypes,抑制与使用 raw 类型相关的警告
    • static-access,抑制与静态存取不正确相关的警告
    • static-method,抑制与可能宣告为 static 的方法相关的警告
    • super,抑制与置换方法相关但不含 super 呼叫的警告
    • ...

示例代码:

package com.suyv.annotation;import java.util.ArrayList;/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-09 09:42
*@Description: TODO
*/
public class TestAnnotation {@SuppressWarnings("all")public static void main(String[] args) {int i;ArrayList list = new ArrayList();list.add("hello");list.add(123);list.add("world");Father f = new Son();f.show();f.methodOl();}
}class Father{@Deprecatedvoid show() {System.out.println("Father.show");}void methodOl() {System.out.println("Father Method");}
}// 添加了@Override注解表明该方法属于重写方法,
// 不添加不会匹配父类的同名方法,相当于子类独有的方法
class Son extends Father{/*@Overridevoid method01() {System.out.println("Son Method");}*/
}

4.4 元注解

JDK1.5在java.lang.annotation包定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。

(1)@Target:用于描述注解的使用范围

  • 可以通过枚举类型ElementType的10个常量对象来指定
  • TYPE,METHOD,CONSTRUCTOR,PACKAGE.....

(2)@Retention:用于描述注解的生命周期

  • 可以通过枚举类型RetentionPolicy的3个常量对象来指定
  • SOURCE(源代码)、CLASS(字节码)、RUNTIME(运行时)
  • 唯有RUNTIME阶段才能被反射读取到。

(3)@Documented:表明这个注解应该被 javadoc工具记录。

(4)@Inherited:允许子类继承父类中的注解

示例代码:

package java.lang;import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
package java.lang;import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {String[] value();
}
package java.lang;import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

4.5 自定义注解的使用

一个完整的注解应该包含三个部分:(1)声明(2)使用(3)读取

4.5.1 声明自定义注解
【元注解】
【修饰符】 @interface 注解名{【成员列表】
}
  • 自定义注解可以通过四个元注解@Retention,@Target,@Inherited,@Documented,分别说明它的声明周期,使用位置,是否被继承,是否被生成到API文档中。
  • Annotation 的成员在 Annotation 定义中以无参数有返回值的抽象方法的形式来声明,我们又称为配置参数。返回值类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上所有类型的数组
  • 可以使用 default 关键字为抽象方法指定默认返回值
  • 如果定义的注解含有抽象方法,那么使用时必须指定返回值,除非它有默认值。格式是“方法名 = 返回值”,如果只有一个抽象方法需要赋值,且方法名为value,可以省略“value=”,所以如果注解只有一个抽象方法成员,建议使用方法名value。
import java.lang.annotation.*;@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {String value();
}
import java.lang.annotation.*;@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {String columnName();String columnType();
}
4.5.2 使用自定义注解
@Table("t_stu")
public class Student {@Column(columnName = "sid",columnType = "int")private int id;@Column(columnName = "sname",columnType = "varchar(20)")private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +'}';}
}
4.5.3 读取和处理自定义注解

自定义注解必须配上注解的信息处理流程才有意义。

我们自己定义的注解,只能使用反射的代码读取。所以自定义注解的声明周期必须是RetentionPolicy.RUNTIME。

补充:理解main方法的语法

由于JVM需要调用类的main()方法,所以该方法的访问权限必须是public,又因为JVM在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。

又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在之前的例子中多次碰到。

命令行参数用法举例

public class CommandPara {public static void main(String[] args) {for (int i = 0; i < args.length; i++) {System.out.println("args[" + i + "] = " + args[i]);}}
}
//运行程序CommandPara.java
java CommandPara "Tom" "Jerry" "Shkstart"
//输出结果
args[0] = Tom
args[1] = Jerry
args[2] = Shkstart

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/265138.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用xshell连接虚拟机(服务器)

作者&#xff1a;余小小 Xshell Xshell [1] 是一个强大的安全终端模拟软件&#xff0c;它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。 Xshell可以…

neuq-acm预备队训练week 8 P8794 [蓝桥杯 2022 国 A] 环境治理

题目描述 输入格式 输出格式 输出一行包含一个整数表示答案。 输入输出样例 解题思路 最短路二分 AC代码 #include<bits/stdc.h> using namespace std; long long temp,n, Q; long long f[105][105],min_f[105][105],cut[105],dis[105][105];//cut为减少多少&#x…

mapstruct个人学习记录

mapstruct核心技术学习 简介入门案例maven依赖 IDEA插件单一对象转换测试结果 mapping属性Spring注入的方式测试 集合的映射set类型的映射测试map类型的映射测试 MapMappingkeyDateFormatvalueDateFormat 枚举映射基础入门 简介 在工作中&#xff0c;我们经常要进行各种对象之…

Sql Server关于表的建立、修改、删除

表的创建&#xff1a; &#xff08;1&#xff09;在“对象资源管理器”面板中展开“数据库”节点&#xff0c;可以看到自己创建的数据库&#xff0c;比如Product。展开Product节点&#xff0c;右击“表”节点&#xff0c;在弹出的快捷菜单中选择“新建表”项&#xff0c;进入“…

JMS(Java Message Service)使用指南

介绍 JMS即Java消息服务&#xff08;Java Message Service&#xff09;应用程序接口&#xff0c;是一个Java平台中关于面向消息中间件&#xff08;MOM&#xff09;的API&#xff0c;用于在两个应用程序之间&#xff0c;或分布式系统中发送消息&#xff0c;进行异步通信。它是一…

SwinIR: Image Restoration Using Swin Transformer

SwinIR 简介 论文地址&#xff1a;SwinIR: Image Restoration Using Swin Transformer 代码&#xff1a;SwinIR ​ 本文提出了一个基于swin transformer的图像超分模型swinIR。其中SwinIR分为三部分&#xff1a;浅层特征提取、深层特征提取和高质量图像重建模块。 现阶段问…

【C++11(三)】智能指针详解--RAII思想循环引用问题

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; C11 1. 前言2. 为什么要有智能指针?3. RAII思想…

使用Python提取PDF文件中指定页面的内容

在日常工作和学习中&#xff0c;我们经常需要从PDF文件中提取特定页面的内容。在本篇文章中&#xff0c;我们将介绍如何使用Python编程语言和两个强大的库——pymupdf和wxPython&#xff0c;来实现这个任务。 1. 准备工作 首先&#xff0c;确保你已经安装了以下两个Python库&…

保姆级 | XSS Platform环境搭建

0x00 前言 XSS Platform 平台主要是用作验证跨站脚本攻击。该平台可以部署在本地或服务器环境中。我们可以使用 XSS Platfrom 平台搭建、学习或验证各种类型的 XSS 漏洞。 0x01 环境说明 HECS(云耀云服务器)xss platformUbuntu 22.04Nginx 1.24.0MySQL 5.6.51Pure-Ftpd 1.0.49…

LeetCode力扣每日一题(Java):35、搜索插入位置

一、题目 二、解题思路 1、我的思路&#xff08;又称&#xff1a;论API的重要性&#xff09; 读完题目之后&#xff0c;我心想这题目怎么看着这么眼熟&#xff1f;好像我之前学过的一个API呀&#xff01; 于是我回去翻了翻我之前写的博客&#xff1a;小白备战蓝桥杯&#xf…

Draw.io or diagrams.net 使用方法

0 Preface/Foreword 在工作中&#xff0c;经常需要用到框图&#xff0c;流程图&#xff0c;时序图&#xff0c;等等&#xff0c;draw.io可以完成以上工作。 official website:draw.io 1 Usage 1.1 VS code插件 draw.io可以扩展到VS code工具中。

Python自动化:selenium常用方法总结

使用的Python版本为3.8&#xff0c;selenium版本为4.15.2 Python自动化:selenium常用方法总结 1. 三种等待方式2. 浏览器操作3. 8种查找元素的方法4. 高级事件 1. 三种等待方式 强制等待 使用模块time下的sleep()实现等待效果隐式等待 使用driver.implicitly_wait()方法&#…