Java 语言入门

Java 语言入门

目标

  • 认识 Java 语言中的保留字
  • 理解 Java 类与 Java 对象之间的关系。
  • 了解 Java 类中的每种结构的功能和语法
  • OOP 与对象密切相关。本单元介绍两个与 Java 语言如何处理对象紧密相关的主题:保留字和 Java 类的结构。

保留字

跟任何编程语言一样,Java 语言指定了一些编译器认为具有特殊含义的关键字。出于该原因,不允许您使用它们来命名您的 Java 结构。保留字(也称为关键字)非常少:

  • abstract
  • assert
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • cla
  • const
  • continue
  • default
  • do
  • double
  • else
  • enum
  • extend
  • final
  • finally
  • float
  • for
  • goto
  • if
  • implement
  • import
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • strictfp
  • super
  • switch
  • synchronized
  • thi
  • throw
  • throw
  • transient
  • try
  • void
  • volatile
  • while

您也不可以使用 true、false 和 null(技术上讲,它们是 字面常量 而不是关键字)来命名 Java 结构

稍后将会看到,使用 IDE 编程的一个优势是,它可以为保留字使用语法颜色。

Java 类的结构

类是一个包含属性和行为的离散实体(对象)的蓝图。类定义对象的基本结构,在运行时,您的应用程序会创建对象的实例。对象拥有明确定义的边界和状态,它可在被正确请求时执行操作。每种面向对象的语言都拥有有关如何定义类的规则。

在 Java 语言中,类的定义如 清单 1 所示:

清单 1. 类定义

package packageName;
import ClassNameToImport; 
accessSpecifier class ClassName {
  accessSpecifier dataType variableName [= initialValue];
  accessSpecifier ClassName([argumentList]) {
    constructorStatement(s)
  }
  accessSpecifier returnType methodName ([argumentList]) {
    methodStatement(s)
  }
  // This is a comment
  /* This is a comment too */
  /* This is a
     multiline
     comment */
}

清单 1 包含各种不同的结构类型,第 1 行是 package,第 2 行是 import,第 3 行是 class。这 3 种结构都属于 保留字,所以它们必须保持清单 1 中的准确格式。我为清单 1 中的其他结构提供的名称描述了它们表达的概念。

备注:在 清单 1 和本节的其他一些代码示例中,方括号表示它们之中的结构不是必需的。方括号(不同于 { 和 })不是 Java 语法的一部分。

可以注意到 清单 1 中的第 11 到 15 行是注释行。在大多数编程语言中,程序员都可添加注释来帮助描述代码。Java 语法允许单行和多行注释。

// This is a comment
/* This is a comment too */
/* This is a
multiline
comment */

单行注释必须包含在一行上,但您可使用邻近的单行注释来形成一个注释组。多行注释以 /* 开头,必须以 */ 终止,而且可以涵盖任意多行。

接下来,我将详细介绍 清单 1 中的结构,首先看看 package。

打包类

在 Java 语言中,您可选择类的名称,比如 Account、Person 或 LizardMan。有时,您可能最终使用了同一个名称来表达两个稍微不同的概念。这种情形称为名称冲突,经常会发生。Java 语言使用包 来解决这些冲突。

Java 包是一种提供命名空间 的机制— 名称在命名空间中是唯一的,但在其外部可能不是唯一的。要唯一地标识一个结构,您必须包含它的命名空间来完全限定它。

包也是利用多个离散功能单元来构造更复杂应用程序的不错方式。

要定义包,可使用 package 关键字,后跟一个合法的包名称,并以一个分号结尾。包名称常常遵循这种事实标准模式:

package  orgType.orgName.appName.compName;

这个包定义可分解为:

  • orgType 是组织类型,比如 com、org 或 net。
  • orgName 是组织的域名称,比如 makotojava、oracle 或 ibm。
  • appName 是缩写的应用程序名称。
  • compName 是组件的名称。

本课程将使用此约定,而且我推荐坚持使用它来定义包中的所有 Java 类。(Java 语言没有强制要求您遵循这种包约定。您完全不需要指定一个包,但在这种情况下,您的所有类必须具有唯一名称且将位于默认包中。)

导入语句

类定义中的下一部分(返回参考 清单 1)是导入语句。导入语句告诉 Java 编译器在何处查找您在代码中引用的类。任何非简单的类都会使用其他类来实现某种功能,导入语句是您向 Java 编译器告知这些类的方式。

Eclipse 使导入简化:在 Eclipse 编辑器中编写代码时,您可键入想要使用的类的名称,然后按 Ctrl+Shift+O。Eclipse 会确定您需要哪些导入语句并自动添加它们。如果 Eclipse 找到两个具有相同名称的类,它会询问您想为哪个类添加导入语句。

导入语句通常类似于:

import ClassNameToImport;

您指定 import 关键字,后跟您想要导入的类,然后输入一个分号。类名应是完全限定的,意味着名称中应包含它的包。

要导入一个包中的所有类,您可将 .* 放在包名称后。例如,这条语句导入 com.makotojava 包中的每个类:

import com.makotojava.*;

但是,导入整个包会降低代码的可读性,所以我推荐使用完全限定名称来仅导入需要的类。

类声明

要在 Java 语言中定义一个对象,必须声明一个类。可将类视为对象的模板,就像饼干模具一样。

清单 1 包含以下类声明:

accessSpecifier class ClassName {
  accessSpecifier dataType variableName [= initialValue];
    accessSpecifier ClassName([argumentList]) {
    constructorStatement(s)
  }
  accessSpecifier returnType methodName([argumentList]) {
    methodStatement(s)
  }
}

类的 accessSpecifier 可拥有多个值,但该值通常为 public。您很快会看到 accessSpecifier 的其他值。

可以将类命名为您想要的任何名称,但约定是使用驼峰式大小写:以一个大写字母开头,但将串联的每个单词的第一个字母大写,将所有其他字母小写。类名应仅包含字母和数字。坚持这些准则,可确保代码更容易供其他遵循相同约定的人使用。

变量和方法

类可拥有两种类型的成员—变量 和方法。

变量

类的变量的值可以区分该类的每个实例并定义它的状态。这些值常常称为实例变量。一个变量有:

  • 一个 accessSpecifier
  • 一个 dataType
  • 一个 variableName
  • 一个可选的 initialValue

可能的 accessSpecifier 值包括:

  • public:任何包中的任何对象都能看到该变量。(不要使用此值;请参阅公共变量边栏。)
  • protected:在同一个包中或(在任何包中定义的)一个子类中定义的任何对象都能看到此变量。
  • 没有修饰符(也称为友好 或包私有 访问):仅在同一个包中定义的类的对象能够看到此变量。
  • private:只有包含该变量的类能够看到它。

公共变量 :使用公共变量绝不是一个好主意,但在极少的情况下有必要这么做,所以存在这个选项。Java 平台不会限制您的使用情形,所以需要您自己遵守使用良好的编码约定的纪律,即使您被诱惑不这么做。

变量的 dataType 取决于变量的类型— 它可能是一种原语类型或另一种类类型(稍后将更详细地介绍)。

variableName 由您自己决定,但根据约定,变量名使用驼峰式大小写约定,但它们以小写字母开头。(这种样式有时称为小驼峰式大小写。)

现在暂时不要关心 initialValue,只需知道可以在声明一个实例变量时初始化它。(否则,编译器会为您生成一个在实例化该类时设置的默认值。)

示例:Person 的类定义

这个示例总结了您目前所学的知识。清单 2 是 Person 的类定义。

清单 2. Person 的基类定义

package com.makotojava.intro;

public class Person {
   private String name;
   private int age;
   private int height;
   private int weight;
   private String eyeColor;
   private String gender;
}

Person 的这个基类定义目前不是很有用,因为它仅定义了 Person 的属性(而且是私有属性)。要更加完整,Person 类还需要行为 —也就是方法。

方法

类的方法定义它的行为。

方法分为两个主要类别:构造方法;以及所有其他方法,这些方法具有许多类型。构造方法仅用于创建类的实例。其他类型的方法可用于几乎任何应用程序行为。

清单 1 中的类定义给出了定义方法的结构的方式,该结构包括的元素有:

accessSpecifier returnType methodName argumentList 这些结构元素在方法定义中的组合称为方法的签名。

现在仔细看看两种方法类别,首先看看构造方法。

构造方法

可使用构造方法指定如何实例化类。清单 1 以抽象形式给出了构造方法声明语法;这里再次给出了它:

accessSpecifier ClassName([argumentList]) {
  constructorStatement(s)
}

构造方法是可选的:如果您不提供构造方法,编译器会为您提供一个,这个方法称为默认(或无参数 或 no-arg)构造方法。如果您使用的构造方法不是 no-arg 构造方法,编译器不会自动为您生成一个。

构造方法的 accessSpecifier 与变量的相同。构造方法的名称必须与类名匹配。所以如果您将类命名为 Person,构造方法的名称必须也是 Person。

对于任何其他不是默认构造方法的构造方法(参见构造方法是可选的边栏),您需要传递一个 argumentList,其中包含一个或多个:

argumentType argumentName

argumentList 中的参数用逗号分隔,而且任何两个参数不能具有相同名称。argumentType 是一种原语类型或另一种类类型(与变量类型相同)。

包含构造方法的类定义

现在来看看在添加了通过两种方式创建 Person 对象的能力后会发生什么:通过使用 no-arg 构造方法和通过初始化一个部分属性列表。

清单 3 展示了如何创建构造方法,以及如何使用 argumentList:

清单 3. 包含构造方法的 Person 类定义

package com.makotojava.intro;
public class Person {
  private String name;
  private int age;
  private int height;
  private int  weight;
  private String eyeColor;

  private String gender;
  public Person() {
    // Nothing to do...
  }

  public Person(String name, int age, int height, int weight String eyeColor, String gender) {
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight;
    this.eyeColor = eyeColor;
    this.gender = gender;
  }
}

可以注意到,清单 3 中使用了 this 关键字来执行参数赋值。this 关键字是 “this object” 的 Java 速记形式,在引用两个具有相同名称的变量时必须使用它。在本例中,age 既是一个构造方法参数,又是一个类变量,所以 this 关键字可帮助编译器消除引用的歧义。

Person 对象变得越来越有趣了,但它需要有更多行为。为此,您需要更多方法。

其他方法

构造方法是一种具有特定功能的特定方法类型。类似地,其他许多类型的方法执行 Java 程序中的特定功能。从本节到本课程结束,将探索其他方法类型。

返回到 清单 1 中,可以看到方法的声明方式:

accessSpecifier returnType methodName ([argumentList]) {
  methodStatement(s)
}

其他方法看起来非常像构造方法,但有两处例外。首先,您可为其他方法提供您喜欢的任何名称(但是,肯定要遵守某些规则)。我推荐以下约定:

  • 以小写字母开头。
  • 避免使用数字,除非确实有必要使用它们。
  • 仅使用字母字符。

第二,不同于构造方法,其他方法拥有一个可选的返回类型。

Person 的其他方法

有了这些基本信息,您就可以在清单 4 中看到在向 Person 对象添加一些方法后发生的情况。(为简洁起见,我省略了构造方法。)

清单 4. 包含一些新方法的 Person

package com.makotojava.intro;

public class Person {
   private String name;
   private int age;
   private int height;
   private int  weight;
   private String eyeColor;
   private String gender;

   public String getName() { return name; }
   public void setName(String value) { name = value; }
   // Other getter/setter combinations...
}

请注意 清单 4 中有关 “getter/setter 组合” 的注释。稍后会更多地使用 getter 和 setter。就现在而言,您只需知道 getter 是一个检索属性值的方法,setter 是一个修改该值的方法。清单 4 仅给出了一种 getter/setter 组合(针对 Name 属性),但您可通过类似方式定义更多组合。

在 清单 4 中可以注意到,如果一个方法没有返回值,您必须在该方法的签名中指定 void 返回类型来告诉编译器。

静态和实例方法

通常会使用两种类型的(非构造)方法:实例方法和静态方法。实例方法依赖于特定对象实例的状态来执行其行为。静态方法有时也称为类方法,因为它们的行为不依赖于任何一个对象的状态。静态方法的行为在类级别上发生。

静态方法主要用于实用程序;您可将它们视为全局方法(类似于 C 语言),但将该方法的代码与定义它的类放在一起。

例如,在后面各节中,将使用 JDK Logger 类向控制台输出信息。要创建一个 Logger 类实例,不需要实例化一个 Logger 类;而是调用一个名为 getLogger() 的静态方法。

在类上调用静态方法的语法不同于在对象上调用方法的语法。您还会使用包含该静态方法的类的名称,如这个调用中所示:

Logger l = Logger.getLogger("NewLogger");

在这个示例中,Logger 是类名,getLogger(...) 是方法名。所以要调用静态方法,您不需要对象实例,只需要类名。

上一篇 下一篇