一:构造类
编程时先定义好类,再对类实例化产生对象。类的形式如下:
class declaration{ //类声明部分
class body //类体部分
}
(一)类声明部分
最简单的类声明仅有一个关键字class和一个类名,例如:
class myApp{
...
}
一般的类声明有如下几个部分:
[modifiers] class ClassName [extends SuperClassName][implements InterfaceNames]
其中方括号 的部分是可以省略的。
modifiers部分称为修饰符,可以设置为abstract、final或public
ClassName是所声明的类名,必须是有效的java标识符。
SuperClassName是超类名,extends表明本类是从超类SuperClassName中派生而来的子类。
InterfaceNames是多个接口名,implements表明本类实现(即使用)这些接口。
(1)修饰符abstract、final、public
若用abstract修饰class,表明文本是抽象类,不能直接实例化为对象。抽象类中存在抽象的方法(即未实现的方法),没有方法体,不能直接调用。这种类只能被子类继承。抽象的方法由子类重写,并给出完整的方法体,其声明格式为:
abstract class Myclass{
...
}
如果认为一个类的各子类会用不同方式实现本类的方法,就可以把本类定义为抽象类。
若用final修饰class,表明本类是最终类,不能再有子类,即不能再被继承。其方法不能再被重写,这样保证该类的唯一性,其声明格式为:
final class Myclass{
...
}
如果你认为一个类已经非常完善,不需要在改变,就可以定义为最终类。
若用public修饰class,表明本类是公用类,可以被当前所属包之外的其他类与对象调用,其声明格式为:
public class Myclass{
...
}
定义一个public类一般位于abstract类和final类之前。在一个java编程单元中可以有多个类,但只能有一个类声明具有public标识符。
若修饰符省略在,则表示本类既不是abstract,又不是final,也不是public,而是“友好的”只能在当前包中使用。
(2)extends子句
在类声明中若有extends关键字,则后面会给出一个超类名,表明本类是从这个超类派生而来的。java不支持多重继承,因此每个类只有一个超类。其声明格式为:
class Myclass1 extends Number{
...
}
java的每个类必须有一个超类,若extends部分省略,则其隐含超类为Object,这是在java的类继承树中的最高类,所有类都是Object的后继。object中定义了所有对象必须具有的基本状态和行为。如:
class Myclass1{
...
}
意味着Myclass1为object的子类,可以继承object定义的状态和方法。
(3)implements子句
类声明的implements关键字后给出若干个接口名,表明本类实现了哪些接口,即这些接口中所描述的全部方法在本类中得到了实现。如:
class Myclass2 implements Myinterface{
...//Myclass2类必然包括接口Myinterface中所描述的所有方法。
}
implements子句可以包括多个接口名,均由本类实现。若这部分省略,则表明本类不使用任何接口。
例子:
import java.applet.Applet; import java.awt.Graphics; import java.util.*; public class Clock extends Applet implements Runnable { Thread clockThread; //声明类变量 public void start() { if(clockThread==null){ clockThread = new Thread(this,"Clock"); //创建新线程 clockThread.start(); //启动线程 } } public void run() { while(clockThread!=null){ repaint(); //刷新 try{ clockThread.sleep(100); //线程睡眠 }catch()(InterruptedException e){ //异常处理 } } } public void paint(Graphics g) { Date now = new Date(); //创建时间对象 g.drawString(now.getHours()+":"+now.getMinutes()+":"+now.getSeconds(),5,10); //输出时间方法 } public void stop(){ clockThread.stop(); //停止线程 clockThread=null; } }
该程序声明了一个类,类中有4个方法。类声明部分表明该类是公共类,clock为类名,其超类是Applet,该类实现了接口Runnable。
二:类体部分
类体部分包含了类中支持的成员变量和方法的声明。成员变量是指一个类或对象相关的变量,在类中但不在方法体中,其作用域是整个类;而在方法体中的变量称为局部变量,只在方法体内部使用。类的成员变量代表了类的状态,其方法实现了类的行为,一般先声明成员变量,然后再给出方法的声明和实现,类体的格式为:
class declaration{
member variable declarations //成员变量的声明
methob declarations //方法的声明
}
(一)成员变量
成员变量也可以称为域,可以分为类变量和实例变量两种:类变量在类中只出现一次,系统仅为类变量分配一次内存;实例变量出现在类的每个实例中,每创建一次新的实例,系统都要为实例变量分配内存;类变量和实例变量的区别在于前面有无关键字static。
最简单的成员变量声明仅有一个变量类型和变量名;
class Myclass{
int op1; //op1为成员变量名,int是变量类型。
}
声明一个成员变量的一般格式为:
[accessSpecifier][static][final][transient][volatile]type variablename
accessSpecifier(访问限制)限制哪些类可以访问本类的成员变量
static 表明这个变量是类变量而不是实例变量。
final表明这个变量是常数。
transient 表明这个变量不是本对象的永久状态
volatile 表明这个变量可以异步地修改
type 指变量的类型,即byte、int等各种简单的数据类型以及符合数据类型的关键字。
variablename 指变量名,必须是合法的标识符。
(1)accessSpecifier
java为变量提供了4种级别的访问:private(私有变量)、protected(保护变量)、public(公共变量)和friendly(友好变量),限制了同一个类中,同一个包中、子类中、不同包中的访问变量的权限。若accessSpecifier部分省略。则变量的隐含声明为friendly。
限制符 | 同类 | 同包 | 子类 | 不同包 |
public protected friendly private |
Y Y Y Y |
Y Y Y N |
Y Y N N |
Y N N N |
class Myclass{
private int op1; //这样的op1只能被Myclass类的实例对象访问。
}
(2)static关键字
若在声明成员变量时加上Static关键字,则该变量是一个类变量(可称为静态变量)而不是实例变量。其声明为:
class Myclass{
static int op1;
}
系统在第一次遇到类变量op1时就为它分配内存,类的所有实例对象共享这个类变量,类变量有静态不变的特点。通常用于定义常数,因为常数对所有对象来说都不变。
若static关键字省略,则所声明的成员变量是实例变量。在同一个类的不同实例对象中,实例变量是各不相同的,每个实例对象的实例变量单独分配内存,不能共享,只能由各对象访问自己的实例对象。
类变量和实例变量的不同之处就是类变量可以用类名来访问(如Myclass.op1),常用的System.out就是用System类直接访问类变量out。但实例变量只能由类实例化后得到的对象名来访问。
(3)final关键字
若在声明成员变量时加上final关键字,则该变量是一个Java常数,其声明为:
class Myclass{
final double PI=3.1415926;
}
如上声明的PI在程序中不能再被赋予新值。
(4)transient关键字
若在声明成员变量时加上transient关键字,表明该变量不是对象的永久状态,其声明为:
class Myclass{
transient int op2;
}
对象序列化时将不处理transient关键字的域。
(5)volatile关键字
若在声明成员变量时加上volatile关键字,表明该变量可以被多个并行 线程异步地修改。
class Myclass{
volatile int op3;
}
java虚拟机保证每次使用该变量之前已从内存读取,用后写回内存,从而保证该变量对多个线程是一致的。
(二)方法
方法用于实现对象的行为,其他对象可用通过调用某个对象的方法来得到该对象的服务。例如:
return_type method_name(){ //方法声明,return_type 表示该方法返回值的数据类型
method body //方法体
}
下面分别介绍方法声明和方法体
(1)方法声明部分
一般的方法声明格式为:
[accessSpecifier][static][abstract][final][native][synchronized]return-type method_name([paramlist])[throws exceptionsList]
其中:
accessSpecifier 部分是方法的访问权限,其声明的形式和含义与成员变量的访问限制声明完全一样。
static 关键字声明该方法是类方法,类方法被类的所有对象共享;若static省略表示该方法是实例方法。
abstract 关键字声明该方法是抽象方法,没有方法体,必须由子类重写。
final关键字声明该方法是最终方法,不能被重写。
native关键字声明的方法没有方法体,由平台相关的语言(特别是C语言)来实现方法体,这种机制提供了融合其他语言进入java程序的方法,但会影响java结构的独立性。
synchronized 关键字声明的方法用于控制多个并发线程对共享数据的访问。
paramlist 是方法的参数
throws exceptionsList 是方法的异常处理,它列出了该方法中可能发生的”异常“的类型,提醒方法的调用者作出适当的处理。
在声明方法时要注意两点:一是方法名的重写和重载;二是构造方法
方法名的重写是声明某方法的名字与其超类中的方法同名,重写意味着对继承的方法提供不同的实现,其中abstract方法必须重写,而final方法不能重写。方法名重载是多个方法可以公用一个方法名。
构造方法是某个方法与声明它的类同名。构造方法有专门的用途,用于建立本类的一个新对象,并且对新对象进行初始化。
声明方法的参数时要同时声明其类和名字,多个参数间用逗号隔开。参数类型可以是任何合法的java数据类型和数组、对象等复合类型,但不能用某个方法做参数,只能用某个对象做参数,然后调用该对象的方法。
参数名可以与类的成员变量同名,这时称这种参数隐藏了成员变量。但参数不能与局部变量同名,例如:
void Mymethod(int i,int j){
for(int i=0;i<10;i++)
...
}
参数中的int i与方法中的局部变量int i同名,因此会出错。
java的方法参数是用值来传递的,即调用方法时接收变量传入的值。对于基本变量类型的参数,方法不能改变它们的值;对于引用类型的参数(即对象、数组等)可以调用对象的方法来修改对象中的变量。
(2)方法体部分
方法体是方法发生动作的地方,方法体中包含了所有合法的java指令来实现方法。方法体中声明的变量称为局部变量,其作用范围只在该方法体内,当方法返回时,局部变量不再存在。局部变量的名字可以和类的成员变量名字相同,当调用方法时局部变量会隐藏成员变量的作用。
在方法体中可以使用this和super两个关键字。
this 在方法体中指当前对象的成员,包括成员变量和方法。当前对象就是 调用本方法的对象,如果方法的某个参数与当前对象的某个成员变量同名,就必须使用this来指明成员变量。同样,this可以用来调用当前对象的某个方法。
super用于指当前对象所隐藏或重写的超类成员。若本方法隐藏了其超类的某个成员变量,可以用super来指这个变量;同理,若本方法重写了其超类的某个方法,可以用super来调用这个被重写的方法。