java语言入门
像任何编程语言一样,Java 语言指定了一些编译器认为具有特殊意义的关键字。出于该原因,您不能使用它们来命名您的 Java 构造。保留字(也称为关键字)非常少:
|
abstract
assert
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
enum
extends
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
try
void
volatile
while
|
您也不能使用 true
、false
和 null
(严格意义上讲,它们是 字面常量 而不是关键字)来命名 Java 构造
使用 IDE 进行编程的一个优势是,它可以对保留字使用语法颜色。
Java 类的结构
类是包含属性和行为的离散实体(对象)的蓝图。类定义了对象的基本结构,在运行时,您的应用程序会创建对象的实例。对象拥有明确定义的边界和状态,在正确请求对象时,它们可以执行相应的操作。每种面向对象的语言都拥有关于如何定义类的规则。
在 Java 语言中,类的定义如清单 1 所示:
清单 1. 类定义
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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 和本节的其他一些代码示例中,方括号表示它们之中的结构不是必需的。方括号本身(不同于 {
和 }
)不是 Java 语法的一部分。
清单 1 包含各种类型的构造,第 1 行是 package
,第 2 行是 import
,第 3 行是 class
。这 3 种构造都属于保留字,所以它们必须保持清单 1 中的准确格式。我为清单 1 中的其他构造提供的名称描述了它们表示的概念。
请注意,清单 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 语言没有强制要求您遵循这种包约定。您完全不需要指定一个包,但在这种情况下,您的所有类都必须有唯一的名称且位于默认包中。)
导入语句
Eclipse 简化了导入
在 Eclipse 编辑器中编写代码时,可以键入想要使用的类的名称,然后按 Ctrl+Shift+O。Eclipse 会确定您需要哪些导入语句并自动添加它们。如果 Eclipse 找到两个具有相同名称的类,它会询问您想为哪个类添加导入语句。
类定义中的下一部分(返回参考清单 1)是导入语句。导入语句告诉 Java 编译器在何处查找您在代码中引用的类。任何非无效类都会使用其他类来实现某种功能,导入语句是您向 Java 编译器告知这些类的方式。
导入语句看起来通常类似于:
|
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*
值包括:
公共变量
使用公共变量绝不是一个好主意,但在极少的情况下必须这么做,所以存在这种选择。Java 平台不会限制您的用例,所以使用良好的编码约定取决于您的自律,即使您采取了别的选择。
-
public
:任何包中的任何对象都能看到该变量。(不要使用此值;请参阅公共变量侧栏。) -
protected
:相同包中定义的任何对象或(在任何包中定义的)一个子类都可以看到该变量。 - 没有说明符(也称为友好或包私有访问):只有在相同包中定义了其类的对象才能看到该变量。
-
private
:只有包含该变量的类能够看到它。
变量的 *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*
与变量的 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 combinations”的注释。稍后会更多地使用 getter 和 setter。就现在而言,您只需知道 getter 是一个检索属性值的方法,setter 是一个修改该值的方法。 清单 4 仅给出了一种 getter/setter 组合(针对 Name
属性),但您可用类似方式定义更多组合。
在清单 4 中可以注意到,如果某个方法没有返回值,则必须在该方法的签名中指定 void
返回类型来告知编译器。
静态和实例方法
通常会使用两种类型的(非构造)方法:实例方法和静态方法。实例方法依赖于特定对象实例的状态来实现其行为。静态方法有时也称为类方法,因为它们的行为不依赖于任何一个对象的状态。静态方法的行为是在类级别上发生的。
静态方法主要用于实用程序;您可将它们视为全局方法(类似于 C 语言),但将该方法的代码与定义它的类放在一起。
例如,在整个教程中,您都会使用 JDK Logger
类向控制台输出信息。要创建一个 Logger
类实例,不需要实例化 Logger
类;而是应该调用一个名为 getLogger()
的静态方法。
在类上调用静态方法的语法不同于在对象上调用方法的语法。您还会使用包含该静态方法的类的名称,如这个调用中所示:
|
Logger l = Logger.getLogger("NewLogger");
|
在这个示例中,Logger
是类名,getLogger(...)
是方法名。因此,要调用静态方法,不需要对象实例,只需类名即可。