Java注释
Java中的注释不会出现在可执行程序中。
Java中为我们提供了3种注释:
// 单行注释:其注释内容从//开始到本行结尾。
/**/多行注释:/*注释内容在此处写*/ 多行注释。
/***/文档注释:注释以/**开始,以*/结束。可以用来自动生成文档。
下面注重来讲文档注释
文档注释
注释以/**开始,以*/结束。可以用来自动生成文档。
JDK包含一个很有用的工具,叫做javadoc,它可以生成一个HTML文档。
比如联机的API文档就是通过对标准Java类库的源代码运行javadoc生成的。
可以直接将类、方法和变量的注释放置在java源文件中,只要用/**...*/文档注释就可以。
如果编写Java源代码时添加了合适的文档注释,然后通过JDK提供的javadoc工具可以直接将源代码里的文档注释提取成一份系统的API文档。
API文档
1,API文档是什么?
开发一个大型软件时,需要定义上千万个类,并且可能由多个程序员来开发这个软件,每个人都会定义一些类,并在这个类里定义方法、属性提供给他人使用,但其他人怎么知道如何使用呢?这时候急需要提供一份说明文档,用于说明每个类、每个方法的用途。当其他人使用一个类或方法时,他无须关心这个类或这个方法的具体实现,只要知道这个类或这个方法的功能即可,然后使用这个类或方法来实现具体的目的,也就是通过调用应用程序接口(API)来编程。API文档就是以说明这些应用程序接口的文档。对于Java语言而言,API文档通常详细说明了每个类、每个方法的功能,用法等。
2,下载JDK的API文档
(1)登录:http://java.sun.com/javase/downloads/index.jsp站点,下载”Java SE 8
Documentation“项,通过该下载项下载Java SE 6文档,这份文档里包含了JDK的
API文档。下载成功后得到一个jdk-6-doc.zip文件。
(2)将jdk-6-doc.zip文件加压到任意路径,将得到一个docs文件夹。这个文件夹内
就是JDK文档,JDK文档不仅包含API文档,还包含了JDK的其他说明文档,如果直接打开
docs文件夹下的index.xml文件。
API文档页面被分成3个部分,左上角部分是API文档“包列表区”,在该区域内可以查看Java基类的所有包;左下角是API稳定啊的“类列表区”,用于查看Java基类的所有类;右边页面是“详细说明区”,默认显示的是各包空间的说明信息。
我们在开发中定义类、方法时也可以先添加文档注释,然后使用javadoc工具来生成自己的API文档。
3,我们要掌握查看API文档的方法的原因?
API是Java提供的基库编程接口,当使用Java语言进行编程时,不可能把所有的Java类、所有的方法全部记录下来,那么当我们遇到不确定的地方时,必须通过API文档来查看某个类、某个方法的功能和用法。掌握查看API文档是学习Java的一个最基本的技能。
由于文档注释是用于生成API文档,而API文档主要用于说明类、方法、属性的功能。
javadoc工具默认只处理以public或protected修饰的类、接口、方法、属性、构造器
之前的文档注释,忽略其他地方的文档注释。
如果开发者希望javadoc工具可以提取private的内容,则可以在使用javadoc工具时
增加-private选项。
4,javadoc的常用选项:
-d<directory>:
该选项指定一个路径,用于将生成的API文档放到指定目录下。
-windowtitle<text>:
该选项指定一个字符串,用于设置API文档的浏览器窗口标题。
doctitle<html-code>:
该选项制定一个HTML格式文本,用于指定概述页面的标题。
注意:一定要对处于多个包下的源文件来生成API文档,才有概述页面。
-header<html-code>:该选项指定一个HTML格式的文本,包含每个页面的页眉。
读者可以使用javadoc-help来查看javadoc命令的所有选项。
6,常用的javadoc标记:
@author:指定Java程序的作者
@version:指定源文件的版本
@deprecated:不推荐使用的方法
@param:方法的参数的说明信息
@return:方法的返回值的说明信息
@see:“参见”,用于指定交叉参考的内容
@exception:抛出异常的类型
@throws:抛出异常,和exception同义。
标记的使用是有位置限制的
可以出现在类或借口文档注释中的有:
@see、@deprecated、@author、@version等。
可以出现在方法或构造器中的:
@see、@deprecated、@param、@return、@throws和@exception等。
可以出现在属性文档注释的有:
@see、@deprecated等。
文档注释注重点
1,注释的插入:
包
公有类与接口
公有的的和受保护的方法
公有的和受保护的域
注意:
每个/**...*/文档注释在标记之后紧跟着自由格式(free-form-text)。
标记由@开始,如@author或@param
自由格式文本的第一句应该是一个概要性的句子。javadoc实用程序自动地将这些句子抽取出来形成概要页。
在自由格式文本中可以使用HTML修饰符。
如果文档中有到其他文件的链接,例如图片,就应该将这些文件放到子目录doc-files中。javadoc实用程序将从源目录拷贝这些目录以及其中的文件到文档目录中。如:<img src="doc-files/uml.png" alt="UML diagram">
2,类注释:
类注释必须放在import语句之后,类定义之前。
注释没有必要在每一行的开始用星号*,
3,方法注释:
每一个方法注释必须放在所描述的方法之前。除了通用标记之外,还可以使用以下标记:
@param variable description
这个标记将对当前方法的“param”(参数)部分添加一个条目。这个描述可以占据多行,并使用HTML标记。一个方法的所有@param标记必须放在一起。
@return description
这个标记将对当前方法添加“return”(返回)部分。这个描述可以跨越多行,并可以使用HTML标记。
@throws class description
这个标记将添加一个注释,用于表示这个方法有可能抛出异常。
4,域注释
只需要对公有域(通常指的是静态常量)建立文档
5,通用注释:
@author name
这个标记将产生一个“author”(作者)条目。可以使用多个@author标记,
每个@author标记对应一名作者
@version text
这个标记将产生一个“version”(版本)条目。
text:可以是对当前版本的任何描述
@since text
这个标记将产生一个“since”(始于)条目
text:可以是对引入特性的版本描述。
例如:@since version 1.7.1
@deprecated test
这个标记将对类、方法或变量添加一个不再使用的注释。
text:给出了取代的建议
例如:@deprecated Use <code>SetVisible(true)</code> instead
@see reference
这个标记将在“see also”部分增加一个超级链接。它可以用于类中,也可以用于方法中。
(1)只要提供类、方法或变量的名字,javadoc就会在文档中插入一个超链接,例如:@see com.gaiwu.javanote.MyNoteUseing#raiseSalary(double),
建立一个链接到com.gaiwu.javanote.MyNoteUseing类的raiseSalary(double)
方法的超链接。
注意:当在当前包或当前类时,可以省略包名或包名和类名都省略掉。
(2)指定一个可选的标签作为锚链接,例如:@see <a href="www.horstan.com/corejava.html">The Core Java home page</a>
注意:也可以省略标签,用户看到的锚的名称就是目标代码名或URL
(3)如果@see 标记后面有一个双引号字符,文本就会显示在“see also”部分,
例如:@see “Core java 2volume 2”,可以为这特性添加多个@see标记,
但必须将他们放在一起。
(4)可以在注释中的任何位置放置指向其他类或方法的超级链接,
以及插入一个专用的标记,例如:@link package.class#feature label
6,包注释:
若需要产生包注释,就需要在每一个包目录中添加一个单独的文件。有两个选择:
(1)提供一个以package.html命名的HTML文件,在标记<body>...</body>
之间的所有文本都会被抽取出来。
(2)提供一个以package-info.java命名的Java文件。这个文件必须包含一个
初始的以/**和*/界定的javadoc注释,跟随在一个包语句之后。它不应该包含更多的代码或注释。
为所有的源文件提供一个概述性的注释。这个注释将被放置在一个名为overview.html的文件中,这个文件位于包含所有源文件的父目录中。标记<body></body>之间的所有文本将被抽取出来。当用户从导航栏中选择“Overview”时,就会显示出这些注释内容。
7,注释抽取:
假设将HTML文件将被存放在目录docDirectory下,执行如下命令:
(1)切换到包含想要生成文档的源文件目录。如果有嵌套的包要生成文档,例如com.horsetmann.core.java,就必须切换到包含子目录com的目录。
(2)如果是一个包,
运行命令:javadoc -d docDirectory nameOfPackage
或对于多个包生成文档,
运行:javadoc -d docDirectory nameOfPackage1 nameOfPackage2...
若文件在默认包中,
运行:javadoc -d docDirectory *.java
若省略了-d docDirectory 选项,那么HTML文件就会被提取到当前目录下。
这样有可能产生混乱,不提倡这样做,
http://java.sun.com/j2se/javadoc 联机文档
代码示例:
package com.gaiwu.javanote;
//类文档注释
/**
*
*
*
* */
public class MyNoteUseing {
//域文档注释
/**
* The "Hearts" card suit
* */
public static final int HEARTS = 1;
//方法文档注释
/**
* Raises the salary of an employee
* @param byPercent the percentage by with to raise the salary(e.g. 10=10%)
* @retuen the amount of the raise
* */
public double raiseSalary(double byPercent)
{
double salary = 0;
salary++;
double raise=salary*byPercent/100;
salary+=raise;
return raise;
}
/*
* 多行文本注释
* */
public static void main(String[] args) {
}
}
Annotation(注释)
Annotation必须使用工具来处理,工具负责提取Annotation里包含的元素,还可以根据这些元素增加额外的功能。
Java提供的三个基本Annotation的用法:
1,限定重写父类方法:@Override
@Override就是用来指定方法覆载的,它可以强制一个子类必须覆盖父类的方法。
@Override只能作用于方法,不能作用于其他程序元素。
代码示例:
public class Fruit
{
public void foo()
{
System.out.println("水果的info方法...");
}
}
class Apple extends Fruit
{
//使用@override指定下面方法必须重写父类方法
@Override
public void foo()
{
System.out.println("苹果重写水果的foo方法...");
}
}
从以上中可能丝毫看不出程序中的@Override有何作用,因为@Override Annotation的
作用是告诉编译器检查这个方法,并从弗雷查找是否包含一个被该方法重写的方法,否
则就编译出错。它主要是帮助我们避免一些低级错误,例如,我们把Apple类中的foo方
法不小心写成fio,这样的“低级错误”可能导致后期排错时的巨大障碍。
2,标记已过时:@Deprecated
@Deprecated用于表示某个程序元素(类、方法等)已过时,当其他程序使用已过时的类
、方法时,编译器将会出现警告。
代码示例:
public class Fruit
{
//定义info方法已过时
@Deprecated
public void foo()
{
System.out.println("水果的info方法...");
}
public static void main(String[] args)
{
//下面使用info方法时将会被编译器警告
new Apple().info();
}
}
@Deprecatted Annotation与文档注释中的@deprecated标记的作用基本相同,但它们的
用法不同,前者是JDK1.5才支持的注释,无须放在文档注释语法(/**...*/部分)中,
而是直接用于修饰程序中的程序单元,如类、方法、接口等。
3,抑制编译器警告:@SuppressWarnings
@SuppressWarnings指示被Annotation表示的程序元素取消显示指定的编译器警告。
代码示例:
//关闭整个类里的编译器警告
@SuppressWarnings(value="unchecked")
public class SuppressWarningsTest
{
public static void main(String[] args)
{
List<String> myList=new ArrayList();
}
}
自定义注释
代码示例:
//定义一个简单的Annotation类型
public @interface Test
{
}
使用Annotation时的语法非常类似于public、final这样的修饰符。通常可用于修饰程
序中的类、方法、变量、接口等定义,通常我们会把Annotation放在所有修饰符之前,
而且由于使用Annotation时可能还需要为其成员变量指定值,因而Annotation的长度可
能较长,所以通常把Annotation另放一行,如下程序所示:
//使用@Test修饰类dingyi
@Test
public class MyClass
{
...
}
默认情况下,Annotation可用于修饰任何程序元素,包括类、接口、方法等,如下程序
使用@TestAnnotation来修饰方法。
public class MyClass
{
//使用@testAnnotation修饰方法
@Test
public void info()
{
...
}
...
}
Annotation可以带成员变量,Annotation定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。如下代码所示:
public @interface MyTag
{
//定义了两个成员变量的Annotation
//Annotation中的成员变量以方法的形式来定义
//以defauly为两个成员变量指定初始值。
String name() default "lili";
int age() default 32;
}
public class Test
{
//使用带成员变量的Annotation时,需要为成员变量赋值
@MyTag(name="xx",age=6)
public void info()
{
}
}
根据Annotation是否可以包含成员变量,我们可以把Annotation分为两类:
1,标记Annotation:
一个没有成员定义的Annotation类型被称为标记。这种Annotation仅使用自身的存在与否来为我们提供信息。
2,元数据Annotation:
那些包含成员变量的Annotation,因为它们可接受更多元数据,所以被称为元数据Annotation。
提取Annotation的信息
java在java.lang.reflect包下新增了AnnotatedElement接口,该接口代表程序中可以接受注释的程序元素,该接口主要有如下几个实现类:
1,Class:类定义
2,Constructor:构造器定义
3,Field:类的成员变量定义。
4,Method:类的方法定义。
5,Package:类的包定义。
AnnotationElement接口是所有程序元素(如Class、Method、Constructor)的父接口,程序通过反射获取了某个类的AnnotationElement对象(如Class、Method、Constructor)之后,程序就可以调用该对象的如下三个方法来访问Annotation信息:
getAnnotation(Class<T> annotationClass):
返回改程序元素上存在的、指定类型的注释,如果该类型的注释不存在,则返回null。
Annotation[] getAnnotations():
返回该程序元素上存在的所有注释
boolean isAnnotationPresent(Class<? extends Annotation>annotationClass):
判断改程序元素上是否包含指定类型的注释,存在则返回true,否则返回false。
获取Test类的info方法里的所有注释,并将这些注释打印出来。
//获取Test类的info方法的所有注释
Annotation[] aArray=Class.forName("Test").getMethod("info").getAnnotations();
//遍历所有注释
for(Anotation an:aArray)
{
System.out.println(an);
}
如果我们需要获取某个注释里的元数据,则可以将注释强制类型转换成所需的注释类型,然后通过注释对象的抽象方法来访问这些元数据,代码如下所示:
//获取tt对象的info方法所包含的所有注释
Annotation[] annotation=tt.getClass().getMethod("info").getAnnotations();
//遍历每个注释对象
for(Annotation tag:annotation)
{
//如果注释类型是MyTagl类型
if(tag instanceof MyTag1)
{
System.out.println("Tag is:"+tag);
//将tag强制类型转换为MyTag1
//并调用tag对象的method1和method2两个方法
System.out.println("tag.name():"+(MyTag1)tag.method1);
System.out.println("tag.name():"+(MyTag1)tag.method2);
}
//如果注释类型是MyTag2
if(tag instanceof MyTag2)
{
System.out.println("Tag is:"+tag);
//将tag强制类型转换为MyTag2
//并调用tag对象的method1和method2两个方法
System.out.println("tag.name():"+(MyTag2)tag.method1);
System.out.println("tag.name():"+(MyTag2)tag.method2);
}
}
使用Annotation例子
JDK元Annotation
JDK在java.lang.annotation包下提供了四个Meta Annotation(元 Annotation),这四个Annotation都是用于修饰其他Annotation定义。
1,使用@Retention
@Retention只能用于修饰一个Annotation定义,用于指定该Annotation可以保罗多长时间。@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention必须为该value成员变量指定值,值只有如下三个:
RetentionPolicy.CLASS:编译器将把注释记录在class文件中。当运行Java程序时,JVM不再保留注释。这是默认值。
RetentionPolicy.RUNTIME:编译器将把注释记录在class文件中。当运行Java程序时,JVM也会保留注释,程序可以通过反射获取该注释。
Ret.SOUREC:编译器直接丢弃这种策略的注释。
代码示例:
//定义下面的Testable Annotation的保留到运行时
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Testable{}
或
//定义下面的Testable Annotation将被编译器直接丢弃
@Retention(RetentionPolicy.SOURCE)
public @interface Testable{}
注意:若我们定义的Annotation类型里只有一个value成员变量,使用该Annotation时可以直接在Annotation后的括号里指定value成员变量的值,无须使用name=value的形式。
2,使用@Target
@Target用于指定被修饰的Annotation能用于修饰哪些程序元素。@Target Annotation包含一个名为value的成员变量,成员变量的值只能是下面的几个:
ElementType.ANNOTATION_TYPE:
指定该策略的Annotation只能修饰Annotation。
ElementType.CONSTRUCTOR:
指定该策略的Annotation能修饰构造器。
ElementType.FIELD:
指定该策略的Annotation只能修饰成员变量。
ElementType.LOCAL_VARIABLE:
指定该策略的Annotation只能修饰局部变量。
ElementType.METHOD:
指定该策略的Annotation只能修饰方法定义。
ElementType.PACKAGE:
指定该策略的Annotation只能修饰包定义。
ElementType.PARAMETER:
指定该策略的Annotation可以修饰参数。
ElementType.TYPE:
指定该策略的Annotation可以修饰类、接口(包括注释类型)或枚举定义。
代码示例:
@Target(ElementType.FIELD)
public @interface ActionListenerFor{}
或
@Target(ElementType.METHOD)
public @interface Testable{}
3,使用@Documented
@Documented用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档,如果定义Annotation类时使用了@Documented修饰,则所有使用该Annotation修饰的程序元素的API文档中将会包含该Annotation说明。
代码定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
//定义Testable Annotation将被javadoc工具提取
@Documented
public @interface Testable{}
public class MyTest
{
//使用@Test修饰info方法
@Test
public void info()
{
System.out.println("info方法...");
}
}
4,使用@Inherited
@Inherited元Annotation指定被它修饰的Annotation将具有继承性:如果某个类使用了Annotation(定义该Annotation时使用了@Inherited修饰)修饰,则其子类将自动具有A注释。
代码示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Inheritable{}
//使用@Inheritable修饰的Base类
@Inheritable
class Base
{
}
//TestInheritable类只是继承了Base类。
//并未直接使用@Inheritable Annotation修饰
public class TestInheritable extends Base
{
public static void main(String[] args)
{
//打印TestInheritable类是否具有Inheritable Annotation
System.out.println(TestInHeritable.class.isAnnotationPresent(Inheritable.class));
}
}
输出结果为:true