封装
类的定义
class Type{
public String _var; // 成员属性
public Type(...){ // 构造方法
// ...
}
public void method)(...){ // 成员方法
// ...
}
}
成员变量初始化:
class Type {
private int field = 10;
}
或者可以使用某个方法的返回值:
class Type {
private int field = addObj();
// ...
private static int addObj() {
// ...
}
// ...
}
如果不进行显式的初始化,成员变量将被赋予默认值:0
false
null
,这是成员变量与局部变量的主要不同点,局部变量不会被赋予默认值,必须显式初始化才可以使用。
类的访问权限
在 Java 中,public、private、protected 这些访问权限必须直接修饰方法,而不是 C++ 分类式地声明。
class Type{
public int field;
public void method(){
//...
}
}
Java 中有四种权限修饰方式:
修饰符 | 访问范围 |
---|---|
public | 均可访问 |
protected | 包内和所有子类可访问 |
(缺省) | 包内可访问 |
private | 仅本类访问 |
构造方法
重载
构造方法的重载机制与 C++ 基本完全相同,不赘述。
委托构造
使用this
关键字可以在构造方法中调用其他构造方法。
class Type {
// ...
Type() {
this(/* params */);
}
// ...
}
在 C++ 中,委托构造必须写在初始化列表中。
静态域/类域
C++ 中有静态方法和静态变量,可以通过类名直接访问。
在大多数面向对象的编程语言中,这个概念都被成为类域,Java 使用static
修饰只是沿用了 C++ 的叫法。
public static void main();
private static int field;
(静态)初始化块
初始化块
构造对象时,初始化块内的代码将被首先调用:
可以用来构造对象,但一般不这么做(除非要进行构造代码的复用),而且要避免读取后面初始化的成员变量。
class Type {
{
// ...
}
}
静态初始化块
首次加载该类时(不论以何种方法),会直接调用静态初始化块。
类似静态域的构造函数。
class Type {
static {
// ...
}
}
对象析构
在 Java 垃圾回收期清理对象之前会调用该对象的finalize
方法,在该方法中可以做一些收尾工作。
更好的方法是提供一个close
方法进行收尾,由调用者决定调用的时间点,因为我们无法确定finalize
方法会在何时被调用。
包
概述
包用来组织类,使类之间拥有一个层次结构,并减少类名冲突(这是主要目的)。
包结构类似(其实完全一样)文件的组织结构:
一个文件路径home/dev/class1.java
对应到包 --> home.dev.class1
。
实际上,大多数人在组织包结构时,通常使用域名的逆序,例如笔者可以这样命名:top.gaolihai
。
这种方式来源于 Sun 公司的建议:
为了保证包名的绝对 唯一性,Sun公司建议将公司的因特网域名(这显然是独一无二的)以逆序的形式作为包名。并且对于不同的项目使用不同的子包。例如, horstmann.com 是本书作者之一注册的域名。逆序形式为 com.horstmann。这个包还可以被进一步地划分成子包,如 com.horstmann.corejava。
—— Core Java I (P131)
将类添加到包
在文件开头写上:
package /* ... */;
例如:
package top.gaolihai.test;
那么该类应放在./top/goalihai/test
目录下,编译时使用javac top/gaolihai/test/Src.java
,调用解释器时使用java top.gaolihai.test.Src
。
当我们不指定类文件的包时,该类将位于一个默认包(没名字)下,与其他没有指定包的类共享一个包作用域。
导入类
要访问不同包里的公有类,我们可以在类名前指定完整的包路径:
java.util.LinkedHashMap<String, Integer> map = new java.util.LinkedHashMap();
或者使用import
:
导入该类:
import java.util.LinkedHashMap
或者导入包下的所有类:
import java.util.*
这时候就可以直接使用:
LinkedHashMap<String, int> map = new LinkedHashMap();
类的作用域在整个包内,故若与某类在同一个包,可以不导入,直接使用。
import 语句并不类似于 C/C++ 中的 #include,而更像 C/C++ 中的 using。对应地,包类似于 C/C++ 中的 namespace。
导入静态域
import
还可以用来将一个类的静态域和静态方法全部导入(或导入特定的),例如导入Math
下的所有静态域和静态方法:
import java.lang.Math.*;
这时就可以直接使用,而不是通过Math
来引用:
round(/* val */);
类路径
在调用第三方库(jar 文件、java 文件)时,我们需要告诉编译器这些类都在哪。
在编译时使用-cp
(classpath 的缩写)参数,其后指定一个或多个.jar
文件或目录并以:
或;
分隔。
java -cp {route};{route};...
对于.java
文件,可以直接指定上级目录,对于.jar
文件,必须指定具体的文件名或使用通配符*
,例如./lib/*
。
更多详细内容见 Java 核心技术 卷 I --> P137