6.1 面向对象概述
人们开始将另一种开发思想引入程序中即面向对象的开发思想。它将所有预处理的问题抽象为对象,同时了解这些时能些相应的属性以及行为,以解决这些对象面临的一些实际问题,这样就在程序开发中引入了象设计的概念,面向对象设计实质上就是对现实世界的对象进行建模操作。
6.12类
如果需要对同一类事物统称,就不得不说明类这个概念。
类就是同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟具有一对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有翅膀这个特性和飞行的技能,这样具有相同特性和行为的一类事物就称为类,类的思想就是这样产生的。对象就是符合某个类的定义所产生出来的实例。更为恰当的描述是,类是世间事物的抽象称呼,而对象则是这个事物相对应的实体。如果面临实际问题,通常需要实例化类对象来解决。
6.1.3面向对象程序设计的特点
面向对象程序设计具有以下特点:
封装性。
继承性。
多态性。
1. 封装
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类户隐藏其实现细节,这就是封装的思想。例如,用户使用计算机时,只需要使用手指能地以实现一些功能,无须知道计算机内部是如何工作的,即使可能知道计算机的工作原理, 个计算机时也并不完全依赖于计算机工作原理这些细节。
采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易地直接结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性
2.继承
继承性主要利用特定对象之间的共有属性。例如,平行四边形是四边形,正方形、矩形也是四边形,平行四边形与四边形具有共同特性,就是拥有4条边,可以将平行四边形类看作四边形的延伸,平行四边形复用了四边形的属性和行为,同时添加了平行四边形独有的属性和行为,如平行四边形的对边平行且相等。这里可以将平行四边形类看作是从四边形类中继承的。在Java语言中将类似于平行四边形的类称为子类,将类似于四边形的类称为父类或超类。值得注意的是,可以说平行四边形是特殊的四边形,但不能说四边形是平行四边形,也就是说子类的实例都是父类的实例,但不能说父类的实例是子类的实例。图6.6阐明了图形类之间的继承关系
6.2.2成员方法
在Java语言中,成员方法对应于类对象的行为,它主要用来定义类可执行的操作,它是包含一系列语句的代码块,本节将对成员方法进行详细讲解。
1.成员方法的定义
定义成员方法的语法格式如下:
[权限修饰符][这回值尖型)万法名([效突型李效名])[throws 异常类型] (
…1/方法体
return 返回值;
其中,“权限修饰符”可以是private、public、protected中的任一个,也可以不写,主要用来控制方法的访问权限,关于权限修饰符将在下一章中详细讲解;“返回值类型”指定方法返回数据的类型,可以是任何类型,如果方法不需要返回值,则使用void关键字;一个成员方法既可以有参数,山可以县其本数据类型的变量。
2. 成员方法的参数
调用方法时可以给该方法传递一个或多个值,传给方法的值叫做实参,在方法内部。
的变量叫做形参,形参的声明语法与变量的声明语法一样。形参只在方法内部有效。langs参数主要有3种,分别为值参数、引用参数和不定长参数,下面分别进行讲解。
(1)值参数
值参数表明实参与形参之间按值传递,当使用值参数的方法被调用时,编译器为形参的单元,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以,在方法中的的形参的修改并不会影响实参
3.多态
上面介绍了继承,了解了父类和子类,其实将父类对象应用于子类的特征就是多态,多态的实现并不依赖具体类,而是依赖于抽象类和接口。
下面以图形类来说明多态。
图形类作为所有图形的父类,具有绘制图形的能力,这个方法可称为“绘制图形”,但如果要执行这个“绘制图形”的命令,没有人知道应该画什么样的图形,并且如果要在图形类中抽象出一个图形对象,没有人能说清这个图形究竟是什么图形,所以使用“抽象”这个词来描述图形类比较恰当。在Java语言中称这样的类为抽象类,抽象类不能实例化对象。在多态的机制中,父类通常会被定义为抽象类,在抽象类中给出一个方法的标准,而不给出实现的具体流程。实质上这个方法也是抽象的,如图形类中的“绘制图形”方法只提供一个可以绘制图形的标准,并没有提供具体绘制图形的流程,
因为没有人知道究竟需要绘制什么形状的图形。
每个图形都拥有绘制自己的能力,这个能力可看作是该类具有的行为,如果将子类的对象统一看作是父类的实例对象,这样当绘制图形时,简单地调用父类也就是图形类绘制图形的方法即可绘制任何图形,这就是多态最基本的思想。图6.7的图形类中绘制图形的方法很好地体现了面向对象的多态思想。
例6.1定义一个add方法,用来计算两个数的和,该方法中有两个形参,但在方法体中,其中的一个形参x执行加y操作,并返回x;在main方法中调用该方法,为该方法传入定义好参;最后分别显示调用add方法计算之后的x值和实参x的值。代码如下:
public class Book {
public static void main(String[] args) {
Book book=new Book();//创建book对象
int x=30;//定义实参变量
int y=40;//定义实参变量
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
}
}
例6.2定义一个change方法,该方法中有一个形参,类型为数组类型,在方法体中,改变数组的索引0、1、2这3处的值;在main方法中定义一个一维数组并初始化,然后将该数组作为参要传递给change方法,最后输出一维数组的元素。代码如下
-
public class RefTest { public static void main(String[] args) { RefTest refTest = new RefTest();//创建 RefTest 对象 int[] i= {0,1,2 };//定义一维数组,作为方法的实参//输出一维数组的原始元素值 System.out.print("原始数据:"); for(int j=0;j<i.length;j++) { System.out.print(i[j]+" ");} refTest.change(i);//调用方法改变数组元素的值 System.out.print("\n修改后的数据:"); for(int j = 0; j < i.length; j++) { System.out.print(i[j]+" ");}} //定义一个方法,方法的参数为一维数组(形参) public void change(int [] i) { i[0]=100; i[1]= 200; i[2]= 300; } }
例6.3定义一个add方法,用来计算多个int类型数据的和,在具体定义时,将参数定义。类型的不定长参数:在main方法中调用该方法,为该方法传入多个 iat类型的数据,并输出计意果。代码如下:
-
public class MultiTest { public static void main(String[] args) { MultiTest multi=new MultiTest();//创建MutiTest对象 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;//返回运算结果 } }
2.3 构造方法
在类中除了成员方法之外,还存在一种特殊类型的方法,那就是构造方法。构造方法是同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自造方法。
构造方法的特点如下:(1)构造方法没有返回类型,也不能定义为void。
(2)构造方法的名称要与本类的名称相同。
(3)构造方法的主要作用是完成对象的初始化工作,它能把定义对象的参数传给对象构造方法的定义语法如下:
class Book{
public book(){//构造方法
}}
例6.4创建猎豹类,用成员方法实现猎豹的行为。
-
public class Leopard { public void gaze(String target){//凝视。目标是参数targe System.out.println("猎豹凝视:"+ target); } public void run() {// 奔跑 System.out.println("猎豹开始奔跑"); } public boolean catchPrey(String prey){//捕捉猎物,返回捕捉是否成功 System.out.println("猎豹开始捕捉"+prey); return true;// 返回成功 } public void eat(String meat){//吃肉,参数是肉 System.out.println("猎豹吃"+ meat); } public void sleep(){// 睡觉 System.out.println("猎豹睡觉");} public static void main(String[] arge) { Leopard liebao=new Leopard(); liebao.gaze("羚羊"); liebao.run(); liebao.catchPrey("羚羊"); liebao.eat("羚羊肉"); liebao.sleep(); } }
在构造方法中可以为成员变量赋值,这样当实例化一个本类的对象时,相应的成员刻初始化。如果类中没有明确定义构造方法,则编译器会自动创建一个不带参数的默认相题
除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,public:构造方法修饰符。
Book:构造方法的名称。
args:构造方法的参数,可以是多个参数。构造方法除了可以用public修饰以外,还可以用private修饰,即私有的构造方法,私有法无法使用new创建对象,这时需要使用静态方法生成类的对象。
例6.5创建一个图书类,将构造方法设为私有,这时如果需要创建图书类的对象,只能定义一个static方法,并调用该静态方法生成图书类的对象
-
public class BookTest { private BookTest() {//私有构造方法 }static public BookTest libraryBorrow() {//创建静态方法,返回本类实例对象 System.out.println("通过调用静态方法创建对象"); return new BookTest(); } public static void main(String[] args) {//创建一个书的对象,不是new实例化的,而是通过方法从图书馆借来的 BookTest book=BookTest.libraryBorrow(); } }
6.2.4局部变量
如果在成员方法内定义一个变量,那么这个变量被称为局部变量。 扫一扫,看
局部变量在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操
作或被初始化,否则会出现编译错误。例如,在项目中创建一个类文件,在该类中定义getName)方法并进行调用。
public String getName(){ //定义一个 getName()方法
int id=0;//局部变量
setName("Java"); //调用类中其他方法
return id+this.name; //设置方法返回值}
例6.6在项目中创建CreateObject类,在该类中创建对象并在主方法中创建对象。
-
public class CreateObject { public CreateObject() {//构造方法 System.out.println("创建对象"); } public static void main(String[] args) { new CreateObject();//创建对象 } }
6.2.7 访问对象的属性和行为
用户使用new操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。前文已经提到过,对象的属性和行为在类中是通过类成员变量和成员方法的形式来表示的,所以当对象获取类成员时,也相应地获取了对象的属性和行为。例6.7在项目中创建TransferProperty类,在该类中说明对象是如何调用类成员的。
public class TransferProperty { int i=47; public void call() { System.out.println("调用call()方法"); for(i=0;i<3;i++) { System.out.println(i+""); if(i==2) { System.out.println("\n"); }}} public TransferProperty() { //定义构造方法 } public static void main(String[] args) {//创建一个对象 TransferProperty t1 = new TransferProperty(); //创建另一个对象 TransferProperty t2 = new TransferProperty(); //将类成员变量赋值为60 t2.i = 60; //使用第一个对象调用类成员变量 System.out.println("第一个实例对象调用变量1的结果:"+t1.i); t1.call(); //使用第一个对象调用类成员方法 //使用第二个对象调用类成员变量 System.out.println("第二个实例对象调用变量i的结果:"+t2.i); t2.call(); //使用第二个对象调用类成员方法 } }
例6.13将π的值赋给静态常量PI,使用PI计算圆类的面积和球类的体积
-
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) { this.radius = radius; this.area = area; System.out.println("圆的半径是:"+ radius+",圆的面积是:"+ area); }} class Spherical{ double radius;// 半径 double volume;// 面积 public Spherical(double radius, double volume) { this.radius = radius; this.volume= volume; System.out.println("球的半径是:"+ radius+",球的面积是:"+ volume); }}
本章小结
面向对象程序设计以对象为核心,该方法认为程序由一系列对象组成。类是对现实世界的抽象,包括表示静态属性的数据和对数据的操作,对象是类的实例化。在面向对象的程序设计中,对象是组成程序的基本模块继承关系是通过 extends 关键字产生的,如果我们要设计的多个类中存在相同属性和方法,那我们在设计中可以将这些内容抽取到单独一个类中,让另外的类继承这个父类,就无需再定义这些属性和行为。
子类可以直接访问父类中的非私有的属性和行为,也就是无法继承父类中私有的内容,我们要了解到这一点。这提高了我们在编写代码时的复用性。
封装
第一层意思:将数据和操作捆绑在一起,创造出一个新的类型的过程。第二层意思:将接口与实现分离的过程。
数据抽象的概念可以在保持外部接口不变的情况下改变内部实现,从而减少甚至避免对外界的干扰;通过继承大幅减少冗余的代码,并可以方便地扩展现有代码,提高编码效率.
构造方法分为两种:无参构造方法 有参构造方法
构造方法只有在使用new创建对象的时候才会运行。
成员方法只有在使用对象调用的时候才会运行。无参构造的作用是:实例化一个对象
有参构造的作用是:初始化类中的属性
静态方法与静态代码块的区别就是:
1、静态方法是被调用的时候执行。
2、静态代码块是自动执行的相同点:静态代码块和非静态代码块都是jvm加载类时且构造方法之前执行的,在类中都可以定义多个,一般在代码块中对一些static变量赋值。
不同点:静态代码块在非静态代码块之前执行,静态代码块在只在第一次new时执行一次,而非静态代码块在每次new一次就执行一次。普通代码块可以在普通方法中定义,而静态代码块不可以。