在日常生活中,在盖房子之前要首先设计一个建筑图纸,然后根据图纸来盖房子。所谓类,好比在日常生活中描述一个物品的信息,如房子的建筑图纸。而对象就好比实实在在的房子,编程语言同样如此。
6.1什么是面向对象
所谓面向对象,是指编写程序的时候要围绕着一个对象的功能进行编写的。
6.1.1面向对象编程的特点
面向对象编程的缩写是OOP,全称为ObjectOrientedProgramming。在进行面向对象的编程时,方法和成员变量都写在具体的对象里,并对其成员变量和方法有很好的隐藏性。对象之间的访问都是通过其接口进行的。下面列举面向对象编程的特点,分为如下几种。
首先要说的是继承。所谓继承,是发生在类与类之间的,是子类共享父类成员变量和方法的一种模式。通过扩展子类的方法可以使子类有比父类更加强大的功能。
说明:继承是面向对象编程的特点,同样也是Java的特点,这里和其他语言有很大不同。
示例代码
01//bike类描述的是一个自行车
02classbike
03{
04}
05
06//racing_cycle类描述的是一个公路赛车,继承自bike
07classracing_cycleextendsbike
08{
09}
提示:继承是发生在类与类之间的。继承可以是单继承,也可以多层继承。
多态是指对象在运行期和编译期具有两种状态,多态的使用使代码具有了更多的灵活性和重用性。
抽象是指在定义类的时候,确定了该类的一些行为和动作。比如自行车可以移动,但怎么移动不进行说明。这种提前定义一些动作和行为的类为抽象的。
封装是指对一件物品的描述信息是这个物品所特有的,是不能让外界看到的一些成员变量和方法。在Java里成员变量和方法就被封装在类里,需要通过一些特有的方法访问它们。
6.1.2面向对象编程与面向过程编程的区别
面向过程是指在遇到问题的时候,怎么去解决这个问题,而分析问题的步骤,就是解决这个问题的方法,是通过方法一步一步来完成的。面向对象是指在遇到问题的时候,把问题分解成各自独立功能的类,而这个类是完成各自问题的。总结如下所述。
面向过程和面向对象最明显的区别就是,面向对象是按照要完成的功能来实现的,而面向过程是按照解决这个问题的步骤来实现的。
面向对象是按照程序中的功能进行划分的。
面向过程是按照问题的解决思路来划分的,是一步一步来解决问题的。
面向过程更看重的是完成问题的过程。
面向对象更看重的是功能,通过各种功能模块的组合来完成问题。
6.2什么是类
所谓类是一种抽象的东西,描述的是一个物品的完整信息。比如房子和图纸的关系。在Java里,图纸就是类,定义了房子的各种信息,而房子是类的实体。
6.2.1类的定义和对象的创建
定义一个类表示定义了一个功能模块。下面先介绍如何定义一个类,以及如何创建这个类的实例,即对象。类是通过关键字class来定义的,在class关键字后面加上类的名称,这样就创建了一个类。在类里面可以定义类的成员变量和方法。类的语法代码如下所示。
class类的名称
{
//类的成员变量
//类的方法
}
创建类的实例是通过new关键字来定义的,后面加上定义类时为类起的名称,需要注意的是在类名后还需要一个括号。创建类的实例的代码如下所示。
new类的名称();
6.2.2如何使用现有类
在定义一些类的时候,如何使用它们呢?这里需要分为多种情况。定义的类可以在一个包下面,也可以不在一个包下面,这在使用时是不同的。类又分为已有类和自定义类,它们之间的使用也是有区别的。下面就通过范例来讲解在不同情况下如何使用类。
【范例】在同目录下使用类。首先是定义一个bike类,在该类中不存在任何成员变量和方法,这里只是演示如何在同一目录下使用类。
示例代码
01//bike.java
02classbike
03{
04}
接下来定义一个使用bike类的类。
01//testBike.java
02//在testBike类里使用了bike类
03classtestBike
04{
05bikeb=newbike();
06}
6.2.3类设计的技巧
设计一个类要明确这个所要完成的功能,类里的成员变量和方法是描述类的功能的。如果定义了和这个类不相关的成员变量和方法将不是一个良好的设计。
【范例】示例代码是一个不太好的类设计。
示例代码
01publicclassbike
02{
03//这个成员变量描述的是自行车的颜色.
04Stringcolor="黄色";
05
06//这个成员变量描述的是公路赛车的颜色,所以在这里不太合适
07Stringracing_color="绿色";
08}
在本程序中定义了一个表示自行车颜色的color成员变量,又定义了一个表示赛车颜色的racing_color成员变量;而该程序是定义的一个bike自行车类,所以定义表示赛车颜色的racing_color成员变量是不太好的选择。
【范例6-8】示例代码6-8是一个良好的类设计。
示例代码6-8
01publicclassbike
02{
03//这个成员变量描述的是自行车的颜色
04Stringcolor="黄色";
05}
01publicclassracing
02{
03//这个成员变量描述的是公路赛车的颜色
04Stringracing_color="绿色";
05}
【代码解析】在该范例中,定义了两个类。其中bike类中只定义了一个表示自行车颜色的color成员变量。同样在racing类中只定义了一个表示赛车颜色的racing_color成员变量。这种设计相对上一个范例中的设计要好得多,这样使类和成员变量相对应,也使别人更容易读懂代码。
6.3成员变量
所谓成员变量就是这个类里定义的一些私有的变量.,这些变量是属于这个类的。就好比日常生活中的自行车的大小,即这个车子是26还是28的,这个尺寸就是自行车的成员变量,是描述这个自行车的。下面开始介绍成员变量。
6.3.1成员变量的创建
成员变量描述的是这个类的一些属性或状态的,下面通过代码来演示怎么定义成员变量。语法为:变量的类型变量的名称。
【范例】创建成员变量的一般形式。
示例代码
01//bike类描述的是一个自行车
02publicclassbike
03{
04//这个成员变量描述的是自行车的颜色.
05Stringcolor;
06
07//这个成员变量描述的是自行车的大小,即尺寸.
08Stringsize;
09}
在该程序中,定义了一个叫做bike的类,在该类中定义了两个成员变量,一个是表示自行车颜色的color成员变量,一个是表示自行车型号的size成员变量。
下面看一个创建成员变量的完整形式。
代码讲解
通过new关键字来创建这个bike类的对象,用bike类的对象引用b来给其成员变量赋值。因为成员变量是在这个类实例化后才能访问到的。成员变量赋完值后,调用println语句来打印并显示结果。
6.3.2成员变量的初始化
通过new关键字来创建一个对象后,会有一个系统默认的初始值。所以说不管有没有在创建成员变量的时候给变量一个值,系统都会有一个默认的值。
成员变量和对象的引用在申明的时候不对其赋初值,那么系统都会赋一个初值,具体的信息如表所示。
6.4局部变量
局部变量和成员变量很相似都是描述信息的。局部变量和成员变量的不同点就是局部变量是在方法体里创建的,在方法体外是访问不到这个变量的。
6.4.1局部变量的创建和初始化
局部变量描述的是方法体的一些属性或状态的,下面通过代码来演示怎么定义局部变量。创建局部变量的基本语法为:变量的类型变量的名称。
【范例】演示局部变量的例子。
示例代码
01//test类描述的是基本类型的初始化
02publicclasstest4
03{
04//程序的运行函数即主入口函数
05publicstaticvoidmain(Stringargs[])
06{
07//基本类型的局部变量
08intsize=123;
09booleanb=true;
10//打印并显示局部变量
11System.out.println(size);
12System.out.println(b);
13}
14}
6.4.2局部变量和成员变量的区别
局部变量描述的是这个方法体内的属性的,而成员变量描述的是这个对象里的属性的,它们之间的区别,即访问区别如下:
成员变量可以被public、protected、default、private、static、final修饰符修饰。
局部变量可以被final修饰符修饰,但不能修饰为public、protected、default、private、static。
成员变量是在堆里进行创建的,而局部变量是在栈里进行创建的。
成员变量是系统默认值。
局部变量没有系统默认值,必须手动赋值。
6.5方法
每个人都有走、吃和睡等动作。在Java中,所谓方法就好比日常生活中的一个动作,是完成一系列操作的。在Java中也是如此,方法收到对象的信息,进行处理的操作。
6.5.1方法的创建和参数
方法的参数是提供外界在执行方法的时候提供给方法的特殊描述信息的,好比日常生活中的,用力砸东西,用大力砸东西。而这个用大力就是提供给这个进行特殊描述的。
创建方法的语法为:
方法修饰符方法的返回类型方法名称(方法参数)
{
方法体
}
方法的定义如下所示。
publicvoidadd(inti,intn)
{
System.out.println(i+n);
}
代码说明:
方法名称为add,有两个参数都是int类型的。
方法体是打印i+n的值,并显示出来。
①方法的修饰符为public类型的,修饰符可有可无。
②方法的返回类型有很多种,主要分为如下几类。
③方法返回值为void类型时为无返回值。
④方法返回值还可以为任意的类型,如String、Boolean、int。如果定义了方法的返回类型就⑤必须在方法体内用return把返回值进行返回。
⑥方法的返回值可以为null,但必须是对象类型。基本类型不能返回null。
⑦在返回值为基本类型的时候,只要能够自动转换就可返回。
⑧方法的参数也有多种形式,下面是对方法参数的讨论。
⑨方法的参数可以为基本数据类型,也可以为对象引用类型。
⑩每个参数都有完整的声明该变量的形式。
⑪方法的参数可以有一个,也可有多个。
⑫Java程序的入口main就为一个方法,参数为String[]args,它是个特殊的方法。
6.5.2方法参数的传递
参数的传递是传递的值还是引用呢。下面通过例子来分别说明,请仔细考虑。
【范例】当传递类型为基本类型时,传递的是该类型的值。
01//test类描述的是基本类型的传递
02publicclasstest
03{
04//方法add是把传入的参数进行+1,并显示其结果
05publicvoidadd(inti)
06{
07i=i+1;
08System.out.println(i);
09}
10
11//程序的运行方法,即主入口方法
12publicstaticvoidmain(Stringargs[])
13{
14//基本类型的局部变量
15intsize=44;
16
17//创建bike类的对象实例,即bike类的对象引用b
18testt=newtest();
19
20//打印原来的值
21System.out.println(size);
22//运行时的值
23t.add(size);
24//打印运行后的值
25System.out.println(size);
26}
27}
在参数为基本类型进行传递的时候,是传递的这个值的备份,即第二份。不论在方法中怎么改变这个备份,都不是操作原来的数据,所以原来的值是不会改变的。
当传递的参数为对象引用类型时,也是利用的传值的方式进行的。
01//test类描述的是方法的传递
02publicclasstest
03{
04publicstaticvoidmain(String[]args)
05{
06//创建一个对象类型
07Strings=newString("Hello");
08
09//打印其值
10System.out.println("before:"+s);
11
12//通过方法去改变其值
13changeString(s);
14
15//打印方法改变的值和原值
16System.out.println("changeString:"+s);
17System.out.println("after:"+s);
18}
19
20publicstaticvoidchangeString(Stringstr)
21{
22str=newString("hi");
23str=str+"china!";
24}
25}
当把对象引用s传递到一个方法后,这个方法可以改变这个对象的属性,并能返回相应的改变。但这个对象引用指向的这个字符串s是永远不会改变的。这里传递对象引用后,又通过这个引用去创建了一个新的String类型的字符串,这两个字符串在内存中当然不是同一个了。
6.6对象引用的使用
所谓对象引用就是该引用名称指向内存中的一个对象,通过调用该引用即可完成对该对象的操作。本节将要讨论一些操作对象引用中将出现的一些常见问题。如不存在的对象、空引用、对象间的比较等问题,下面分别来说明。
6.6.1调用不存在的对象或成员变量
如果调用的对象或成员变量没有创建,那么在编译的时候编译器将出现错误。下面用代码演示这个错误,并演示如何修正。
【范例】代码演示访问不存在的成员变量。
示例代码
01//test类描述的是测试访问不存在的成员变量
02publicclasstest
03{
04//main方法为程序的入口函数
05publicstaticvoidmain(String[]args)
06{
07//创建test类的对象实例
08testt=newtest();
09//t.a访问的是一个不存在的成员变量,将提示不可识别的字段。
10System.out.println(t.a);
11}
12}
运行将会发生如下异常。
Exceptioninthread"main"java.lang.Error:Unresolvedcompilationproblem:
t.acannotberesolvedorisnotafield
attest.main(test.java:7)
【代码解析】对象引用t要访问的是a这个成员变量,而a没有声明,在编译的时候将提示错误信息。在错误提示里,已经提示为main方法里的第7行,只需查看这里就能找到错误的所在。
修改上述代码使程序运行通过。
01//test类描述的是测试访问不存在的成员变量
02publicclasstest
03{
04//a为test类的成员变量
05Stringa;
06
07//main方法为程序的入口方法
08publicstaticvoidmain(String[]args)
09{
10//创建test类的对象实例
11testt=newtest();
12//t.a访问的是一个不存在的成员变量,将提示不可识别的字段
13System.out.println(t.a);
14}
15}
根据上例中的错误提示在test类声明了一个名称为a的成员变量。因为String类型的a没有进行赋值,所以打印出来为null。
6.6.2调用对象为null值的引用
任何操作的对象的值为null的时候都将出现空指针错误,即“NullPointException“错误,因为成员变量和方法是属于对象的,即属于用new关键字创建出来的对象的。下面用代码来演示这个错误,并演示如何进行修正。
01//ArrayList类所需要的
02importjava.util.ArrayList;
03
04//test类测试访问null值的对象
05publicclasstest
06{
07//声明一个成员变量a并进行初值
08publicStringa="test类的成员变量";
09
10//Java程序的主入口方法
11publicstaticvoidmain(String[]args)
12{
13//创建test类的对象实例
14testt=newtest();
15
16//创建一个集合类,对象引用为一个null值
17ArrayListal=null;
18
19//向一个null的集合对象里添加数据
20al.add(t.a);
21}
22}
ArrayList类为一个集合类和数组很相似,都是用来存储数据用的。错误提示在main方法里的20行,提示为NullPointerException,即空指针错误。对象引用al声明为一个null值,表示这个对象并没有创建其对象的实例,只是一个引用而已。当操作任意一个为null的对象的时候都将提示空指针错误。
6.6.3对象引用间的比较
两个对象引用进行比较,比较的是这两个对象的引用,而引用是在内存中的一个地址。地址当然是不能相同的了。下面通过一个例子来演示引用间的比较。
【范例】演示两个对象引用的比较。
equals方法在这里比较的是对象的引用,因为equals方法是Object类的方法,而任何类的父类都为Object,equals方法是继承过来的。继承将在后面的章节里做详细讲解。用new关键字创建的对象地址是重新分配的,它们进行比较,地址当然是不同的了。
6.7this
this是Java保留的一个关键字,所谓this就好比日常生活中的“你我他”中的我,表示自己、本身的意思。在Java里也是如此,表示类的本身。