一.面向对象
面向对象的概念
面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。当然,一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易得到维护。
在程序开发初期人们使用结构化开发语言,但随着软件的规模越来越庞大,结构化语言的弊端也逐渐暴露出来,开发周期被无休止地拖延,产品的质量也不尽如人意,结构化语言已经不再适合当前的软件开发。这时人们开始将另一种开发思想引入程序中,即面向对象的开发思想。面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及行为,以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象设计实质上就是对现实世界的对象进行建模操作。
在现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即静态部分与动态部分。静态部分,顾名思义,就是不能动的部分,这个部分被称为“属性”,任何对象都具备其自身属性,如一个人,其属性包括高矮、胖瘦、性别、年龄等。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。在计算机的世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。例如,现在面临一只大雁 要从北方飞往南方这样一个实际问题,试着以面向对象的思想来解决这一实际问题。 步骤如下:
(1)首先可以从这一问题中抽象出对象,这里抽象出的对象为大雁。
(2)然后识别这个对象的属性。对象具备的属性都是静态属性,如大雁有一对翅膀、黑色的羽毛等。这些属性。
(3)接着识别这个对象的动态行为,即这只大雁可以进行的动作,如飞行、觅食等,这些行为都是这个对象基于其属性而具有的动作。
(4)识别出这个对象的属性和行为后,这个对象就被定义完成了,然后可以根据这只大雁具有的特性制定这只大雁要从北方飞向南方的具体方案以解决问题。 究其本质,所有的大雁都具有以上的属性和行为,可以将这些属性和行为封装起来以描述大雁这类动物。 由此可见,类实质上就是封装对象属性和行为的载体,而对象则是类抽象出来的一个实例。
不能将所谓的一个事物描述成一类事物, 如一只鸟不能称为鸟类。如果需要对同一类事物统称,就不得不说明类这个概念。
类的封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类
(1)封装性
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装思想。采用封装思想保证了类的内部数据结构的完整性,使用类的用户不能轻易地操作类的数据结构,只能执行类允许公开的数据,这样子避免了外部操作和内部数据影响,提高了程序的可维护性。
(2)继承性
继承性主要描述的是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展。继承不仅增强了代码的复用性、提高开发效率,还为程序的维护补充提供了便利。
(3)多态性
多态性指是在程序中允许出现重名的现象,它指在一个类中定义的属性和方法被其他类继承后,它们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同类中具有不同的语义。
二.类的定义
(1)对象
在面向对象的思想中,最核心的就是对象,为了在程序中创建对象,首先需要定义一个类,类是对象的抽象,它用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也被称作属性,成员方法用于描述对象的行为,可简称为方法。
(2)对象的创建与使用
应用程序想完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象。在java程序中可以使用new关键字来创建对象,具体格式如下:
类名 对象名称 =new 类名();例如,创建person类的实例对象代码如下:person p=new person();
类就是同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟具有一-对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有翅膀这个特性和飞行的技能,这样具有相同特性和行为的- -类事物就称为类,类的思想就是这样产生的。类是封装对象属性和行为的载体。反过来说,具有相同属性和行为的一类实体被称为类。
(3)类的封装
在设计一个类时,应该对成员变量的访问作出一些限定,不允许外界随意访问,这就鸳要实现类的封装。
所谓类的封装是指在定义一个类时,将类中的属性私有化,即使用private关键字来修饰,私有属性只能在它所在类中被访问,如果外界想要访问私有属性,需要提供一些使用public修饰的公有方法,其中包括用于获取属性值的get()方法和设置属性值的set()方法。
权限修饰符
java中的权限修饰符主要包括private、public和protected,这些修饰符控制着对类和类的成员变量以及成员方法的访问。
2.成员变量
在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样,语法如下:其中,[=值]表示可选内容,即定义变量时可以为其赋值,也可以不为其赋值。为了了解成员变量,首先定义一个鸟类,成员变量对应于类对象的属性,在Bird类中设置4成员变量,分别为wing、claw、beak 和feather,分别对应于鸟类的翅膀、爪子、喙和羽毛。
public class Bird {String wing; //翅膀
String claw; //爪子
String beak; //喙
String feather; //羽毛
根据以上代码,读者可以看到在Java中使用class 关键字来定义类,Bird 是类的名称。同时Bird类中定义了4个成员变量,成员变量的类型可以设置为Java中合法的数据类型,其实成员文就是普通的变量,可以为它设置初始值,也可以不设置初始值。如果不设置初始值。
在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样,语法如下:
在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样,语法如下:
数据类型 变量名称 [ =值] ;
2.2 成员方法
在Java语言中,成员方法对应于类对象的行为,它主要用来定义类可执行的操作,它是包含系列语句的代码块,本节将对成员方法进行详细讲解。
1.成员方法的定义
[权限修饰符] [返回值类型]方法名( [参数类型参数名] ) [throws 异常类型] {..//方法体
return 返回值;
其中,“权限修饰符”可以是private、public、 protected 中的任一一个, 也可以不写,主要用来控制方法的访问权限,关于权限修饰符将在下章中详细讲解;“返回值类型”指定方法返回数据 的类型,可以是任何类型,如果方法不需要返回值,则使用void 关键字;一个成 员方法既可以有参数,也可以没有参数,参数可以是对象也可以是基本数据类型的变量。
如果定义的方法有返回值,则必须使用returm关键字返回一个指定类型的数据,并且返回值类型要与方法返回的值类型一致, 例如,定义一个返回值类型为 int的方法, 就必须使用retum返回一个int类型的值。
2.成员方法的参数
调用方法时可以给该方法传递一个或多 个值,传给方法的值叫做实参,在方法内部,接收实参的变量叫做形参,形参的声明语法与变量的声明语法样。 形参只在方法内部有效。Java 中方法的参数主要有3种,分别为值参数、引用参数和不定长参数。
(1)值参数
值参数表明实参与形参之间按值传递,当使用值参数的方法被调用时,编译器为形参分配存储单元,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以,在方法中对值类型的形参的修改并不会影响实参。
注意:定义成员方法的语法格式如下:[权限修饰符][返回值类型]方法名([参数类型 参数名])[throws 异常类型]{…//方法体return 返回值;
代码6.1
结果
(2)引用参数
如果在给方法传递参数时,参数的类型是数组或者其他引用类型,那么,在方法中对参数的修改会反映到原有的数组或者其他引用类型上,这种类型的方法参数,我们称之为引用参数。
代码6.2
结果
(3)不定长参数
声明方法时,如果有若干个相同类型的参数,可以定义为不定长参数
代码6.3
结果
2.3 成员变量使用方法
代码6.4
运行结果如下:
2.4 构造方法
在类中除了成员方法之外,还存在一-种特殊类型的方法,那就是构造方法。构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化-一个对象时,类都会自动调用构造方法。
(1)构造方法没有返回类型,也不能定义为void.
(2)构造方法的名称要与本类的名称相同。
(3)构造方法的主要作用是完成对象的初始化工作,它能把定义对象的参数传给对象成员。
class Book{undefined
public Book( ){ //构造方法
}}
Public: 构造方法修饰符。\nBook: 构造方法的名称。
在构造方法中可以为成员变量赋值,这样当实例化一一个本类的对象时,相应的成员变量也将被初始化。如果类中没有明确定义构造方法,则编译器会自动创建一个不带参数的默认构造方法除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,即有参数构造方法。
class Book{undefined
public Book( int args){ //有参数构造方法
//对成员变量进行初始化
}
}
public:构造方法修饰符。
Book:构造方法的名称。
args:构造方法的参数,可以是多个参数。
构造方法除了可以用public修饰以外,还可以用private修饰,即私有的构造方法,私有法无法使用new创建对象,这时需要使用静态方法生成类的对象。
代码6.5
运行结果如下:
2.4 局变量
如果在成员方法内定义一个变量,那么这个变量被称为局部变量。
局部变量在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作或被初始化,否则会出现编译错误。
2.5局部变量的有效范围
可以将局部变量的有效范围称为变量的作用域局部变量的有效范围从该变量的声明开始到该变量的结束为止
对象的创建
在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
运行结果:
访问对象的属性和行为
用户使用 new 操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。前文已经提到过,对象的属性和行为在类中是通过类成员变量和成员方法的形式来表示的,所以当对象获取类成员时,也相应地获取了对象的属性和行为。
6.7代码
运行结果如下:
在上述代码的主方法中首先实例化一一个对象, 然后使用“”操作符调用类的成员变量和成员方法。但是在运行结果中可以看到,虽然使用两个对象调用同一个成员变量,结果却不相同,因为在打印这个成员变量的值之前将该值重新赋值为60,但在赋值时使用的是第二个对象t2调用成员变量,所以在第一个对象 t1调用成员变量打印该值时仍然是成员变量的初始值。由此可见,两个对象的产生是相互独立的,改变了t2的i值,不会影响到t1的i值。在内存中这两个对象的布局。
对象的销毁
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址会被回收。在其日一扫他语言中需要手动回收废弃的对象,但是Java拥有-套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的但占用内存的资源。
虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象,如果某些对象不是通过new操作符在内存中获取一块内存区 域,这种对象可能不能被垃圾回收机制所识别,所以在Java中提供了一个fnalize0方法。这个方法是Objet类的方法,它被声明为protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了finalize(方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才能真正回收被对象占用的内存。
由于垃圾回收不受人为控制,具体执行时间也不确定,所以finalize0方法 也就无法执行,为此,Java提供了System.gc0方法强制启动垃圾回收器,这与给120打电话通知医院来救护病人的道理一样,告知垃圾回收器进行清理。
在谈到垃圾回收机制之前,首先需要了解何种对象会被 Java 虚拟机视为垃圾。主要包括以下两种情况:
(1)对象引用超过其作用范围,这个对象将被视为垃圾。
(2)将对象赋值为null。
this 关键字
6.8代码如下:
运行结果如下:
从这个结果可以看出,输出的值不是成员变量的值,也就是说如果方法中出现了与局部变量同后名的参数,会导致方法无法直接使用该成员变量。在上述代码中可以看到,成员变量与在showName()方法中的形式参数的名称相同,都为name,那么该如何在类中区分使用的是哪一个变量呢?在Java语言中规定使用this关键字来代表本类对象的引用,this 关键字被隐式地用于引用对象的成员变量和方法。
7.1类的封装
封装是面向对象编程的核心思想,将对象的属性性和行为封装起来,其载体就是类
7.1代码
代码如下:
System.out.println(\"**请让厨师给我切一点葱花。***\");\n\nSystem.out.println(cookName+\"搅鸡蛋\"); //被乱改之后\n\n System.out.println(\"**请让厨师为我做一份清蒸鱼。***\");\n\nSystem.out.println(cookName+\"你是我的小呀小苹果~\");//被乱改之后
7.2代码
public class H7_2 {//创建类
public static void main(String[] args) {//主函数
Cook1 cook = new Cook1(); // 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***"); //输出
cook.cooking("香辣肉丝"); // 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");//输出**你们的厨师叫什么名字?***
System.out.println(cook.name); // 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");//输出**请让厨师给我切一点葱花。***
cook.cutOnion(); // 厨师去切葱花
}
}
class Cook1 { //创建Cook1类
String name;// 厨师的名字
public Cook1() { //普通类
this.name = "Tom Cruise"; // 厨师的名字叫Tom Cruise
}
void cutOnion() { // 厨师切葱花
System.out.println(name + "切葱花"); //输出厨师切葱花
}
void washVegetavles() { // 厨师洗蔬菜
System.out.println(name + "洗蔬菜"); //输出厨师洗蔬菜
}
void cooking(String dish) {// 厨师烹饪顾客点的菜
washVegetavles(); //洗蔬菜
cutOnion(); //切洋葱
System.out.println(name + "开始烹饪" + dish); //输出name + "开始烹饪" + dis
}}
运行结果如下:
将厨师单独封装成一个类, 将厨师的工作定义成厨师类的行为,当我们想让厨师做菜,只能通过调用对象成员方法的方式实现,而我们却不知道这个方法到底是怎么写的,所以就无法随意修改了。餐馆没有义务告诉我们厨师的任何信息,并且厨师也不会随意受我们差遣,所以说厨师有些属性和行为是不予公开的 。
代码7.3
public class H7_3 {//创建类
public static void main(String[] args) {//主函数
Cook2 cook = new Cook2();// 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出**请让厨师为我做一份香辣肉丝。***
cook.cooking("香辣肉丝");// 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");//输出**你们的厨师叫什么名字?***
System.out.println(cook.name);// 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");//输出**请让厨师给我切一点葱花。***
cook.cutOnion();// 厨师去切葱花
}
}
class Cook2 {//创建cook2
private String name;//厨师的名字
public Cook2() {//遍历cook2
this.name = "Tom Cruise";//厨师的名字叫Tom Cruise
}
private void cutOnion() {//厨师切葱花
System.out.println(name + "切葱花");//输出name + "切葱花"
}
private void washVegetavles() {//厨师洗蔬菜
System.out.println(name + "洗蔬菜");//输出name + "洗蔬菜"
}
void cooking(String dish) {//厨师烹饪顾客点的菜
washVegetavles();//输出washVegetavles的内容
cutOnion();//输出cutOnion的内容
System.out.println(name + "开始烹饪" + dish);//输出name + "开始烹饪" + dish
}
}
运行结果如下:
其实按照日常生活场景来讲,顾客去餐馆吃饭,下单的是服务员,上菜的也是服务员, 顾客跟本没有接触厨师的机会,所以厨师这个角色是对顾客隐藏起来的,被封装在餐馆的类当中。
代码7.4
运行结果如下:
从这个例子我们就能看出,作为顾客,我始终是和服务员进行交流,再由服务员与厨师进行交流整个过程中,顾客与厨师是完全没有交集的。作为顾客,我不知道我品尝的美食是由哪位厨师用何种方法烹任出来的,这种编程模式,就是封装。
将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。
7.2类的继承
继承在面向对 象开发思想中是一个非常重要的概念,它使整个程序架构具有-定的弹性,在程\n序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性。资源包本节将详细讲解类的继承。在第6章中曾简要介绍过继承,其基本思想是基于某个父类的扩展,制定出一个新的子类,子类可以继承承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父空中的某些方法。例如,平行四边形是特殊的四边形,可以说平行四边形类继承了四边形类,这时江边形类将所有四边形具有的属性和方法都保留下来,并基于四边形类展了一些新的平行四边形类特有的属性和方法。
7.3 extends 关键字
在Java中,让一个类继承另一个类,用extends关键字,语法如下:
child extends parents
这里child这个类作为子类继承了parents 这个类,并继承parents中的属性和方法。举一个简单的例子:每个人都用过计算机,最常见的计算机就是台式机。后来随着科技的发展,计算机变得越来越小,台式机改良成了可移动的笔记本电脑,笔记本电脑又改良成了更轻薄的平板电脑。我们可以把普通计算机看成一个类,那么笔记本电脑和平板电脑都是这个类衔生出的子类。
注意:Java中的类只支持单继承,即一个子类只能继承一个父类。
代码7.5
运行结果如下:
从这个结果可以看出,Pad类继承了Computer类之后,虽然没有定义任何成员方法,但仍可以调用父类的方法。这个方法是从父类那继承过来的。
7.4方法的重写
1.重写的实现 继承并不只是扩展父类的功能,还可以重写父类的成员方法。重写(还可以称为覆盖)就是在子类中将父类的成员方法的名称保留,重新编写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型(重写父类成员方法的返回值类型是基于J2SE 5.0版本以上编译器提供的新功能)。在继承中还有种特殊的重写方式, 子类与父类的成员方法返回值、 方法名称、参数类型及个教完全相同,唯一不同的是方法实现内容,这种特殊重写方式被称为重构。
注意:当重写父类方法时,修改方法的修饰权限只能从小的范围到大的范围改变。
子类重写父类的方法还可以修改方法的返回值类型,但这只是在J2SE 5.0以上的版本中支持的面功能,但这种重写方式需要遵循一个原则,即重写的返回值类型必须是父类中同一方法返回值关主的子类。
7.6代码
class Computer2 {// 父类:电脑
void showPicture() {//显示图片
System.out.println("鼠标点击");//输出鼠标点击
}
}
public class H7_6 extends Computer2{//子类继承父类
void showPicture() {//显示图片
System.out.println("手指点击触摸屏");//输出手指点击触摸屏
}
public static void main(String[] args) {//主函数
Computer2 pc = new Computer2();// 电脑类
System.out.print("pc打开图片:");//输出pc打开图片:
pc.showPicture();// 调用方法
H7_6 ipad = new H7_6();// 平板电脑类
System.out.print("ipad打开图片:");//输出ipad打开图片:
ipad.showPicture();// 重写父类方法
Computer2 computerpad = new H7_6();// 父类声明,子类实现
System.out.print("computerpad打开图片:");//输出computerpad打开图片:
computerpad.showPicture();// 调用父类方法,实现子类重写的逻辑
}
}
运行结果如下:
从这个结果我们可以看出,虽然子类调用了父类的方法,但实现的是子类重写后的逻辑, 而不是父类原有的逻辑。如果父类声明的对象是由子类实例化的,那么这个对象所调用的方法也是被子类重写过的。
注意:在Java语言中,一个类只可以有一个父类!
7.5super 关键字
如果子类重写了父类的方法,就再也无法调用到父类的方法了吗?如果想在子类的方法中实现父类原有的方法怎么办?为了解决这种需求,Java 提供了super 关键字。
super关键字的使用方法与this关键字类似。this 关键字代表本类对象,super 关键宇代表父类对象,使用方法如下:
super.property;
//调用父类的属性\n\nsuper.method();
//调用父类的方法
代码7.7
运行结果如下:
注意:如果子类构造方法中使用类似super()的构造方法,其他初始化代码只能写在super()之后,不能写在前面,否则会报错。
7.6所有类的父类——Object类
在开始学习使用class关键字定义类时,就应用了继承原理,因为在Java中,所有的类都直接或间接继承了java.lang.Object 类。Object 类是比较特殊的类,它是所有类的父类,是Java类层中的最高层类。当创建一一个类时,总是在继承,除非某个类已经指定要从其他类继承,否则它就是从java.lang.Object类继承而来的,可见Java中的每个类都源于java.lang.Object 类,如String、Integer 等类都是继承于Object类;除此之外自定义的类也都继承于Object类。由于所有类都是Object子类,所以在定义类时,省略了extends Object关键字,如图7.10所示便描述了这一原则。
在Object类中主要包括clone(、finalize(、equalsO、toString0等方法,其中常用的两个方法为equals()和 toString0方法。由于所有的类都是Object 类的子类,所以任何类都可以重写Object类中的方法。
Object的重要方法:
1. getClass( )方法
getClass0方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName0方法可以取得类的名称。
getClass( ) . getName( );
可以将getClass0方法与toString0方法联合使用。
toString( )方法
toString0方法的功能是将一一个对象返回为字符串形式, 它会返回一 个String 实例。在实际的应用中通常重写toString( )方法,为对象提供一个特定的输出模式。当这个类转换为字符串或与字符串连接时,将自动调用重写的toString0方法。的重要方法
代码7.8
运行结果如下:
在本实例中重写父类Object的toString( )方法,在子类的toString( )方法中使用Object 类中曲getClass( )方法获取当前运行的类名,定义一段输出字符串,当用户打印ObjectInstance类对象时,将自动调用toString( )方法。
7.7equals()方法
前面章节曾讲解过equals()方法,当时是比较“==”运算符与equalsl()方法,说明“==”比较的是两个对象的引用是否相等,而equals0方法比较的是两个对象的实际内容。
代码7.9
运行结果如下:
抽象类
1,当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的。
7.8类的多态
多态意为一个名字可具有多种语义,在程序设计语言中,多态性是指“一种定义,多种实现”例如,运算符“+”作用于两个整型量时是求和,而作用于两个字符型量时则是将其连接在一起。利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。
类的多态性可以从两方面体现:一是方法的重载,二是类的上下转型。
.静态方法
a,只要在类中定义的方法前加上static关键字
b,同静态变量一样,静态方法可以使用“类名.方法名”的方式来访问,也可以通过类的实例对象来访问。
注意:在一个静态方法中只能访问用static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象
7.9方法的重载
在第6章中曾学习过构造方法,知道构造方法的名称由类名决定,所以构造方法只有一一个名称,但如果希望以不同的方式来实例化对象,就需要使用多个构造方法来完成。由于这些构造方法都需要根据类名进行命名,为了让方法名相同而形参不同的构造方法同时存在,必须用到“方法重载”。虽然方法重载起源于构造方法,但是它也可以应用到其他方法中。本节将讲述方法的重载。
东法的重获就是在网个类中允许网时存在个以 上的同名方法,只要这些方法的参数个数或类型不同即可。
代码7.10
public class H7_10 {//创建类
// 定义一个方法
public static int add(int a) {// 定义一个方法
return a;//定义a
}
public static int add(int a, int b) {// 定义与第一个方法参数个数不同的方法
return a + b;//定义a+b
}
public static double add(double a, double b) {// 定义与第一个方法相同名称、参数类型不同的方法
return a + b;//定义a+b
}
public static int add(int a, double b) {// 定义一个成员方法
return (int) (a + b);//定义a+b
}
public static int add(double a, int b) {// 这个方法与前一个方法参数次序不同
return (int) (a + b);//定义a+b
}
public static int add(int... a) {// 定义不定长参数
int s = 0;//定义s初值
for (int i = 0; i < a.length; i++) {// 根据参数个数循环操作
s += a[i];// 将每个参数的值相加
}
return s;// 将计算结果返回
}
public static void main(String args[]) {//主方法
System.out.println("调用add(int)方法:" + add(1));//输出"调用add(int)方法:" + add(1)
System.out.println("调用add(int,int)方法:" + add(1, 2));//输出"调用add(int,int)方法:" + add(1, 2)
System.out.println("调用add(double,double)方法:" + add(2.1, 3.3));//输出"调用add(double,double)方法:" + add(2.1, 3.3)
System.out.println("调用add(int a, double b)方法:" + add(1, 3.3));//输出"调用add(int a, double b)方法:" + add(1, 3.3)
System.out.println("调用add(double a, int b) 方法:" + add(2.1, 3));//输出"调用add(double a, int b) 方法:" + add(2.1, 3)
System.out.println("调用add(int... a)不定长参数方法:"+ add(1, 2, 3, 4, 5, 6, 7, 8, 9));//输出"调用add(int... a)不定长参数方法:"+ add(1, 2, 3, 4, 5, 6, 7, 8, 9)
System.out.println("调用add(int... a)不定长参数方法:" + add(2, 3, 4));//输出"调用add(int... a)不定长参数方法:" + add(2, 3, 4)
}
}
运行结果如下:
注意:虽然在方法重载中可以使两个方法的返回类型不同,但只有返回类型不同并不足以区分两个方法的重载,还需要通过参数的个数以及参数的类型来设置。
2,Java允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰
(1)接口
如果在一个抽象类的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象。
使用接口可以实现多重继承,一个类可以同时实现多个接口,于是可以将所有需要继承的接口放置implements关键字后使用逗号隔开,实现多个接口语法如下:
修饰符 class 类名 implement 接口1,接口2....{}(九)多态
(2)多态的概念
利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。
假如现在要编写一个绘制图形的方法draw(),如果传入正方形对象将绘制正方形,如果传入圆形对象就绘制圆形,这种场景可以使用重载来实现,定义如下:
public void draw(Square s){
//绘制正方形的方法
}\npublic void draw(Circular c){
//绘制圆形方法
}
接口
a,如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另一种方式来定义,即接口 。
b,接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象。
c,在定义接口时,需要使用interface关键字来声明。其语法如下:
final关键字类修饰
Java中的类被final关键字修饰后,该类将不可以被继承,也就是不能够派生子类
特征: 1,final修饰符的类不能被子类重写 2,final修饰的方法不能被子类重写
3,final修饰的变量(成员变量和局部变量)是常量,只能赋值一次
构造方法的定义
在一个类的定义方法如果同时满足这三个条件,该方法成为构造方法,具体方法如下
a、 方法名与类名相同
b、在方法名的前面没有返回值类型的声明
c、在方法中不能使用return语句返回一个值,但是可以单独写一个return语句来作为方法的结束
6.构造方法的重载:
a,一个类可以定义多个构造方法,每个构造方法的参数类型或参数个数不同即可
b,在创建对象时,可以通过调用不同的构造方法来为不同的属性进行赋值
重写父类方法
1.在继承关系中,子类会自动调用父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。
2,需注意的是,在子类中重写的方法需要和父类重写的方法具有相同的方法名,参数列表以及返回值类型
super关键字
a,当子类重写父类的方法后,子类对象将无法访问父类被重写的方法
b,使用super关键字访问父类的成员变量和成员方法
匿名内部类
Java内部类可以分为:成员内部类,方法内部类和匿名内部类等.