静态域与静态方法

静态域

如果将域定义为 static, 每个类中只有一个这样的域。而每一个对象对于所有的实例域 却都有自己的一份拷贝。例如, 假定需要给每一个雇员賦予唯一的标识码。这里给 Employee 类添加一个实例域 id 和一个静态域 nextld:

class Employee { 
    
private static int nextld = 1 ;
    
private int id;
    
...
}

 

现在, 每一个雇员对象都有一个自己的 id 域, 但这个类的所有实例将共享一个 iiextld 域。

静态常量

静态变量使用得比较少,但静态常量却使用得比较多。例如, 在 Math类中定义了一个 静态常量:

public class Hath {
​
...
​
public static final double PI = 3.14159265358979323846;
​
...
​
}

 

如果关键字 static 被省略, PI 就变成了 Math 类的一个实例域。需要通过 Math类的对象 访问 PI,并且每一个 Math 对象都有它自己的一份 PI 拷贝。 另一个多次使用的静态常量是 System.out。它在 System 类中声明:

public class System { 
​
...
​
public static final PrintStream out = . . .; 
​
...
}

 

由于每个类对象都可以对公有域进行修改,所以,最好不要将域设计 为 public。然而, 公有常量(即 final 域)却没问题。因为 out 被声明为 final, 所以,不允许 再将其他打印流陚给它:

System.out = new PrintStrean(. . . ); // Error out is final

 

System.out的源码

public static final PrintStream out = null;

 

[注]  如果查看一下 System 类, 就会发现有一个 setOut 方法, 它可以将 System.out 设 置为不同的流。 读者可能会感到奇怪, 为什么这个方法可以修改 final 变量的值。原因在 于,setOut 方法是一个本地方法, 而不是用 Java 语言实现的。本地方法可以绕过 Java 语 言的存取控制机制。这是一种特殊的方法, 在自己编写程序时, 不应该这样处理。
public static void setOut(PrintStream out) {
        checkIO();
        setOut0(out);
    }

 

静态方法

静态方法是一种不能向对象实施操作的方法。例如, Math类的 pow 方法就是一个静态方法。表达式

Math.pow(x, a)

计算幂 x^a 在运算时, 不使用任何 Math 对象。换句话说,没有隐式的参数。

可以认为静态方法是没有 this 参数的方法(在一个非静态的方法中,this参数表示这个方法的隐式参数

[注]  可以使用对象调用静态方法。 例如, 如果 harry 是一个 Employee 对象, 可以用 harry.getNextId( ) 代替 Employee.getNextId( )。不过,这种方式很容易造成混淆,其原因 是 getNextld 方法计算的结果与 harry 毫无关系。我们建议使用类名, 而不是对象来调用 静态方法。
public static int getNextld(){
​
 return nextld; // returns static field
​
 } 

 

在下面两种情况下使用静态方法:

•一 方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如: Math.pow) 。

•一个方法只需要访问类的静态域(例如:Employee.getNextldh)

工厂方法

已经见过工厂方法 LocalDate.now 和 LocalDate.of;

NumberFormat 类如下使用工厂方法生成不同风格的格式化对象:

NumberFormat currencyFormatter = NumberFormat.getCurrencylnstance();
​
NumberFormat percentFormatter = NumberFormat.getPercentlnstance();
​
double x = 0.1 ; System.out.println(currencyFormatter.format(x)); // prints SO.10 
System.out.println(percentFomatter.format(x)); // prints 10% 

 

为什么 NumberFormat 类不利用构造器完成这些操作呢? 这主要有两个原因:

•无法命名构造器。构造器的名字必须与类名相同。但是, 这里希望将得到的货币实例 和百分比实例采用不用的名字。

•当使用构造器时,无法改变所构造的对象类型。而 Factory方法将返回一个 DecimalFormat 类对象,这是 NumberFormat 的子类。

main方法

main方法也是一个静态方法。

public class Application { 
​
public static void main(String[] args) { 
​
// construct objects here
​
. . .
    }
} 

 

main方法不对任何对象进行操作。事实上,在启动程序时还没有任何一个对象。静态的 main方法将执行并创建程序所需要的对象。

[注]  每一个类可以有一个 main 方法。这是一个常用于对类进行单元测试的技巧。

Employee 类的一个简单版本, 其中有一个静态域 nextld 和一个静态方法 getNextld 这里将5个 Employee 对象写人数组, 然后打印雇员信息。最后, 打印出下一个可用的员T标识码来展示静态方法。

/**
 * This program demonstrates static methods.
 * @version 1.01 2004-02-19
 * @author Cay Horstmann
 */
public class StaticTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      Employee[] staff = new Employee[3];
​
      staff[0] = new Employee("Tom", 40000);
      staff[1] = new Employee("Dick", 60000);
      staff[2] = new Employee("Harry", 65000);
​
      // print out information about all Employee objects
      for (Employee e : staff)
      {
         e.setId();
         System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
               + e.getSalary());
      }
​
      int n = Employee.getNextId(); // calls static method
      System.out.println("Next available id=" + n);
   }
}
​
class Employee
{
   private static int nextId = 1;
​
   private String name;
   private double salary;
   private int id;
​
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
      id = 0;
   }
​
   public String getName()
   {
      return name;
   }
​
   public double getSalary()
   {
      return salary;
   }
​
   public int getId()
   {
      return id;
   }
​
   public void setId()
   {
      id = nextId; // set id to next available id
      nextId++;
   }
​
   public static int getNextId()
   {
      return nextId; // returns static field
   }
​
   public static void main(String[] args) // unit test
   {
      Employee e = new Employee("Harry", 50000);
      System.out.println(e.getName() + " " + e.getSalary());
   }
}
​

 

需要注意,Employee 类也有一个静态的 main 方法用于单元测试。试试运行

java Employee java StaticTest

执行两个 main方法。

 

方法参数

按 值调用(call by value) 表示方法接收的是调用者提供的值。而按引用调用 (call by reference) 表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而 不能修改传递值调用所对应的变量值。

Java 程序设计语言总是采用按值调用。也就是说, 方法得到的是所有参数值的一个拷 贝,特别是,方法不能修改传递给它的任何参数变量的内容。 例如, 考虑下面的调用:

double percent = 10;
harry.raiseSalary(percent);

 

不必理睬这个方法的具体实现, 在方法调用之后, percent 的值还是 10。

如果 Java 对对象采用的是按引用调用,那么这个方法就应该能够实现交换数据的效果:

Employee a = new Employee("Alice", .. .); 
​
Employee b = new Employee("Bob", . ..); 
​
swap(a, b); // does a now refer to Bob, b to Alice? 

 

但是,方法并没有改变存储在变量 a 和 b 中的对象引用。swap 方法的参数 x 和 y 被初始 化为两个对象引用的拷贝,这个方法交换的是这两个拷贝。

下面总结一下 Java中方法参数的使用情况:

•一个方法不能修改一个基本数据类型的参数(即数值型或布尔型) 。

•一个方法可以改变一个对象参数的状态。

•一个方法不能让对象参数引用一个新的对象。

[注]  C++ 有值调用和引用调用。 引用参数标有 & 符号。 例如, 可以轻松地实现 void tripleValue(double& x) 方法或 void swap(Employee& x, Employee& y) 方法实现修改 它们的引用参数的目的。
/**
 * This program demonstrates parameter passing in Java.
 * @version 1.00 2000-01-27
 * @author Cay Horstmann
 */
public class ParamTest
{
   public static void main(String[] args)
   {
      /*
       * Test 1: Methods can't modify numeric parameters
       */
      System.out.println("Testing tripleValue:");
      double percent = 10;
      System.out.println("Before: percent=" + percent);
      tripleValue(percent);
      System.out.println("After: percent=" + percent);
​
      /*
       * Test 2: Methods can change the state of object parameters
       */
      System.out.println("\nTesting tripleSalary:");
      Employee harry = new Employee("Harry", 50000);
      System.out.println("Before: salary=" + harry.getSalary());
      tripleSalary(harry);
      System.out.println("After: salary=" + harry.getSalary());
​
      /*
       * Test 3: Methods can't attach new objects to object parameters
       */
      System.out.println("\nTesting swap:");
      Employee a = new Employee("Alice", 70000);
      Employee b = new Employee("Bob", 60000);
      System.out.println("Before: a=" + a.getName());
      System.out.println("Before: b=" + b.getName());
      swap(a, b);
      System.out.println("After: a=" + a.getName());
      System.out.println("After: b=" + b.getName());
   }
​
   public static void tripleValue(double x) // doesn't work
   {
      x = 3 * x;
      System.out.println("End of method: x=" + x);
   }
​
   public static void tripleSalary(Employee x) // works
   {
      x.raiseSalary(200);
      System.out.println("End of method: salary=" + x.getSalary());
   }
​
   public static void swap(Employee x, Employee y)
   {
      Employee temp = x;
      x = y;
      y = temp;
      System.out.println("End of method: x=" + x.getName());
      System.out.println("End of method: y=" + y.getName());
   }
}
​
class Employee // simplified Employee class
{
   private String name;
   private double salary;
​
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }
​
   public String getName()
   {
      return name;
   }
​
   public double getSalary()
   {
      return salary;
   }
​
   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }
}
 

对象构造

重载

有些类有多个构造器。例如, 可以如下构造一个空的 StringBuilder 对象:

StringBuilder messages = new StringBuilder(); 

或者, 可以指定一个初始字符串:

StringBuilder todoList = new StringBuilder("To do:\n");

这种特征叫做重载(overloading)。如果多个方法(比如, StringBuilder 构造器方法)有 相同的名字、不同的参数,便产生了重载。

Java 允许重载任何方法, 而不只是构造器方法。因此,要完整地描述一个方法, 需要指出方法名以及参数类型。这叫做方法的签名(signature)。例如, String 类有 4 个 称为 indexOf 的公有方法。它们的签名是

indexOf(int) 
​
indexOf(int, int) 
​
indexOf(String) 
​
indexOf(String, int)

返回类型不是方法签名的一部分。也就是说, 不能有两个名字相同、 参数类型也相 同却返回不同类型值的方法。

默认域初始化

如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值: 数值为 0、 布尔值为 false、 对象引用为null。

[注]  这是域与局部变量的主要不同点。必须明确地初始化方法中的局部变量。 但是, 如果没有初始化类中的域, 将会被自动初始化为默认值(0、false 或 null)。

 

 

无参数的构造器

很多类都包含一个无参数的构造函数,对象由无参数构造函数创建时, 其状态会设置为 适当的默认值。 例如, 以下是 Employee 类的无参数构造函数:

public Employee() { 
​
name = salary = 0; 
​
hireDay = LocalDate.now(); 
​
} 

 

如果在编写一个类时没有编写构造器, 那么系统就会提供一个无参数构造器。这个构造 器将所有的实例域设置为默认值。于是, 实例域中的数值型数据设置为 0、 布尔型数据设置 为 false、 所有对象变量将设置为 null。

如果类中提供了至少一个构造器, 但是没有提供无参数的构造器, 则在构造对象时如果 没有提供参数就会被视为不合法。

请记住,仅当类没有提供任何构造器的时候, 系统才会提供一个默认的构造器 如果在编写类的时候, 给出了一个构造器, 哪怕是很简单的, 要想让这个类的用户能够 采用下列方式构造实例: new ClassNameO 就必须提供一个默认的构造器 (即不带参数的构造器) 。 当然, 如果希望所有域被赋 予默认值, 可以采用下列格式:

public ClassName()

显式域初始化

通过重载类的构造器方法,可以采用多种形式设置类的实例域的初始状态。

可以在类定义中, 直接将一个值赋给任何域。例如:

class Employee{
​
 private String name ="";
​
. . .
​
}

 

在执行构造器之前,先执行赋值操作。当一个类的所有构造器都希望把相同的值赋予某 个特定的实例域时,这种方式特别有用。

参数名

在编写很小的构造器时(这是十分常见的), 常常在参数命名上出现错误。 通常, 参数用单个字符命名:

public Employee(String n, double s){
​
    name=n;
​
    salary = s;
​
}

 

但这样做有一个缺陷:只有阅读代码才能够了解参数 n 和参数 s 的含义。 有些程序员在每个参数前面加上一个前缀“ a”:

public Employee(String aNaie, double aSalary) { 
​
name = aName; 
​
salary = aSalary; 
​
} 

 

还一种常用的技巧,它基于这样的事实:参数变量用同样的名字将实例域屏蔽起来。 例 如,如果将参数命名为 salary, salary将引用这个参数, 而不是实例域。 但是,可以采用 this, salary 的形式访问实例域。回想一下,this 指示隐式参数, 也就是所构造的对象。下面是一个 示例:

public Employee(String naie, double salary) { 
​
this.name = name;
​
 this,salary = salary;
​
 } 

 

初始化块

前面已经讲过两种初始化数据域的方法:

•在构造器中设置值

•在声明中赋值

实际上,Java 还有第三种机制, 称为初始化块(initializationblock)。在一个类的声明中, 可以包含多个代码块。只要构造类的对象,这些块就会被执行。

class Employee { 
    
    private static int nextld;
​
    private int id; 
    private String name; 
    private double salary;
​
    // object initialization block 
    { 
        id = nextld; 
        nextld++;
    }
​
    public Employee(String n, double s){
        salary = s;
    }
​
    public Employee() { 
        name = "";
        salary = 0;
    }
    . . .
}

 

在这个示例中,无论使用哪个构造器构造对象,id 域都在对象初始化块中被初始化。首 先运行初始化块,然后才运行构造器的主体部分。

由于初始化数据域有多种途径,所以列出构造过程的所有路径可能相当混乱。下面是调 用构造器的具体处理步骤:

1 ) 所有数据域被初始化为默认值(0、false 或 null)。

2 ) 按照在类声明中出现的次序, 依次执行所有域初始化语句和初始化块。

3 ) 如果构造器第一行调用了第二个构造器,则执行第二个构造器主体 。

4 ) 执行这个构造器的主体。

 

下面程序讨论了许多特性:

•重载构造器

•用 this(...) 调用另一个构造器

•无参数构造器

•对象初始化块

•静态初始化块

•实例域初始化

import java.util.*;
​
/**
 * This program demonstrates object construction.
 * @version 1.01 2004-02-19
 * @author Cay Horstmann
 */
public class ConstructorTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      Employee[] staff = new Employee[3];
​
      staff[0] = new Employee("Harry", 40000);
      staff[1] = new Employee(60000);
      staff[2] = new Employee();
​
      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
               + e.getSalary());
   }
}
​
class Employee
{
   private static int nextId;
​
   private int id;
   private String name = ""; // instance field initialization
   private double salary;
  
   // static initialization block
   static
   {
      Random generator = new Random();
      // set nextId to a random number between 0 and 9999
      nextId = generator.nextInt(10000);
   }
​
   // object initialization block
   {
      id = nextId;
      nextId++;
   }
​
   // three overloaded constructors
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }
​
   public Employee(double s)
   {
      // calls the Employee(String, double) constructor
      this("Employee #" + nextId, s);
   }
​
   // the default constructor
   public Employee()
   {
      // name initialized to ""--see above
      // salary not explicitly set--initialized to 0
      // id initialized in initialization block
   }
​
   public String getName()
   {
      return name;
   }
​
   public double getSalary()
   {
      return salary;
   }
​
   public int getId()
   {
      return id;
   }
}
 

对象析构与 finalize 方法

有些面向对象的程序设计语言,特别是 C++, 有显式的析构器方法,其中放置一些当对 象不再使用时需要执行的清理代码。在析构器中, 最常见的操作是回收分配给对象的存储空 间。由于 Java 有自动的垃圾回收器,不需要人工回收内存, 所以 Java 不支持析构器。

可以为任何一个类添加 finalize 方法。finalize 方法将在垃圾回收器清除对象之前调用。 在实际应用中,不要依赖于使用 finalize 方法回收任何短缺的资源, 这是因为很难知道这个 方法什么时候才能够调用。

[注]  有个名为 System.mnFinalizersOnExit(true) 的方法能够确保 finalizer 方法在 Java 关 闭前被调用。不过,这个方法并不安全,也不鼓励大家使用。有一种代替的方法是使用

 

Java 允许使用包(package> 将类组织起来。借助于包可以方便地组织自己的代码,并将 自己的代码与别人提供的代码库分开管理。

 

类的导入

一个类可以使用所属包中的所有类, 以及其他包中的公有类(public class)。我们可以 采用两种方式访问另一个包中的公有类。第一种方式是在每个类名之前添加完整的包名。 例如:

java.time.LocalDate today = java.time.LocalDate.now(); 

 

这显然很繁琐。更简单且更常用的方式是使用 import 语句。import 语句是一种引用包含 在包中的类的简明描述。

可以使用 import 语句导人一个特定的类或者整个包。import 语句应该位于源文件的顶部 (但位于 package语句的后面)。例如, 可以使用下面这条语句导人 java.util 包中所有的类。

import java.util.*; 

 

然后, 就可以使用

LocalDate today = LocalDate.now();

 

而无须在前面加上包前缀。

 

静态导入

import 语句不仅可以导人类,还增加了导人静态方法和静态域的功能。 例如,如果在源文件的顶部, 添加一条指令:

import static java.lang.System.*; 

 

就可以使用 System类的静态方法和静态域,而不必加类名前缀:

out.println("Goodbye, World!"); //i.e.,
​
 System.out exit⑼; //i.e., System.exit 

 

另外,还可以导入特定的方法或域:

import static java.lang.System.out; 

 

实际上,是否有更多的程序员采用 System.out 或 System.exit 的简写形式,似乎是一件值 得怀疑的事情。这种编写形式不利于代码的清晰度。不过,

sqrt(pow(x, 2) + pow(y, 2))

 

看起来比

Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) 

 

清晰得多。

将类放入包中

要想将一个类放人包中, 就必须将包的名字放在源文件的开头,包中定义类的代码之 前。例如,程序 Employee.java 开头是这样的:

package com.horstiann.corejava;
public class Employee{
​
. . .
​
}

 

如果没有在源文件中放置 package语句, 这个源文件中的类就被放置在一个默认包 ( defaulf package) 中。默认包是一个没有名字的包。在此之前,我们定义的所有类都在默认 包中。

PackageTest 类放置在默认包中; Employee 类放置在 com.horstmann.corejava 包中。因此, Employee.java 文件必须包含在子目 录 com/horstmann/ corejava 中。

import com.horstmann.corejava.*;
// the Employee class is defined in that package
import static java.lang.System.*;
​
/**
 * This program demonstrates the use of packages.
 * @version 1.11 2004-02-19
 * @author Cay Horstmann
 */
public class PackageTest
{
   public static void main(String[] args)
   {
      // because of the import statement, we don't have to use com.horstmann.corejava.Employee here
      Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);
​
      harry.raiseSalary(5);
​
      // because of the static import statement, we don't have to use System.out here
      out.println("name=" + harry.getName() + ",salary=" + harry.getSalary());
   }
}
​

 

包作用域

前面已经接触过访问修饰符 public 和 private。标记为public 的部分可以被任意的类使 用;标记为private 的部分只能被定义它们的类使用。如果没有指定 public 或 private, 这个部 分(类、方法或变量)可以被同一个包中的所有方法访问。

 

类路径

为了使类能够被多个程序共享,需要做到下面几点:

1 ) 把类放到一个目录中, 例如 /home/user/classdir。需要注意, 这个目录是包树状结构 的基目录。如果希望将 com.horstmann.corejava.Employee类添加到其中,这个 Employee.class 类文件就必须位于子目录 /home/user/classdir/com/horstmann/corejava中。

2 ) 将 JAR 文件放在一个目录中,例如:/home/user/archives。

3) 设置类路径(classpath)。类路径是所有包含类文件的路径的集合。 在UNIX 环境中, 类路径中的不同项目之间

采用冒号 ㈠ 分隔: /home/user/classdir:.:/home/user/archives/archive.jar

而在 Windows 环境中,则以分号(;)分隔:

c:\classdir;.;c:\archi»es\archive.jar

在上述两种情况中,句点(.)表示当前目录。

类路径包括:

•基目录 /home/user/classdir或 c:\classes;

•当前目录 (.);

•JAR 文件 /home/user/archives/archive.jar c:\archives\archive.jar。

从 Java SE 6 开始,可以在 JAR 文件目录中指定通配符,如下:

 /home/user/dassdir:.:/home/aser/archives/’*‘

或者

c:\classdir;.;c:\archives\*

但在 UNIX 中,禁止使用 * 以防止 shell 命令进一步扩展。

设置类路径

最好采用-classpath (或 -cp) 选项指定类路径: java -classpath /home/user/dassdir:.:/home/user/archives/archive.jar HyProg 或者 java -classpath c:\classdir;.;c:\archives\archive.jar MyProg

整个指令应该书写在一行中。将这样一个长的命令行放在一个 shell 脚本或一个批处理文 件中是一个不错的主意。

利用-dasspath选项设置类路径是首选的方法, 也可以通过设置 CLASSPATH 环境变量 完成这个操作。其详细情况依赖于所使用的 shell。在 Bourne Again shell ( bash) 中, 命令格 式如下:

export CLASSPATH=/home/user/classdir:.:/home/user/archives/archive.jar

在 Windows shell, 命令格式如下: s

et CLASSPATH=c:\classdir;.;c:\archives\archive.jar

直到退出 shell 为止,类路径设置均有效。

 

文档注释

JDK 包含一个很有用的工具,叫做javadoc, 它可以由源文件生成一个 HTML 文档。

如果在源代码中添加以专用的定界符 /**开始的注释, 那么可以很容易地生成一个看上 去具有专业水准的文档。这是一种很好的方式,因为这种方式可以将代码与注释保存在一个 地方。

 

注释的插入

javadoc 实用程序(utility) 从下面几个特性中抽取信息:

•包

•公有类与接口

•公有的和受保护的构造器及方法

•公有的和受保护的域

每个 /** . . . */ 文档注释在标记之后紧跟着自由格式文本(free-form text)。标记由@开 始, 如@author 或@param。

自由格式文本的第一句应该是一个概要性的句子。javadoc 实用程序自动地将这些句子抽 取出来形成概要页。

在自由格式文本中,可以使用 HTML 修饰符, 例如,用于强调的 <em>...</eitf>、 用于 着重强调的 <strong>...</stroiig> 以及包含图像的 <img ..•> 等。不过,一定不要使用 <hl><hr>, 因为它们会与文档的格式产生冲突。

[注]  如果文档中有到其他文件的链接, 例如, 图像文件(用户界面的组件的图表或图 像等) , 就应该将这些文件放到子目录 doc-files 中。javadoc 实用程序将从源目录拷贝这 些目录及其中的文件到文档目录中。在链接中需要使用 doc-files 目录, 例如:<img src= “ doc-files/uml_png” alt=“ UML diagram” >。

 

类注释

类注释必须放在 import 语句之后,类定义之前。

没有必要在每一行的开始用星号 *, 例如, 以下注释同样是合法的:

/**

A Card object represents a playing card, such

as "Queen of Hearts". A card has a suit (Diamond, Heart,

Spade or Club) and a value (1 = Ace, 2 . . . 10, 11 = jack,

12 = Queen, 13 = King).

*/

然而, 大部分 IDE 提供了自动添加星号 *, 并且当注释行改变时, 自动重新排列这 些星号的功能。

 

方法注释

每一个方法注释必须放在所描述的方法之前。除了通用标记之外, 还可以使用下面的标记:

• @param 变量描述

这个标记将对当前方法的“ param” (参数)部分添加一个条目。这个描述可以占据多 行, 并可以使用 HTML 标记。一个方法的所有@param 标记必须放在一起。

• @return 描述

这个标记将对当前方法添加“ return” (返回)部分。这个描述可以跨越多行, 并可以 使用 HTML 标记。

• @throws 类描述

这个标记将添加一个注释, 用于表示这个方法有可能抛出异常。

 

域注释

只需要对公有域(通常指的是静态常量)建立文档。例如,

/**

The "Hearts" card suit

*/

public static final int HEARTS = 1 ;

 

通用注释

下面的标记可以用在类文档的注释中。

•eauthor 姓名

这个标记将产生一个 ** author" (作者)条目。可以使用多个@aUthor 标记,每个@ author 标记对应一个作者 參 ©version 这个标记将产生一个“ version”(版本)条目。这里的文本可以是对当前版本的任何描 述。 下面的标记可以用于所有的文档注释中。

•@sinee 文本

这个标记将产生一个“ since” (始于)条目。这里的 text 可以是对引人特性的版本描 述。例如,@since version 1.7.10

•@deprecated文本

这个标记将对类、方法或变量添加一个不再使用的注释。文本中给出了取代的建议。 例如, @deprecated Use  setVIsible(true) instead 通过@see 和@link标记,可以使用超级链接, 链接到 javadoc 文档的相关部分或外 部文档。

•®see 引用

这个标记将在“ see also” 部分增加一个超级链接。它可以用于类中,也可以用于方 法中。

 

包与概述注释

可以直接将类、方法和变量的注释放置在 Java 源文件中,只要用 /** . . . */ 文档注释界 定就可以了。但是, 要想产生包注释,就需要在每一个包目录中添加一个单独的文件。可以 有如下两个选择:

1 ) 提供一个以 package.html 命名的 HTML 文件。在标记 <body></body> 之间的所有 文本都会被抽取出来。

2 ) 提供一个以 package-info.java命名的 Java 文件。这个文件必须包含一个初始的以 /** 和 */ 界定的 Javadoc 注释, 跟随在一个包语句之后。它不应该包含更多的代码或注释。

 

注释的抽取

这里,假设 HTML 文件将被存放在目录 docDirectory 下。执行以下步骤:

1 ) 切换到包含想要生成文档的源文件目录。如果有嵌套的包要生成文档, 例如 com. horstmann.corejava, 就必须切换到包含子目录 com 的目录(如果存在 overview.html 文件的 话, 这也是它的所在目录)。

2 ) 如果是一个包,应该运行命令:

javadoc -d docDirectory nameOfPackage

或对于多个包生成文档,运行:

javadoc -d docDirectory nameOfPackage\ nameOfPackage ...

如果文件在默认包中, 就应该运行:

javadoc -d docDirectory *.java

如果省略了 -d docDirectory 选项, 那 HTML 文件就会被提取到当前目录下。这样有可能 会带来混乱,因此不提倡这种做法。

[注]  如果需要进一步的定制,例如, 生成非 HTML 格式的文档, 可以提供自定义的 doclet, 以便生成想要的任何输出形式。显然, 这是一种特殊的需求, 有关细节内容请查 阅 http://docs.oracle.com/javase/8/docs/guides/javadoc/doclet/overview.html 的联机文档。

类设计技巧

简单地介绍几点技巧,应用这些技巧可以使得设计出来的类更具有 OOP 的专业水准。

  1. 一定要保证数据私有

  2. 一定要对数据初始化

  3. 不要在类中使用过多的基本类型

  4. 不是所有的域都需要独立的域访问器和域更改器

  5. 将职责过多的类进行分解

  6. 类名和方法名要能够体现它们的职责

  7. 优先使用不可变的类

posted on 2020-08-07 21:33  ♌南墙  阅读(181)  评论(0)    收藏  举报