目录
6.1 面向对象概述
在程序开发初期人们使用结构化开发语言,但随着软件的规模越来越庞大,结构化语言的弊端也逐渐暴露出来,开发周期被无休止地拖延,产品的质量也不尽如人意,结构化语言已经不再适合当前的软件开发。这时人们开始将另一一种开发思想引入程序中,即面向对象的开发思想。面向对象思想是人类最自然的种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪此相应的属性以及行为,以解决这些对象面临的一些实际问题, 这样就在程序开发中引入了面向对象设计的概念,面向对象设计实质上就是对现实世界的对象进行建模操作。
6.1.1 对象
在现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即静态部分与动态部分。静态部分,顾名思义,就是不能动的部分,这个部分被称为“属性”,任何对象都具备其自身属性,如一个人,其属性包括高矮、胖瘦、性别、年龄等。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。
在计算机的世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。例如,现在面临一只大雁 要从北方飞往南方这样一个实际问题,试着以面向对象的思想来解决这一实际问题。 步骤如下:
(1)首先可以从这一问题中抽象出对象,这里抽象
出的对象为大雁。
(2)然后识别这个对象的属性。对象具备的属性都
是静态属性,如大雁有一对翅膀、黑色的羽毛等。这些属性。
(3)接着识别这个对象的动态行为,即这只大雁可
以进行的动作,如飞行、觅食等,这些行为都是这个对象基于其属性而具有的动作。
(4)识别出这个对象的属性和行为后,这个对象就被定义完成了,然后可以根据这只大雁具有的特性制定这只大雁要从北方飞向南方的具体方案以解决问题。
究其本质,所有的大雁都具有以上的属性和行为,可以将这些属性和行为封装起来以描述大雁这类动物。 由此可见,类实质上就是封装对象属性和行为的载体,而对象则是类抽象出来的一个实例。
6.1.2 类
不能将所谓的一个事物描述成一类事物, 如一只鸟不能称为鸟类。如果需要对同一类事物统称,就不得不说明类这个概念。
类就是同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟具有一-对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有翅膀这个特性和飞行的技能,这样具有相同特性和行为的- -类事物就称为类,类的思想就是这样产生的。在图6.3中已经描述过类与对象之间的关系,对象就是符台某个类的定义所产生出来的实例。更为恰当的描述是,类是世间事物的抽象称呼,而对象则是这个事物相对应的实体。 如果面临实际问题,通常需要实例化类对象来解决。例如,解决大雁南飞的问题,这里只能拿这只大雁来处理这个问题,而不能拿大雁类或鸟类来解决。
类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称为类。例如,鸟类封装了所有鸟的共同属性和应具有的行为,定义完鸟类之后,可以根据这个类抽象出一个实体对象,最后通过实体对象来解决相关的实际问题。
在Java语言中,类包括对象的属性和方法。类中对象的属性是以成员变量的形式定义的,对象的行为是以方法的形式定义的,有关类的具体实现会在后续章节中进行介绍。
6.1.3 面向对象程序设计的特点
面向对象程序设计具有以下特点:
封装性。
继承性。
多态性。
1. 封装
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。例如,用户使用计算机时,只需要使用手指敲击键盘就可以实现一些功能,无须知道计算机内部是如何工作的,即使可能知道计算机的工作原理,但在使用计算机时也并不完全依赖于计算机工作原理这些细节。
采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易地直接操作此数据结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。
2. 继承
类与类之间同样具有关系,如一个百货公司类与销售员类相联系,类之间的这种关系被称为关联。关联主要描述两个类之间的一般二元关系, 例如,一个百货公司类与销售员类就是一个关联,学生类与教师类也是一个关联,两个类之间的关系有很多种,继承是关联中的一种。学生类与教师类也是一个关联。
两个类之间的关系有很多种,继承是关联中的一种。继承性主要利用特定对象之间的共有属性。例如,平行四边形是四边形,正方形、矩形也是四边形,平行四边形与四边形具有共同特性,就是拥有4条边,可以将平行四边形类看作四边形的延伸,平行四边形复用了四边形的属性和行为,同时添加了平行四边形独有的属性和行为,如平行四边形的对边平行且相等。这里可以将平行四边形类看作是从四边形类中继承的。在Java语言中将类似于平行四边形的类称为子类,将类似于四边形的类称为父类或超类。值得注意的是,可以说平行四边形是特殊的四边形,但不能说四边形是平行四边形,也就是说子类的实例都是父类的实例,但不能说父类的实例是子类的实例。
3. 多态
上面介绍了继承,了解了父类和子类,其实将父类对象应用于子类的特征就是多态,多态的实现并不依赖具体类,而是依赖于抽象类和接口。下面以图形类来说明多态。
图形类作为所有图形的父类,具有绘制图形的能力,这个方法可称为“绘制图形”,但如果要执行这个“绘制图形”的命令,没有人知道应该画什么样的图形,并且如果要在图形类中抽象出一个图形对象,没有人能说清这个图形究竟是什么图形,所以使用“抽象”这个词来描述图形类比较恰当。在Java语言中称这样的类为抽象类,抽象类不能实例化对象。在多态的机制中,父类通常会被定义为抽象类,在抽象类中给出一个方法的标准,而不给出实现的具体流程。实质上这个方法也是抽象的,如图形类中的“绘制图形”方法只提供一个可以绘制图形的标准,并没有提供具体绘制图形的流程,因为没有人知道究竟需要绘制什么形状的图形。
每个图形都拥有绘制自己的能力,这个能力可看作是该类具有的行为,如果将子类的对象统一看作是父类的实例对象,这样当绘制图形时,简单地调用父类也就是图形类绘制图形的方法即可绘制任何图形,这就是多态最基本的思想。
6.2 类与对象
在6.1.2节中已经讲过类是封装对象的属性和行为的载体,Java中定义类使用class关键字,其语法如下:
class 类名称{
//类的成员变量//类的成员方法
}
在Java语言中对象的属性以成员变量的形式存在,对象的方法以成员方法的形式存在。
6.2.1 成员变量
在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样,语法如下:
数据类型 变量名称 [ = 值];
为了了解成员变量,首先定义一个鸟类,成员变量对应于类对象的属性,在Bird类中设置4成员变量,分别为wing、claw、beak 和feather,分别对应于鸟类的翅膀、爪子、喙和羽毛。
public class Bird {String wing; //翅膀
String claw; //爪子
String beak; //喙
String feather; //羽毛
根据以上代码,读者可以看到在Java中使用class 关键字来定义类,Bird 是类的名称。同时Bird类中定义了4个成员变量,成员变量的类型可以设置为Java中合法的数据类型,其实成员文就是普通的变量,可以为它设置初始值,也可以不设置初始值。如果不设置初始值。
6.2.2 成员方法
在Java语言中,成员方法对应于类对象的行为,它主要用来定义类可执行的操作,它是包含系列语句的代码块,本节将对成员方法进行详细讲解。
1.成员方法的定义
定义成员方法的语法格式如下:
[权限修饰符] [返回值类型]方法名( [参数类型参数名] ) [throws 异常类型] {
...//方法体return 返回值;
}
其中,“权限修饰符”可以是private、public、 protected 中的任一一个, 也可以不写,主要用来控制方法的访问权限,关于权限修饰符将在下章中详细讲解;“返回值类型”指定方法返回数据 的类型,可以是任何类型,如果方法不需要返回值,则使用void 关键字;一个成 员方法既可以有参数,也可以没有参数,参数可以是对象也可以是基本数据类型的变量。
例如:定义一个showGoods方法,用来输出库存商品信息,代码如下:
public void showGoods(){
system.out.println("库存商品名称:");system.out.println(FullName);
}
如果定义的方法有返回值,则必须使用returm关键字返回一个指定类型的数据,并且返回值类型要与方法返回的值类型一致, 例如,定义一个返回值类型为 int的方法, 就必须使用retum返回一个int类型的值。
代码如下:
public void showGoods(){
system.out.println("库存商品名称:");return 1;
}
2.成员方法的参数
调用方法时可以给该方法传递一个或多 个值,传给方法的值叫做实参,在方法内部,接收实参的变量叫做形参,形参的声明语法与变量的声明语法样。 形参只在方法内部有效。Java 中方法的参数主要有3种,分别为值参数、引用参数和不定长参数。
(1)值参数
值参数表明实参与形参之间按值传递,当使用值参数的方法被调用时,编译器为形参分配存储单元,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以,在方法中对值类型的形参的修改并不会影响实参。
例6.1
package 第六章;
public class zy { //创建类
public static void main(String[] args) { //主方法
// TODO Auto-generated method stub
Book book=new Book(); //创建Book对象
int x=30; //定义实参变量x
int y=40; //定义实参变量y
System.out.println("运算结果:"+ book.add(x,y)); //输出运算结果
System.out.println("实参x的值:"+x); //输出实参x的值
}
private int add(int x,int y) //计算两个数的和
{
x=x+y; //对x进行加y操作
return x; //返回x
}
}
(2)引用参数
如果在给方法传递参数时,参数的类型是数组或者其他引用类型,那么,在方法中对参数的修改会反映到原有的数组或者其他引用类型上,这种类型的方法参数,我们称之为引用参数。
例6.2
package 第六章;
public class zy { //创建类
public static void main(String[] args) { //主方法
// TODO Auto-generated method stub
zy refTest =new zy(); //创建RefTest对象
int [] i= {0, 1, 2}; //定义一维数组,作为方法的实参
//输出一维数组的原始元素值
System.out.print("原始数据: "); //输出原始数据
for (int j=0;j<i.length;j++) //for循环j++
{
System.out.print(i[j]+" "); //输出i,j的数
}
refTest.change(i); //调用方法改变数组元素的值
System.out.print("\n修改后的数据:"); //输出修改后的数据
for (int j=0;j<i.length;j++) //for循环j++
{
System.out.print(i[j]+" "); //输出i,j的数
}
}
public void change (int [] i) //定义一个方法,方法的参数为一维数组(形参)
{
i[0] = 100; //输出i=100
i[1] = 200; //输出i=200
i[2] = 300; //输出i=300
}
}
(3)不定长参数
声明方法时,如果有若干个相同类型的参数,可以定义为不定长参数
例6.3
package 第六章;
public class zy { //创建类
public static void main(String[] args) { //主方法
// TODO Auto-generated method stub
zy multi=new zy(); //创建Multi对象
System.out.print("运算结果:"+multi.add(20,30,40,50,60)); //输出运算结果
}
int add(int...x) //定义add方法,并指定不定长参数的类型为int
{
int result=0; //记录运算结果
for(int i=0;i<x.length;i++) //遍历参数
{
result +=x[i]; //执行相加操作
}
return result; //返回运算结果
}
}
3. 成员方法的使用
本节通过一个具体的实例讲解成员方法的定义及使用。
例6.4
package 第六章;
public class zy { //创建类
public void gaze(String target){ //主方法
// TODO Auto-generated method stub
System.out.println("猎豹凝视:"+target); //输出猎豹凝视
}
public void run() { //奔跑
System.out.println("猎豹开始奔跑"); //输出猎豹开始奔跑速度
}
public boolean catchPrey(String prey) { //定义prey
System.out.println("猎豹开始捕捉"+prey); //输出猎豹开始捕捉
return true; //结束
}
public void eat(String meat) { //定义meat
System.out.println("猎豹吃"+meat); //输出猎豹吃
}
public void sleep() { //睡觉
System.out.println("猎豹睡觉"); //输出猎豹睡觉
}
public static void main (String[] args) { //主方法
zy liebao =new zy(); //定义新数组
liebao.gaze("羚羊"); //羚羊
liebao.run(); //奔跑
liebao.catchPrey("羚羊"); //羚羊
liebao.eat("领羊肉"); //领羊肉
liebao.sleep(); //睡觉
}
}
6.2.3 构造方法
在类中除了成员方法之外,还存在一-种特殊类型的方法,那就是构造方法。构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化-一个对象时,类都会自动调用构造方法。
(1)构造方法没有返回类型,也不能定义为void.
(2)构造方法的名称要与本类的名称相同。
(3)构造方法的主要作用是完成对象的初始化工作,它能把定义对象的参数传给对象成员。
构造方法的定义语法如下:
class Book {
public Book(){ //构造方法}
}
Public: 构造方法修饰符。
Book: 构造方法的名称。
在构造方法中可以为成员变量赋值,这样当实例化一一个本类的对象时,相应的成员变量也将被初始化。如果类中没有明确定义构造方法,则编译器会自动创建一个不带参数的默认构造方法除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,即有参数构造方法
语法如下:
class Book {
public Book(){ //构造方法//对成员变量进行初始化
}
}
public:构造方法修饰符。
Book:构造方法的名称。
args:构造方法的参数,可以是多个参数。
构造方法除了可以用public修饰以外,还可以用private修饰,即私有的构造方法,私有法无法使用new创建对象,这时需要使用静态方法生成类的对象。
例6.5
package 第六章;
public class zy { //创建类
private zy() { //类名
}
static public zy libraryBrrow() { // 创建静态方法,返回本类实例对象
System.out.println("通过调用静态方法创建对象"); // 创建静态方法,返回本类实例对象
return new zy(); //输出结果
}
public static void main(String[]args) { //主方法
zy book =zy.libraryBrrow(); //输出new实例化的结果
}
}
6.2.4 局部变量
如果在成员方法内定义一个变量,那么这个变量被称为局部变量。局部变量在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作或被初始化,否则会出现编译错误。
例如,在项目中创建一个类文件,在该类中定义getName()方法并进行调用
public string getName(){ //定义一个getName()方法
int id=0; //局部变量
setName("Java"); //调用类中其他方法
return id+this.name; //设置方法返回值
}
如果id这个局部变量的初始值去掉,编译器将出现错误。
6.2.5 局部变量的有限范围
可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量的声明开始到该变量的结束为止。
6.2.6 对象的创建
在6.1节中曾经介绍过对象,对象可以认为是在一类事物中抽象出某一个特例, 可以通过这个特例来处理这类事物出现的问题。在Java语言中通过new操作符来创建对象。前文在讲解构造方法时介绍过,每实例化一个对象就会自动调用一次构造方法, 实质上这个过程就是创建对象的过程。准确地说,可以在Java语言中使用new操作符调用构造方法创建对象。
语法如下:
Test test=new Test();
Test test=new Test("a");
Test: 类名。
test: 创建Test类对象。
new; 创建对象操作符。
a; 构造方法的参数。
test对象被创建出来时,就是一一个对象的引用,这个引用在内存中为对象分配了存储空间,6.23节中介绍过,可以在构造方法中初始化成员变量,当创建对象时,自动调用构造方法,也就是说在Java语言中初始化与创建是被捆绑在一起的。
每个对象都是相互独立的,在内存中占据独立的内存地址,并且每个对象都具有自己的生命周期,当一个对象的生命周期结束时,对象就变成垃圾,由Java虚拟机自带的垃圾回收机制处理,不能再被使用。
例6.6
package 第六章;
public class zy { //创建类
public zy() { //构建方法
System.out.println("创建对象"); //输出创建对象
}
public static void main(String args[]) { //主方法
new zy(); //创建对象
}
}
6.2.7 访问对象的属性和行为
用户使用new操作符创建一个对象后, 可以使用“对象类成员”来获取对象的属性和行为。前文已经提到过,对象的属性和行为在类中是通过类成员变量和成员方法的形式来表示的,所以当对象获取类成员时,也相应地获取了对象的属性和行为。
例6.7
package 第六章;
public class TransferProperty { //创建类
int i = 47; // 定义成员变量
public void call() { // 定义成员方法
System.out.println("调用call()方法"); //输出"调用call()方法"
for (i = 0; i < 3; i++) { //控制长度
System.out.print(i + " "); //输出结果
if (i == 2) { //if语句
System.out.println("\n"); //输出结果
}
}
}
public TransferProperty () { // 定义构造方法
}
public static void main(String[] args) { //主方法
TransferProperty t1 = new TransferProperty(); // 创建一个对象
TransferProperty t2 = new TransferProperty(); // 创建另一个对象
t2.i = 60; // 将类成员变量赋值为60
System.out.println("第一个实例对象调用变量i的结果:" + t1.i); // 使用第一个对象调用类成员变量
t1.call(); // 使用第一个对象调用类成员方法
System.out.println("第二个实例对象调用变量i的结果:" + t2.i); // 使用第二个对象调用类成员变量
t2.call(); // 使用第二个对象调用类成员方法
}
}
在上述代码的主方法中首先实例化一一个对象, 然后使用“”操作符调用类的成员变量和成员方法。但是在运行结果中可以看到,虽然使用两个对象调用同一个成员变量,结果却不相同,因为在打印这个成员变量的值之前将该值重新赋值为60,但在赋值时使用的是第二个对象t2调用成员变量,所以在第一个对象 t1调用成员变量打印该值时仍然是成员变量的初始值。由此可见,两个对象的产生是相互独立的,改变了t2的i值,不会影响到t1的i值。在内存中这两个对象的布局。
6.2.8 对象的销毁
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址会被回收。在其日一扫他语言中需要手动回收废弃的对象,但是Java拥有-套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的但占用内存的资源。
虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象,如果某些对象不是通过new操作符在内存中获取一块内存区 域,这种对象可能不能被垃圾回收机制所识别,所以在Java中提供了一个fnalize0方法。这个方法是Objet类的方法,它被声明为protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了finalize(方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才能真正回收被对象占用的内存。
由于垃圾回收不受人为控制,具体执行时间也不确定,所以finalize0方法 也就无法执行,为此,Java提供了System.gc0方法强制启动垃圾回收器,这与给120打电话通知医院来救护病人的道理一样,告知垃圾回收器进行清理。
6.2.9 this关键字
例6.8
package 第六章;
public class Book2 { //创建类
String name="abc"; //定义一个成员变量
public void showName(String name) { //定义一个showName类并从传入一个参数
System.out.println(name); //定义name
}
public static void main(String[] args) { //主方法
Book2 book=new Book2(); //在Book2类定义一个对象
book.showName("123"); //调用showName方法
}
}
从这个结果可以看出,输出的值不是成员变量的值,也就是说如果方法中出现了与局部变量同后名的参数,会导致方法无法直接使用该成员变量。
在上述代码中可以看到,成员变量与在showName()方法中的形式参数的名称相同,都为name,那么该如何在类中区分使用的是哪一个变量呢?在Java语言中规定使用this关键字来代表本类对象的引用,this 关键字被隐式地用于引用对象的成员变量和方法。
例6.9
package 第六章;
public class Book2 { //创建类
String name="abc"; //创建一个成员变量
public void showName(String name) { //调用成员变量
System.out.println(name); //定义name
}
public static void main(String[] args) { //主方法
Book2 book=new Book2(); //创建对象
book.showName("123"); //调用showName方法
}
}
在这里读者明白了this 可以调用成员变量和成员方法,但Java语言中最常规的调用方式是使用“对象.成员变量”或“对象.成员方法”进行调用(关于使用对象调用成员变量和方法的问题,将在后续章节中进行讲述)。
既然this关键字和对象都可以调用成员变量和成员方法,那么this 关键字与对象之间具有怎样的关系呢?
事实上,this 引用的就是本类的一个对象,在局部变量或方法参数覆盖了成员变量时,如上面代码的情况,就要添加this关键字明确引用的是类成员还是局部变量或方法参数。
如果省略this关键字直接写成name = name,那只是把参数name赋值给参数变量本身而已,成员变量name的值没有改变,因为参数name在方法的作用城中覆盖了成员变量name.
public class Book {
public Book getBook() {
return this;//返回Book类引用}
}
其实,this 除了可以调用成员变量或成员方法之外,还可以作为方法的返回值。
在getBook()方法中,方法的返回值为Book类,所以方法体中使用return this这种形式将Book类的对象进行返回。
介绍过this关键字,了解了this可以调用类的成员变量和成员方法,事实上this还可以调用类中的构造方法。
例6.10
package 第六章;
public class EggCake { //创建类
int eggCount; // 鸡蛋灌饼里有几个蛋
public EggCake(int eggCount) { // 有参数构造方法,参数是给饼加蛋的个数
this.eggCount = eggCount; //新建数组
System.out.println("这个鸡蛋灌饼里有" + eggCount + "个蛋。"); // 无参数构造方法,默认给饼加一个蛋
}
public EggCake() { //方法名
this(1); //调用方法
}
public static void main(String[] args) { //主方法
EggCake cake1 = new EggCake(); //在EggCake里创建一个对象
EggCake cake2 = new EggCake(5); //在EggCake里创建一个对象
}
}
6.3 static 关键字
由static修饰的变量、常量和方法被称作静态变量、静态常量和静态方法,也被称为类的静态成员。静态成员是属于类所有的,区别于个别对象。
6.3.1 静态变量
很多时候,不同的类之间需要对同- 个变量进行操作,比如一个水池,同时打开入水口和出水口,进水和出水这两个动作会同时影响到池中的水量,此时池中的水量就可以认为是一一个共享的变量。在Java程序中,把共享的变量用static 修饰,该变量就是静态变量。
可以在本类或其他类使用类名和“”运算符调用静态变量。
语法如下:
类名.静态类成员
例6.11
public class H6_11 { //创建类
static public int water = 0;
public void outlet() { // 放水,一次放出2个单位
if (water >= 2) { //定义water大于或等于2
water = water - 2; //水量减2
} else { //else语句
water = 0; //定义水等于0
}
}
public void inlet() { // 注水,一次注入3个单位
water = water + 3; //水量加3
}
public static void main(String[] args) { //主方法
H6_11 out = new H6_11(); //在Pool类里创建一个对象
H6_11 in = new H6_11(); //在Pool类里创建一个对象
System.out.println("水池的水量:" + H6_11.water); //输出水池的水量
System.out.println("水池注水两次。"); //水池注水两次的量
in.inlet(); //调用注水方法
in.inlet(); //调用注水方法
System.out.println("水池的水量:" + H6_11.water); //输出水池的水量
System.out.println("水池注水一次。"); //水池注水一次的量
out.outlet(); //调用防水方法
System.out.println("水池的水量:" + H6_11.water); //输出信息
}
}
例6.12
public class StaticVariable { //创建类
static int x; // 静态变量
int y; // 普通成员变量
public StaticVariable(int x, int y) { // 构造函数
this.x = x; //调用静态变量并初始化
this.y = y; //调用成员变量并初始化
}
public static void main(String[] args) { //主方法
StaticVariable a = new StaticVariable(1, 2); //在类里创建一个对象并赋值
StaticVariable b = new StaticVariable(13, 17); //在类里创建一个对象并赋值
System.out.println("a.x的值是 = " + a.x); //输出a.x
System.out.println("a.y的值是 = " + a.y); //输出a.y
System.out.println("b.x的值是 = " + b.x); //输出b.x
System.out.println("b.y的值是 = " + b.y); //输出b.y
}
}
6.3.2 静态常量
有时,在处理问题时会需要两个类共享一个数据常量。 例如,在球类中使用PI这个常量,可能除了本类需要这个常量之外,在另外一个圆类中也需要使用这个常量。这时没有必要在两个类中同时创建PI这个常量,因为这样系统会将这两个不在同一个类中的常量分配到不同的内存空间中,门费了系统资源。为了解决这个问题,可以将这个常量设置为静态的。PI常量在内存中被共享的布局。
例6.13
public class Graphical { //创建类
final static double PI = 3.1415926; // 创建静态常量π
public static void main(String[] args) { //主方法
double radius = 3.0; // 半径
double area = Graphical.PI * radius * radius; // 计算面积
double volume = 4 / 3 * Graphical.PI * radius * radius * radius; // 计算体积
Circular yuan = new Circular(radius, area); //在类里创建一个对象
Spherical qiu = new Spherical(radius, volume); //在类里创建一个对象
}
}
class Circular { //类名
double radius; // 半径
double area; // 面积
public Circular(double radius, double area) { //赋值double类型
this.radius = radius; //调用变量并初始化
this.area = area; //调用变量并初始化
System.out.println("圆的半径是:" + radius + ",圆的面积是:" + area); //输出圆的半径
}
}
class Spherical { //类名
double radius; // 半径
double volume; // 体积
public Spherical(double radius, double volume) { //赋值double类型
this.radius = radius; //调用变量并初始化
this.volume = volume; //调用变量并初始化
System.out.println("球的半径是:" + radius + ",球的体积是:" + volume); //输出球的半径
}
}
6.3.3 静态方法
如果想要使用类中的成员方法,需要先将这个类进行实例化,但有些时候不想或者无法创建类的对象时,还要调用类中的方法才能够完成业务逻辑,此时就可以使用静态方法。调用类的静态方法,无需创建类的对象。
例6.14
public class StaticMethod { //创建类
static public void show() { //定义静态方法
System.out.println("静态方法无需实例化就可以调用"); //输出静态方法无需实例化就可以调用
}
public static void main(String[] args) { //主方法
StaticMethod.show(); //使用类名调用静态方法
}
}
6.3.4 静态代码块
在类中除成员方法之外,用static修饰代码区域可以称之为静态代码块。定义一块静 态代码块,可以完成类的初始化操作,在类声明时就会运行。
语法如下:
public class staticTest {
static { //此处编辑执行语句}
}
例6.15
public class StaticTest { //创建类
static String name; //普通类
static { //普通类
System.out.println(name + "静态代码块"); //静态代码块
}
{
System.out.println(name+"非静态代码块"); //非静态代码块
}
public StaticTest(String a) { //公开类
name = a; //定义name=a
System.out.println(name + "构造方法"); //输出构造方法
}
public void method() { //公开类
System.out.println(name + "成员方法"); //输出成员方法
}
public static void main(String[] args) { //主方法
StaticTest s1; // 声明的时候就已经运行静态代码块了
StaticTest s2 = new StaticTest("s2"); // new的时候才会运行构造方法
StaticTest s3 = new StaticTest("s3"); // new的时候才会运行构造方法
s3.method(); //只有调用的时候才会运行
}
}
6.4 类的主方法
主方法是类的入口点,它定义了程序从何处开始;主方法提供对程序流向的控制,Java 编译器通过主方法来执行程序。主方法的语法如下:
public static void main (string [] arge){
//方法体
}
在主方法的定义中可以看到主方法具有以下特性。
(1)主方法是静态的,所以如要直接在主方法中调用其他方法,则该方法必须也是静态的
(2)主方法没有返回值
(3)主方法的形参为数组。其中args[0]~args[n]分别代表程序的第一个参数到第n+I个参数,可以args.length获取参数的个数。
例6.16
public class TestMain1 { //创建类
public static void main(String[] args) { //主方法
for (int i = 0; i < args.length; i++) { // 根据参数个数做循环操作
System.out.println(args[i]); // 循环打印参数内容
}
}
}
在Eclipse中设置程序参数的步骤如下:
(1) 在Eipsce,在包资源管理器的项目名称节点上单击鼠标右键,在弹出的快捷菜单中选择"Run As" "Run Configurations" 命令,弹出Run Configurations对话框。
(2)在Run Configurations对话框中选择Arguments选择卡,在Program arguments 文本框中输入相应的参数,每个参数间按<Enter>键隔开。
6.5 小结
本章学习了面向对象的概念、类的定义、成员方法、类的构造方法、主方法以及对象的应用等。通过对本章的学习,读者应该掌握面向对象的编程思想,这对Java的学习十分有帮助,同时在此基础上读者可以编写类,定义类成员、构造方法、主方法以解决一些实际问题。 由于在Java中通过对象来处理问题,所以对象的创建、比较、销毁的应用就显得非常重要。初学者应该反复揣摩这些基本概念和面向对象的编程思想,为Java语言的学习打下坚实的基础。