Java之二 面向对象

网友投稿 674 2022-05-30

Java 语言的历史和现状

Java的类

对 象 实 例

实 例 变 量

new操 作 符

对象操作符——点

成 员 函 数 定 义

成 员 函 数 调 用

This 关键字

构 造 函 数(Constructor)

Java的类

视频课堂:https://edu.csdn.net/course/play/8222

类是Java语言面向对象编程的基本元素,它定义了一个对象的结构和行为。在Java程序里,你要表达的概念封装在某个类里。一个类定义了一个对象的结构和它的功能接口,功能接口称为成员函数。当Java程序运行时,系统用类的定义创建类的实例,类的实例是真正的对象。类定义的一般形式如下:

classclassnameextendssuperclassname{

ypeinstance-variable1;

typeinstance-variable2;

typeinstance-variableN;

typemethodname1(parameter-list){

method-body;}

typemethodname2(parameter-list){

method-body;}

typemethodnameN(parameter-list){

method-body;}

}

这里,classname和superclassname是合法的标识符。关键词extends用来表明classname是superclassname派生的子类。有一个类叫做Object,它是所有Java类的根。如果你想定义Object的直接子类,你可以省略extends子句,编译器会自动包含它。下面是一个简单的类的定义。classUniversity{}

对 象 实 例

类名可以作为变量的类型来使用,如果一个变量的类型是某个类,那么它将指向这个类的实例,称为对象实例。所有对象实例和它们的类型(某个类的子类的实例都是相容的。就象可以把byte型的值赋给int型的变量一样,你可以把Object的子类的任何实例赋给一个Object型的变量。一个实例是类模板的单独的拷贝,带有自己的称为实例变量的数据集。每个实例也可以作为一个对象。当你定义一个变量的类型是某个类时,它的缺省值是null,null是Object的一个实例。对象null没有值,它和整数0不同。下面这个例子中,声明变量u的类型是类University。Universityu;这里,变量u的值是null。

实 例 变 量

Java通过在类定义的大括号里声明变量来把数据封装在一个类里。这里的变量称为实例变量。下面的例子定义了一个叫做University的类,它有两个实例变量:name和city。classUniversity{Stringname,city;}

new操 作 符

操作符new用来生成一个类的实例,下面这个例子生成了类University的一个实例,存放在变量u中。

Universityu=newUniversity();在此例中,变量u指向这个对象,但并不真正包含这个对象。你可以用多个变量指向同一个对象。下面的例子中,创建了一个University的对象,但创建了两个指向它的变量。

Universityu=newUniversity();

Universityu2=u;

对u2所指向的对象的任何改动都会对u所指向的对象起作用,因为它们是同一个对象。对u和u2的赋值只是把它们指向这个对象,既没有分配内存,也没有复制这个对象的任何部分。对u的再赋值只是简单地去掉了u和原来对象的联系,并不影响对象本身,下面的例子说明了这种情况。

Universityu=newUniversity();

Universityu2=u;

u=null;

尽管u被赋值为null,u2仍指向原来由操作符new创建的对象。在前面的例子里,我们生成了一个对象并且指向了它两次。这就允许两个变量改变同一个对象。创建一个新的对象时,可直接对它的实例变量赋值。每个对象都有它所属类的实例变量的拷贝,每个对象的实例变量都是和其他对象的实例变量分离的,所以改变一个对象的实例变量不会影响其他对象的实例变量。

下面的例子创建了两个University的对象,并对它们分别赋值:

classTwoUniversity{

publicstaticvoidmain(Stringargs[]){

Universityu1=newUniversity();

Universityu2=newUniversity();

u1.name="北京大学";

u1.city="北京";

u2.name="清华大学";

u2.city="北京";

System.out.println("大学:"+u1.name+"城市:"+u1.city);

System.out.println("大学:"+u2.name+"城市:"+u2.city);

}}

这个例子创建了两个University的对象,并且对它们的name、city分别赋了不同的值,这说明这两个对象是真正分离的。

下面是该程序运行后的输出结果。

C:\>javaTwoUniversity大学:北京大学城市:北京

大学:清华大学城市::北京

对象操作符——点

操作符点操作符用来接收一个对象的实例变量和成员函数。下面是用点操作符来接收实例变量的一般形式。

objectreference.variablename

这里objectreference是一个对象实例,variablename是这个对象里你想接收的实例变量。

下面的程序段说明了怎样用点操作符来给实例变量赋值。

u.name="北京大学";

u.city="北京";

下面说明怎样用点操作符来得到实例变量的值。

System.out.println("大学:"+u.name+"城市:"+u.city);

通过向类University里加入一个成员函数main,我们创建了一个完整的例子,它使用了new操作符来创建一个University,用点操作符来赋值,然后打印结果。

classUniversity{

Stringname,city;

publicstaticvoidmain(Stringargs[]){

Universityu=newUniversity();

u.name="北京大学";

u.city="北京";

System.out.println("大学:"+u.name+"城市:"+u.city);

}}

运行这个程序后,就会得到下面的结果。

C:\>javaTwoUniversity大学:北京大学城市:北京

成 员 函 数 定 义

成员函数,是类的功能接口,是类定义里的一个子程序,在类的定义里和实例变量处于同一级别。你必须通过一个类的实例来调用成员函数。成员函数可以不用点操作符而直接使用实例变量。成员函数带有输入参数,具有某种类型的返回值。成员函数定义的一般形式如下:

typemethodname(formal-parameter-list){

method-body;}

这里type指的是成员函数的返回值的类型,如果没有返回值,就用无值(void类型。methodname可以是任何合法的标识符,但不能与当前的类名相同。formal-parameter-list是用逗号分隔的类型、标识符对的序列。如果没有参数,括号里就是空的。还是用我们的University的例子,下面的成员函数用来初始化两个实例变量。成员函数是在类的大括号内定义的,和实例变量所处的范围相同。

classUniversity{

Stringname,city;

voidinit(Stringa,Stringb){

name=a;

city=b;

}}

注意,我们这里直接给name和city赋值,而没有象以前那样用u1.name。这是因为每个成员函数都在类的个别实例内执行。我们创建的类的实例具有它自己的实例变量,所以成员函数可直接使用它们。

成 员 函 数 调 用

可以用点操作符来调用一个类的实例的成员函数。成员函数调用的一般形式如下:

objectreference.methodname(parameter-list);

这里,objectreference是指向某个对象的变量,methodname是objectreference所属类的一个成员函数,parameter-list是用逗号分隔的变量或表达式的序列,它们要与该成员函数的定义的参数个数及类型匹配。在这个例子里,我们可以对任何University对象调用成员函数init来给name和city赋值。下面的程序段说明了怎样完成这个工作。

Universityu=newUniversity();

u.init("北京大学","北京");

这个例子创建了University的一个实例,存放在u中。通过点操作符来调用这个实例的init成员函数,把"北京大学"和"北京"分别传递给参数a和b。在init成员函数内部,name和city直接指向u所指向的对象的实例变量。把name赋值为"北京大学",city赋值为"北京",然后返回。在这个例子里,init被定义为无值(void返回类型)。在进行这个成员函数调用后,u指向这个name值和city值改变了的University对象。

this

Java有一个特殊的实例值叫this,它用来在一个成员函数内部指向当前的对象。在前面的例子里,我们调用u.init,一进入init成员函数内部,this就会指向u所指向的对象。在Java里,在同一个范围定义两个相同名字的局部变量是不可以的。有趣的是,局部变量、成员函数的参数可以和实例变量的名字相同。前面我们没有用name和city作为成员函数init的参数名字,因为这样它们在成员函数的范围里就把实例变量name和city隐藏了,即name指向参数name,隐藏了实例变量name。this让我们可以直接指向对象本身。下面是另一个版本的init,用name和city作为参数名字,用this来接收当前对象的实例变量。

voidinit(Stringname,Stringcity){

this.name=name;

this.city=city;

}

下面是带有新的init初始成员函数的TwoUniversity例子。

classUniversity{

Stringname,city;

voidinit(Stringname,Stringcity){

this.name=name;

this.city=city;

}}

Java之二 面向对象

classTwoUniversityInit{

publicstaticvoidmain(Stringargs[]){

Universityu1=newUniversity();

Universityu2=newUniversity();

u1.init("北京大学","北京");

u2.init("清华大学","北京");

System.out.println("大学:"+u1.name+"城市:"+u1.city);

System.out.println("大学:"+u2.name+"城市:"+u2.city);

}}

构 造 函 数(Constructor)

每创建一个类的实例都去初始化它的所有变量是乏味的。如果一个对象在被创建时就完成了所有的初始工作,将是简单的和简洁的。因此,Java在类里提供了一个特殊的成员函数,叫做构造函数(Constructor)。一个构造函数是对象被创建时初始对象的成员函数。它具有和它所在的类完全一样的名字。一旦定义好一个构造函数,创建对象时就会自动调用它。构造函数没有返回类型,即使是void类型也没有。这是因为一个类的构造函数的返回值的类型就是这个类本身。构造函数的任务是初始一个对象的内部状态,所以用new操作符创建一个实例后,立刻就会得到一个清楚、可用的对象。下面这个例子里,用构造函数取代了成员函数init。

classUniversity{

Stringname,city;

University(Stringname,Stringcity){

this.name=name;

this.city=city;

}}

classUniversityCreate{

publicstaticvoidmain(Stringargs[]){

Universityu=newUniversity("北京大学","北京");

System.out.println("大学:"+u.name+"城市:"+u.city);

}}

new语句中类名后的参数是传给构造函数的。

Java 面向对象的分析

深入分析面向对象实例

与面向过程的思想做一个比较,面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现过程;面向对象是指,我们考虑问题时,把任何东西看做是对象,以对象为单位,考虑它的属性及方法。

好比一个木匠在做一把凳子,假如他是面向过程的木匠,他会想到制作凳子的过程。“先做什么呢?凳子腿?凳子板?用什么工具呢?”。假如他是一个面向对象的木匠,他会把所有的东西看做成对象,“凳子腿,凳子板两个对象。凳子腿有属性,长方体的,长度,宽度是多少厘米,有方法钉钉子。凳子板的属性,正方形,边长是多少厘米等等问题。”这样的话,面向对象的木匠会依据这些条件。将一个凳子组装在一起。最终目的是做成一个凳子,用什么思想方法去做,是值得研究的。

通过刚才的例子,我们会有一种感觉,面向对象的木匠会对事务量化的分析,用“数学”的方法处理问题似的。似乎他更具有进步意义。面向对象的思想也确实有着他的先进之处,它把世界上的所有事务看做成为对象,这样的话更贴近于现实世界,这样的话使得逻辑清楚,谁看报告的时候也喜欢看条理清楚的报告啊。这样使得面向对象的软件开发,成为上世纪90年代直到现在的主流开发技术。传统开发方法存在以下问题:

1.软件重用性差

重用性是指同一事物不经修改或稍加修改就可多次重复使用的性质。软件重用性是软件工程追求的目标之一。谁愿意来往返回的写一件事情呢。

2.软件可维护性差

软件工程强调软件的可维护性,强调文档资料的重要性,规定最终的软件产品应该由完整、一致的配置成分组成。在软件开发过程中,始终强调软件的可读性、可修改性和可测试性是软件的重要的质量指标。实践证实,用传统方法开发出来的软件,维护时其费用和成本仍然很高,其原因是可修改性差,维护困难,导致可维护性差。

3.开发出的软件不能满足用户需要

用传统的结构化方法开发大型软件系统涉及各种不同领域的知识,在开发需求模糊或需求动态变化的系统时,所开发出的软件系统往往不能真正满足用户的需要。

现在的面向对象的思想已经扩展到很多方面,如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络治理结构、CAD技术、人工智能等领域。而且他指的是面向对象分析(OOA),面向对象设计(OOD),面向对象编程(OOP),这一套过程了。

下面我们来看一下,经常用到的重要概念,也就是java语言的的OOP特性,这是对于OOP而言的,不含前面的OOA和OOD的。因为是初学嘛,还没有学到怎么分析和设计呢。Java的OOP有三大特性:封装、继续、多态。

封装的概念已经在第4节课说过了,我们讲的是,它用权限修饰符private使得属性不能被外界访问,像是人的五脏六腑怎么能让人随意的碰呢?人的这个属性也是要封装的。如有再不明白,请访问我们的技术论坛。

说一下轻易理解的继续:

当一个类是另一个类的特例时,这两个类之间具有父子类的关系。子类继续了父类的方法和属性,就是说子类可以重用父类中的这部分代码。比如:轿车是车的一个特例。轿车是车的子类。就是说,轿车继续了车的一切特性。继续用要害字extends表示。

实践:

//这是基类

publicclassChe{

privateintwheel=4;

publicintgetWheel(){

returnwheel;

}   }

publicclassJiaocheextendsChe{

privateStringpinpai="桑塔纳";

publicStringgetPinpai(){

returnpinpai;

}   }

publicclassTestche{

publicstaticvoidmain(String[]args){

Jiaochecar=newJiaoche();

intwheels=car.getWheel();//调用基类的方法

StringPinpal=car.getPinpai();//调用本身的方法

System.out.println("车有"+wheels+"个轮子");

System.out.println("轿车的品牌是"+Pinpal);

}   }

注意:java语言与C++不同只可以从一个父类继续哦(单继续)。

还有就是最难理解的多态了,我们下次课讲面向对象的多态性。

使用Java 包的概念

java中“包”的引入的主要原因是java本身跨平台特性的需求。因为java中的所有的资源也是以文件方式组织,这其中主要包含大量的类文件需要组织管理。java中同样采用了目录树形结构。虽然各种常见操作系统平台对文件的管理都是以目录树的形式的组织,但是它们对目录的分隔表达方式不同,为了区别于各种平台,java中采用了"."来分隔目录。

package和import

打包和导入包

Java程序编译的类被放在包内,要访问类就要给出类所属的包名,来指明类是在哪一个包中,以便能够找到该类。一个包中有许多类,同时还可以有子包。如我们会在应用程序中经常用到Systen.out.println()方法来讲结果输出。参看Java的包,我们知道System是一个类,它属于lang包;同时,lang又属于java包。指明类的位置是,当没有用import语句,要访问System类就首先要指明在哪一个包中(用VJ++编写程序时,每一个源文件都默认用import语句将java.lang包中的所有类引入,所以可以直接用类名System来访问类)。Java用小圆点"."来说明包的这种包含关系,例如:

lang.System表示System类属于子包lang,java.lang表示子包lang是属于java包,java包是最外层包即根包。这样java.lang.System已经完全表明了System包的层次关系,根据这种关系,就能够找到System类并访问它了。java.lang.System称为访问类System的全限定名,用全限定名就可以访问类了,要访问类需要完全说明包的层次关系,例如java是最外层包,lang.System不是类System的全限定名,不能用它来访问类System。

当类有其静态成员变量和静态成员方法时,静态变量和静态方法能够被类直接访问,out是System类的静态成员,out有一个方法println(),下面介绍怎样访问类的静态成员。

能够用类的全限定名访问类,同样可以通过类成员的全限定名访问类的成员,如System的成员out是一个对象,out的全限定名为java.lang.System.out;同时,对象out又有println()方法,则println()方法的全限定名为:java.lang.System.out.println(),通过该名可以访问println()方法。

下面的程序是使用全限定名来访问方法的实例:

mainclass{

publicstaticvoidmain(Stringarg[]){

java.lang.Stringhello=newjava.lang.String("helloworld!");

java.lang.System.out.println(hello);

}}

类的全限定名与类在文件系统中的存储结构即目录有对应关系,例如java.lang.Sytem表示类System存储在lang目录中,lang是java的子目录,java是根目录。java.lang对应的目录为:\java\lang

当包的层次很多,而类处于较内层的包时,则类的全限定名较长,例如有下面的层次的包:school.department.class.group

有名为fly的类在包group中,model类在包department中,则:

fly的全限定名为:school.department.class.group.fly

model的全限定名为:school.department.model

显然用这样的名字来操作类,将是非常麻烦的。因此,Java提供了import语句。下面介绍包操作语句import和package。

2.1包操作语句import

指明将要访问的类所在的包,以便在当前目录找不到时,在import语句指明的包中寻找,若找不到类将出现编译错误。

包语句import的一般格式:

import类名;

我们知道,访问类可以用全限定名来访问,当要访问的类在同一个包中时,这时可以直接用要访问的类的类名代替全限定名进行操作。

例如,我们定义了两个类firstclass、secondclass,它们都属于mylopbag.smallbag包,在secondclass类中可以直接用firstclass代替全限定名mylafgebag.Smallbag.firstclass类。

当所要访问的类不在同一个包中时,就需要使用全限定名。全限定名往往很长,为此用import语句来减短访问类时用的名字。下面介绍import语句的两种用法。

用import语句。指明要访问的类位置。我们知道,类System在子包lang中,子包lang在最外层包即根包java中,我们引入如下语句

第一种用法:importJava.lang.*;

表示引入java.lang包内的所有类,当要访问包中的类时,直接用类名,如直接用类名为System访问类System.同时,类System中定义了Prinln()方法,用System.println()就可以调用方Prinln();

第二种用法:imnortjava.lang.System;

表示只引入java.lang包中的System类,访问包java.lang中的类时.只有System类能用类名来访问,包中的其他类需要全限定名来访问。

System.println()调用println()方法,其它类的成员则需要用成员的全限定来访问。用该语句能减少访问类时搜索的路径,提高运行的效率。

要注意的是import语句引入的是类,不能是子包,例如

importjava.lang.*;

该语句在编译时会出错,因为lang是java的一个子包,不是类,而VJ++认为lang是一个类,这样会出现找不到lang类的提示。用户在编程时,系统默认在每个源文件头加入了下面的import语句:

importjava.lang.*;

因此在用到这条语句时,编程时无需用说明。import语句在源文件的前面,一个源文件可以有多条import语句。import语句在package语句后面。import语句与C语言的include语句有本质的区别。import语句只指明要用到的类所在的位置,以便能在用到时可以加载;而C语言用include语句将要用的文件包含在源文件中,作为源文件编译成一个模块。这体现了Java语言的特点,用户只需要将模块编译一次。当用户在编写另一个模块用到已经编译的模块时,只要告诉编译程序它的位置,如用全限定名或者用import语句,编译程序无需再一次编译已经编译的模块,就能够将源文件编译通过。

2.2包操作语句Package

Package语句必须是源文件的第一条语句,且一个源文件只能有一条该语句。Package语句的格式为:

Packape包名;

例如:

Packagemyrotbag;

也可以是:

Packagemyrootbag.mysubbag;

常用的java包

在Java中,包的概念和目的都与其他语言的函数库非常类似,所不同的只是其中封装的是一组类。为了开发和重用的方便,我们可以将写好的程序类整理成一个个程序包。下面是Java预设包中主要的几个:

·              java.lang提供基本数据类型及操作。

·              java.util提供高级数据类型及操作。

·              java.io提供输入/输出流控制。

·              java.awt提供图形窗口界面控制。

·              java.awt.event提供窗口事件处理。

·              java.net提供支持Internet协议的功能。

·              java.applet提供实现浏览器环境中Applet的有关类和方法。

·              java.sql提供与数据库连接的接口。

·              java.rmi提供远程连接与载入的支持。

·              java.security提供安全性方面的有关支持。

我们可以引用这些包,也可以创建自己的包。

1、包的声明

为了声明一个包,首先必须建立一个相应的目录结构,子目录与包名一致。然后在需要放入该包的类文件开头声明包,形式为:

package包名;这样,在这个类文件中定义的所有类就都被装入到您所希望的包中了,例如:

packagebookexample;

classA{

……

}

classBextendsA{

……

}

publicclassOverrideExample{

……

}

不同的程序文件内的类也可以同属于一个包,只要在这些程序文件前都加上同一个包的说明即可。

2、包的使用

在Java中,为了装载使用已编译好的包,通常可使用以下3种方法:

在要引用的类名前带上包名作为修饰符。例如:

bookexample.AobjA=newbookexample.A();

其中bookexample是包名,A是包中的类名,objA是类的对象。

(2)在文件开头使用import引用包中的类。例如:

importbookexample.A;

classExample{

AobjA=newA();

}

同样,bookexample是包名,A是包中的类,objA是创建的A类对象。

(3)在文件前使用import引用整个包。例如:

importbookexample.*;

classExample{

AobjA=newA();

}

bookexample整个包被引入,A是包中的类,objA是创建的A类对象。

在使用包时,可以用点“.”表示出包所在的层次结构,用“.*”表示该目录结构下的所有内容。

需要指出的是,java.lang这个包无需显式引用,它总是被编译器自动调入。使用包时还要特别注意系统classpath路径的设置情况,它需要将包名对应目录的父目录包含在classpath路径中,否则编译时会出错,提示用户编译器找不到指定的类。

使用Java 的API文档

API文档的概念

在做c#练习时,如果我们遇到不会的对象或方法,会去查询msdn;那么在java中我们会查询java的api文档。

Java的api文档里包含了java所有的基础类库;

API文档的使用

Java中文API文档的chm格式文档。

实践问题:

1.你以前编写过面向过程的程序吗?比如:类似的脚本语言是面向过程的吗?

2.能不能从你的现实生活中分别提取一个面向对象和面向过程的实例?

小结:

在本章中,我们主要学习了:

u    Java面向对象的特征

u    面向对象的分析方法

英语词汇:

英文                    全文                           中文

Constructor       Constructor          构造函数

Extends       Extends           继承,扩展

Package        Package               包

Import                  Import                         导入

练习项目:

针对一个银行的取款,分别编写一个面向对象和面向过程的两个程序代码?

Java 面向对象编程

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【云驻共创】如何写代码:利益
下一篇:OBS权限控制的几件事(一)
相关文章