作者dasea (植栽鸡肉饭)
看板ncyu_phyedu
标题[讨论] 类别与物件
时间Sat Jan 30 14:54:46 2010
类别与物件的基本概念
所谓物件,说得白话一点,可称之为"东西"。这是个很抽象的名词,我们若以它具体的特性
来描述,会比较清楚:
Object有生命周期,会"产生"和"消灭"
Object具有其内部状态, 同一类别的不同Object, 其的内部状态可能都不一样
Object可以接收"讯息",并依据讯息的参数以及该物件的内部状态,做出反应,并可能因而
改变该物件的内部状态
属於同一个Class的Object,会具有该Class所定义的以上三种特质。
除此之外,Class之间可以定义继承(Inheritance)关系,子类别(Sub Class)继承父类别
(Super Class)的所有特性,子类别还可以定义其专属的特性。
以Object-Oriented(物件导向) Language写作程式时,写作的主体是Class。Class定义了
所有属於该Class的Object的特性,这些特性可分类如下:
Object产生时一定要呼叫的方法, 称为Constructor(建构子)
Objec消灭需要呼叫的方法, 称为Destructor(解构子)
表达Object内部状态的变数, 称为Object Variable(物件变数成员)
Object可以接收的讯息, 称为Object Method(物件方法成员)
上述两个可总称为Object Member
属於Class的变数, 称为Class Variable(类别变数)
属於Class的方法, 成为Class Method(类别方法)
上述两个可总称为Class Member
和其他Class间的继承关系
如何以Java撰写类别
Java规定公共类别(public class)必须写在该公共类别名称的.java档案内, 例如public
class Example就必须写在Example.java这个档案内。Example.java里面也可以定义其他
的类别,但是只有class Example能够宣告为public,其他Example.java里的class都不能宣
告为public。当Java Virtual Machine启动时,它会去找命令列上所指定的class里的
public static void main(String[] argv)方法,当做是程式的进入点。这有点像是C语言
的main, 不同处在於每个java class都可以定义自己的public static void
main(String[] argv)。
java Example
启动上述的JVM时, JVM会去执行class Example里的public static void main(String[]
argv)。以下范例Example.java说明如何定义Java的class。
class Vehicle {
private int speed; // Object Variable
private String direction; // Object Variable, direction is a reference to
String Object
private static int numVehicle = 0; // Class Variable
public Vehicle() { // Constructor, called when new a Object
this(0,"north"); // call another constructor to do initialization
}
public Vehicle(int s, String dir) { // Another Constructor. Use
overloading to define two constructors
float speed; // define a local variable
speed = s; // the speed here refers to the above local variable
this.speed = s; // If we want to set object variable, use this.speed
to refer object variable speed
direction = dir; // dir is a reference to object, not the object
itself
numVehicle++; // increase the Vehicle number
}
protected void finalize() { // Destructor, called when the object is
garbage collected by JVM
System.out.println("finalize has been called");
numVehicle--;
}
void setSpeed(int newSpeed) { // Object Method
this.speed = newSpeed;
}
void setDir(String dir) { // Object Method
this.direction = dir;
}
int getSpeed() { // Object Method
return speed;
}
String getDir() { // Object Method
return direction;
}
public static int totalVehicle() { // Class Method
return numVehicle;
}
}
public class Example {
public static void main(String[] argv) {
Vehicle v1 = new Vehicle(50, "west"); // new 叙述用来产生物件. 物件产
生时需要呼叫Constructor来初始化物件
Vehicle v2;
v1.setSpeed(30);
v1.setDir("north");
System.out.println("V1: speed is "+v1.getSpeed()+", direction is
"+v1.getDir()+".\n");
v2 = new Vehicle(40, "south");
System.out.println("There are "+Vehicle.totalVehicle()+" Vehicles in
the world.\n");
v1 = v2; // let reference v1 point to where v2 is pointing
System.out.println("V1: speed is "+v1.getSpeed()+", direction is
"+v1.getDir()+".\n");
System.gc(); // force system to do garbage collection, the object
previously pointed by v1 shall be destroyed
System.out.println("There are "+Vehicle.totalVehicle()+" Vehicles in
the world.\n");
}
}
上述例子里所用到的关键字或类别名称说明如下:
public:可用在
class前面表示此class可以供其他package里的类别使用。同一个目录下的class均可视为
属於同一个package。
object or class member前面, 表示所有的class均可存取此member。
private:可用在object or class member前面, 表示只有定义这些member的class才可存
取。
static:可用在member前面。如果member前面有static, 表示该member属於class,否则属
於object。不论系统创造了多少object,class variable只有一个;而每个object都有其
object variable。存取class method的语法是ClassName.classMethod();存取object
method时,则必须以reference.objectMethod()来呼叫。在Object Method里,可用this表
示目前的物件。但在Class Method里就不能存取object member了。
this:表示目前这个物件
String:定义於java.lang package下面的类别, 属於Java语言定义的标准程式库。
System:定义於java.lang package下面的类别, 属於Java语言定义的标准程式库。
System.out是class System里面的一个Class Variable, 其型态为reference to 定义於
java.io package里面的PrintStream。我们可透过该变数所指到的物件, 将讯息印到萤幕
上。
System.gc是class System里面的一个Class Method, 呼叫该方法可强迫JVM回收没有被任
何reference指到的物件。当物件被回收时, 该物件的finalize方法会被呼叫。
new:用来产生新的物件。後面必须跟着某个constructor, 以便进行初始化的动作。
Object Method的名称如果和Class的名称相同, 则表示该Method为Constructor。
Constructor不能宣告传回值。
要附带说明的是, Java以new指令来产生物件, 但不像C++有提供相对应的delete指令来消
灭物件。Java采用Garbage Collection的观念,当系统於闲置期间自动呼叫或由使用者强
制呼叫System.gc()时,没有被任何reference指到的Object就会被回收。
Class里面一定要定义一个以上的Constructor, 但为了方便起见,如果Compiler发现某
Class没有定义Constructor,则Compiler会帮我们产生一个不做任何事的Constructor:
public class A {
}
就相当於
public class A {
public A() {}
}
Overloading
同一个class里的Method名称可以重复使用,只要可以由Method的参数个数和型态来区分就
可以了。这种观念称为overloading。
不只一般的method可以overloading, constructor也可以overloading。
public class Overloading {
int data;
public Overloading() {
this(0); // call constructor Overloading(int)
}
public Overloading(int data) {
this.data = data;
}
public void print() {
this.print(0); // call method print(int)
}
public void print(int msg) {
}
public void print(float msg) {
}
public void print(int msg, String others) {
}
}
上面的例子里说明constructor也可以overloading。要特别注意的是,传回值并不能用来
分辨要呼叫哪个method,因此若再加上public int print()的宣告,就会造成编译错误了。
初始化的执行顺序
Class variable是在该类别载入JVM时进行初始化的, 因此写作上经常在class variable
的宣告後面加上初始化的动作。对Object Variable来说, 是在产生Object时进行初始化
的, 但初始化的步骤可以写在变数宣告後, 也可以写在constructor内, 因此必须对其执
行顺序有所了解。步骤如下:
先将所有变数设为内定值。对数值型态来说, 其值为0;对reference来说, 其值为null;对
boolean来说, 其值为false。
呼叫父类别的constructor。
执行变数宣告的初始化动作。
执行自己的constructor。
因此在如下的范例内
public class InitSequence {
int data = 2;
public InitSequence(int data) {
this.data = data;
}
public static void main(String[] argv) {
InitSequence s = new InitSequence(3);
System.out.println(s.data);
}
}
data的变化如下
设为内定值0
呼叫父类别的Constructor。因为类别InitSequence没有宣告继承任何类别, Java规定此
情况会自动继承java.lang.Object这个类别。Object的Constructor不做任何事。
执行变数宣告的初始动作,成为2
执行自己的constructor,成为3
因此最後执行的结果会在萤幕上印出数字3。
Java语言还可以定义static block:
public class StaticBlock {
static { // this is a static block
data = (int)(Math.random()*100);
}
static int data;
public static void main(String[] argv) {
System.out.println(data);
}
}
static block内的程式码, 是在该class载入JVM之後, 进行class variable初始化之前的
时间内执行。一般比较会使用static block的场合, 是该class用到一些非Java的程式库
, 需要透过System.loadLibrary(String libName)方法把外界的程式码载入时。这样写的
好处是只有当该class第一次被使用到时, 才会下载相关软体, 以节省记忆体空间, 避免
重复下载, 并可以把实作的细节和外界隔离开来。对没有这种机制的C语言来说, 很可能
就必须在主程式内写上一堆很难懂的启动程式码。
class ClassNeedToLoadLibrary {
static {
System.loadLibrary("mylib");
}
}
public class Main {
public static void main(String[] argv) {
}
}
final关键字
final关键字用在变数宣告时,表示该变数的值只能在宣告时给定,然後就不能再更改了。
public class Main {
public static final double PI = 3.14159;
public final int x = 10;
public static void main(String[] argv) {
final int local = 10;
Main m = new Main();
PI = 100; // Compile Error, final variable can only be set at
initialization
m.x = 10; // Compile Error
local = 100; // Compile Error
}
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 61.58.22.74