您的位置:首页 > 编程语言 > Java开发

java基础教程-面向对象的程序设计

2012-06-27 11:25 666 查看
这是一篇原创的课程文件,本来是PPT的我把他转成了word文档便于大家学习,因为是原版的课程所以平篇幅比较长!

学习目标 www.rjpx.net

[b]n 类和对象的描述[/b]

[b]n 类,属性,方法,构造方法定义[/b]

[b]n private和public访问权限的介绍[/b]

[b]n 源文件的布局[/b]

[b]n 包的声明和导入[/b]

[b]n 包与目录的布局[/b]

[b]n CLASSPATH环境变量的使用[/b]

[b]n API文档的使用[/b]

类和对象的描述

现实社会中一切皆对象。比如:人,树,石头,猫,鸟,汽车,地球等等。任何一种对象都具有静态的属性,但不一定具有动态的行为。比如:石头。一般情况下,对象既有静态的属性,也有动态的行为。对象本身的属性和行为之间可以相互影响,比如:一个人饿了(属性),就会去吃饭(行为)。相反,这个人吃饭(行为)后,就饱了(属性),体重(属性)也增加了。不同的对象之间也可以相互作用。比如:人看到汽车开过来了,就会沿着路边走。如果这个人站在路中间不动(他不怕死),那么汽车就会停下来。那么怎么用Java语言来实现上述功能呢?后面实例分析有实现。

如同建筑设计师设计建筑图(建筑的蓝图),可以用该图来盖出许许多多这种风格的房子一样。类是对象的蓝图,是用来描述对象的,你可以用该类,来实例化许许多多个该类型的对象,类就是对象的模板。在类中定义了一套数据元素(属性)和一套行为(方法)。数据是用来描述具体的一个对象(静态),行为是用来描述该类型对象的共性,也就是该对象能够做什么(动态),以及完成相关对象之间的交互,从而改变对象的状态。同样对象的状态也能够对象的行为。属性和方法都叫做类的成员。例如杯子装水的时候:最大盛水量和当前盛水量。盛水的方法要始终跟踪这两个属性。 装水时改变了当前盛水量的属性,同样当当前盛水量等于最大盛水量(水装满时),就会影响装水的行为,将不再倒水。

我们下面通过一个具体事例来说明Java中如何实现以上概念。

例1:

编写一个类,描述人吃饭,体重增加这个简单操作。

下图描述了一个“人”

这是一个UML中的类图,我们对它进行简单说明。

n 第一行:是类名Person,代表我们正在说明一个“人”的概念。

n 第二行:是属性,“-” 号代表这个属性只有这个类自己可以访问,weight代表属性的名字,double表示属性的类型,这里意思是“人有一个体重的特性,体重可以是小数,别人不能直接看出人有多重,必须使用某种称量体重的方法”。

n 第三行、第四行:是构建器,“+” 号代表public访问权限,含义是任何人可以访问到它。构建器是外界创造出这个“概念”的实际“例子”的入口,第三行是按照“缺省”方式构建,第四行是按照特定方式构建,特定方式是指按照参数指定的属性构建

n 第五行、第六行:是方法,其中eat方法有参数,参数名字是temp,参数类型是double,该方法的返回类型为void,该方法含义是人可以吃一定数量的食物,吃完不需要给外界任何回馈。第六行的方法getWeight()没有参数,返回double类型,含义是看这个人的重量。

声明类

Java中的语法和C一样,语句都是以分号结束,区分大小写。

在Java技术中采用下列方法声明类:

<modifier> class <name>{

<attribute_declaration>

<constructor_declaration>

<method_declaration>

}

说明:

<modifier>:暂时只用"public",含义为:可以被所有其它类访问。或者不加public, 在修饰类的访问权限的时候,只有两种:1,就是加上public,表示所有类都可以访问。 2,就是什么也不写,表示本包访问权限,在讲到包的含义时再理解。

<name>:任何合法的标识符。它代表所声明类的名称。

Java中的标识符(类名,变量名,方法名)是由字母,数字,下划线(_),美圆符($)组成,数字不能用于标识符的开始。其中长度不受限制,不能使用java中的关键字,并且是区分大小写的。比如:class,void等关键字。Java中的关键字都是由小写的字母组成的,所以在我们并不知道java中有那些关键字的情况下,在定义标识符的时候,只要不全是小写的字母,就不会和java中的关键字相冲突。

<attribute_declaration>:声明属性。也就是说用变量表示事物的状态。

<constructor_declaration>:声明构造函数。也叫构造方法,也叫构造器。是用来实例化该类的实例(对象)的。

<method_declaration>:声明方法。来说明事物能够做的事情,也就是行为。

注意:属性,方法,构造函数在类中的顺序没有固定的约束。一般习惯性地先声明属性,后声明方法(习惯性地把构造方法写普通方法的前面)。

所以Person这个类的初始版本应该是:

public class Person{

}

声明属性

<modifier> <type> <name> [ = <default_value> ];

说明:

<name>:任何合法的标识符。它代表所声明属性的名称。

<modifier>:暂时只用“public”和“private”,其中private含义为:仅能被所属类中的方法访问,这称作封装。

<type>:可以是任何原始类型(基本类型)或其它类(引用类型)。

[=<default_value>]是给属性初始化为给定的值。如果没有的话初始化为默认的值。(基本类型的初始化相应的值:比如:int,short,byte,long,char(Unicode码值)初始化为0,float,double初始化为0.0,boolean初始化为false,所有的引用类型都初始化为null)。

注意:Java语言与其它语言不同,在JAVA中声明属性和初始化属性值必须一句完成。不能分开写:先声明,再另起一行初始化。

例如:

private int a ;

a=5; //错误

private int b=6;//声明一个属性 b,并初始化为6;

在类里面除了声明语句之外,是不能直接写其它执行语句的。 a=5 是赋值语句。如果要执行语句应放在语句块(方法块,初始化块等)里执行。

据此,我们的Person类成为如下样子:

public class Person{

private double weight;

}

声明构造器

<modifier> <class_name> (<parameter>) {

<statement>

}

说明:

<class_name>:是类名,构造器的名字和类名必须一样。

<modifier>:可以是public,指明可以被任何其它代码访问。private,指明仅能被同一个类中的其它代码访问。

<parameter>:向构造器传递参数,可以没有参数。传递多个参数时,参数之间用逗号分开。每个参数由参数类型和标识符组成,这和声明属性的方式很类似,但是不能向参数赋初始值。

注意:构造器必须没有返回类型,并且构造方法的名字和类名必须一样。当一个类里面如果没有声明构造方法,那么虚拟机将自动给该类一个默认的构造器(不带参数的构造器)。如果在该类里面,定义了带参数的构造方法,那么虚拟机将不再为该类提供默认的构造方法,也就是该类不能按缺省方式构建了。

我们的类此时变成:

public class Person {

private double weight;

// 该类的默认的构造器

public Person() {

}

// 带参数的构造器

public Person(double d_weight) {

weight = d_weight; // 实例化对象时,给weight属性赋初始值

}

}

声明成员方法

<modifier> <return_type> <name> ( <parameter> ){

<statement>

}

<name>:任何合法的标识符。

<modifier>:可以是public,指明可以被任何其它代码访问,private:指明仅能被同一个类中的其它代码访问。

< return_type>:指明方法返回值的类型。假如方法不返回值,应被声明为void。

<parameter>:向方法传递参数。传递多个参数时,参数之间用逗号分开。每个参数由参数类型和标识符组成。

注意:方法必须有返回类型,返回类型为void和没有返回类型是不一样的。除了返回类型void外,有其它返回类型的方法块里必须有return语句。

我们的类此时变成(Person.java):

public class Person {

private double weight;

// 该类的默认的构造器

public Person() {

}

// 带参数的构造器

public Person(double d_weight) {

weight = d_weight; // 实例化对象时,给weight属性赋初始值

}

public void eat(double temp) { // 吃饭的方法

weight = weight + temp; // 吃多少,体重就增加多少

}

public double getWeight() {// 得到人的体重属性

return weight; //返回weight属性

}

}

private封装

在类里面声明属性的时候,一般把属性的访问权限定义成private,封装的要求。这样只能在类里面访问该属性,在类的外面是没有访问的权限的,也就是说对于该类的实例(对象),是不能够直接访问该对象的属性的。这样就会保护对象状态不会非法改变。

比如,人的体重是不能直接修改的,通过吃饭可以增加人的体重,如果该人很瘦,是不能直接把20斤牛肉放到该人身上,就算增加该人的体重的。同样的道理,如果该人很胖,也不能够从该人身上割下20斤肉,而让体重下降20斤。

所以我们在以上的类中声明weight属性为private。

public 公共访问

在类里面声明方法的时候,一般把该方法定义成public访问权限。在程序运行的时候,就是通过对象和对象之间的交互来实现的。为了保证对象都能够执行功能(方法),应该把方法的访问权限定义成public。

我们对方法getWeight()的处理就是这样。

下面是测试Person的PersonApp.java

public class PersonApp {

public static void main(String[] args) {

// p1是声明的变量,类型是Person类型的,并且引用了Person类的一个对象,且使用默认的构造器构造对象

Person p1 = new Person();

// p2 同p1,使用带参数的构造器

Person p2 = new Person(120);

// p1所引用的对象(简称p1对象),吃了2.5斤

p1.eat(2.5);

// p2 对象 吃了4.3斤

p2.eat(4.3);

// 打印出p1的体重

System.out.println("p1的体重为:" + p1.getWeight());

// 打印出p2的体重

System.out.println("p2的体重为:" + p2.getWeight());

}

}

编译和运行的过程如下图:

例2

我们知道如果文件名出现重复,那么我们要放在不同的目录中,class文件作为类的字节码载体,如果存在类名重复,那么class文件就应该放到不同的目录下,就类似文件夹的方式来管理文件。在Java里面是通过包的结构来管理类的。下面我们就上面例子修改下,再加个类,定义不同的包,放在不同目录下进行访问。

源文件的布局

Java技术源文件只有三部分,采用下面的布局:

[<package_declaration>]

<import_declaration>

<class_declaration>

说明:

<package_declaration> 声明包的语句,包通常使用小写字母,用.作为分割符,这是一种逻辑结构划分的方法。

<import_declaration> 导入包语句

<class_declaration> 类的声明语句

源文件命名

源文件的名字必须与该文件中声明的公有类的名字相同。一个源文件中可以包含多个类,但是最多只能包含一个公有类,显然,这个文件的名字应该是这个public类的名字后缀是“java”。如果源文件中不含公有类,源文件的名字不受限制。

包的声明

多数软件系统是庞大的。为了方便管理,通常要将类组织成包。在包中可以存放类,也可以存放子包,从而形成具有层次结构的包。包可以根据需要任意组织,通常,要按照类的用途、含义来组织包。如下UML 包图:

Java技术提供了包的机制,以次来组织相关的类。声明包的句法如下:

package <top_pkg_name> [.<sub_pkg_name>];

你可以使用package命令指明源文件中的类属于某个特定的包。例如:

package shenzhen.luohu;

public class Person{

//…

}

package声明必须放在源文件的最前面,或者说执行代码的第一行,或者除了注释之外的第一行。一个源文件最多只能有一条package声明。一条package声明对源文件中的所有类起作用。如果你的源文件中没有package声明,你的类将在“缺省”包终,这个缺省包的位置就是当前目录。

包的导入

当你想要使用包中的类的时候,可以用import命令告诉编译器类在哪里。import命令的语法:

import <pkg_name>[.<sub_pkg_name>].<class_name | *>;

例如:

import shenzhen.nanshan.*;

import shenzhen.futian.*;

import java.util.List;

import java.io.*;

当你使用import指令时,你并没有将那个包或那个包中的类拷贝到当前文件或当前包中。你仅仅是将你在import指令中选择的类加入到你的当前名字空间。无论你是否导入当前包,当前包都是你的名字空间的一部分。

import命令指明你要访问的类。例如,你需要访问Writer类,你需要下面的命令:

import java.io.Writer;

如果你需要访问一个包中的所有类,你需要下面的命令:

import java.io.*;

但是不会导入java.io下子包的类。

默认情况下,系统将自动导入java.lang包。

import java.lang.*; //源文件里不管有没有写上该句,该句的功能永远存在。

import java.io.Writer;与import java.io.*;的区别如下:

如果写类名,那么虚拟机将直接从所在包里找到该加载执行,如果写*号,编译器会CLASSPATH指定的路径,一个一个路径去找,直到找到该类为止。

javac和java命令都有-classpath 参数,他们就是通知编译器或虚拟机在哪些路径中查找可能用到的类。

包与目录的布局

由于编译后的字节码文件在文件系统中存放,包结构就以目录结构的方式体现,包的名字就是目录的名字。例如,shenzhen.luohu包中的PersonApp.class文件应该在 path\shenzhen\luohu目录中。

*运行的时候进入到path目录下:

path>java shenzhen.luohu.PersonApp 或者

path>java shenzhen/luohu/PersonApp

我们没有使用-CLASSPATH参数,系统是如何工作的呢?

首先,系统级别的CLASSPATH环境变量应该是个“.”,表示当前路径,在运行javac或java的时候如果没有-classpath参数就会使用环境变量中的CLASSPATH环境变量,所以系统将从当前路径开始查找类,也就是在“path”路径下,那么按照shenzhen/luohu/路径查下去,确实能找到PersonApp类,所以运行正常,在这里我们把path路径称为顶层目录。

在这种情况下不能进入到shenzhen目录下运行:path\shenzhen>java luohu.PersonApp或者path\shenzhen>java luohu\PersonApp,也不能进入到上一级目录运行。假如你把shenzhen 放在daima文件夹里,你也不能进入到daima 那个文件所在目录下运行:

path>java daima\shenzhen\luohu\PersonApp 或者

path>java daima.shenzhen.luohu.PersonApp

如果想在任何目录下运行正确,必须有三个限制:

n CLASSPATH环境变量或-CLASSPATH参数已指向顶层目录

n class文件按包路径完整结构存放。

n 类的名字必须是全限定名,就是必须包含包路径的类名。

上面是运行时的目录结构,我们可以通过拷贝的方式将类文件防止为以上形式并运行成功。我们也可以在编译的时候用下面两种方式把包的结构生成出来。

通常我们需要把源文件和类文件完全分离,例如我们我们把源文件按包路径完整的存放到src目录中,我们将来编译的类文件将按照包路径完整的存放到build目录中,如下图:

为了达到以上目的,我们手工开始工作,虽然将来有集成开发环境(IDE)帮助我们,但是这对我们明白包的含义很有帮助。

1、手动建立文件夹。把包的结构创建出来

我们分别使用三个包,在一个我们选定的工作目录下按照上图结构创建好目录,其中build目录下的结构无需创建(但是build自身要创建),src目录中存放源文件,他们分别按照自己的package声明存放到不同目录。

2、自动把包的目录结构生成出来。

进入工作目录(src和build的上级目录),执行以下命令:

就自动把类按包的结构生成到build目录中了。

其中-d指定了生成带有包结构的类的顶层目录,-sourcepath 指定了源文件查找路径,显然,由于PersonApp要使用到其他包里的其他类,而这些类还是以源文件形式存在的时候,编译器必须能查找到他们并同时将他们编译成功才可以编译PersonApp自身,编译器对源文件的查找方式和虚拟机对类的查找方式类似。

<PersonApp.java>

//声明包

package shenzhen.luohu;

//导入包

import shenzhen.nanshan.*;

import shenzhen.futian.*;

//公共类PersonApp

public class PersonApp {

public static void main(String[] args) {

// p1是声明的变量,类型是Person类型,并且引用了Person类的一个对象

Person p1 = new Person();

// p2 同p1

Person p2 = new Person(120);

// c1是声明的变量,类型是Cat类型的,并且引用了Cat类的一个对象

Cat c1 = new Cat();

c1.jiao();

// p1所引用的对象(简称p1对象),吃了2.5斤

p1.eat(2.5);

// p2 对象 吃了4.3斤

p2.eat(4.3);

// 打印出p1的体重

System.out.println("p1的体重为:" + p1.getWeight());

// 打印出p2的体重

System.out.println("p2的体重为:" + p2.getWeight());

}

}

<Person.java>

//声明包

package shenzhen.nanshan;

//声明公共类Person

public class Person {

// 声明该类的一个属性,访问权限为private ,对该属性进行封装,实例化时,给该属性的初始化默认值0。

private double weight;

// 该类的默认的构造器

public Person() {

}

// 带参数的构造器

public Person(double init_weight) {

// 实例化对象时,给weight属性赋初始值

weight = init_weight;

}

// 吃饭的方法

public void eat(double temp) {

// 吃多少,体重就增加多少

weight = weight + temp;

}

// 得到人的体重属性

public double getWeight() {

// 返回weight属性

return weight;

}

}

<Cat.java>

//声明包

package shenzhen.futian;

//声明公共类

public class Cat {

public void jiao() {

System.out.println("cat jiao......");

}

}

运行时情况如下:

当然我们也可以在build目录下,利用CLASSPATH环境变量已经带有的.(当前路径)直接找到要运行的类(shenzhen.luohu.PersonApp),我们也可以利用绝对路径形式制定CLASSPATH,例如:

而且绝对路径相对路径的概念在编译、运行的时刻同样有效。

对于CLASSPATH我们可以通过环境变量方式设置,例如希望从系统级别设置类路径,也可以通过-CLASSPATH参数形式设置,例如希望临时更改类路径。

例3

人看到汽车开过来了,就会沿着路边走。如果这个人站在路中间不动(他不怕死),那么汽车就会停下来

这里涉及到两个对象的相互作用,我们先声明两个类,来描述上述现象,然后再用一个测试类来实现。

〈CarPersonApp.java〉

class Car {

private boolean moving;

public boolean getMoving() {

return moving;

}

public void move(boolean side) {

if (side) {

System.out.println("车继续行驶");

moving = true;

} else {

System.out.println("车停下来");

moving = false;

}

}

};

class Person {

boolean side; // 表示人是否在路边

public boolean walk(boolean car) {

if (car) // 如果有车的话,人往路边走

{

System.out.println("人往路边走");

side = true;

} else {

System.out.println("人直着走");

side = false;

}

return side;

}

};

public class CarPersonApp {

public static void main(String[] args) {

Person p = new Person();

Car c = new Car();

c.move(true); // 车在行驶

p.walk(c.getMoving());// 测试人是否能行走,也就是说车的行为,影响了人的行为

}

}

编译和运行:

API文档的使用

Java API是扩展的Java类库。它为程序员提供了几千个类,包括基本的数学函数、数组和字符串、窗口,图形用户界面,输入/输出,联网等任何你需要的内容。

类库被组织成许多包,每个包都包含多个类。下面列举了一些重要的包:

n java.lang:包含一些形成语言核心的类,如String、Math、Integer和Thread。

n java.awt:包含了构成抽象窗口工具包(AWT)的类,这个包被用来构建和管理应用程序的图形用户界面。

n java.applet:包含了可执行applet特殊行为的类。

n java.net:包含执行与网络相关的操作的类和处理接口及统一资源定位器(URLs)的类。

n java.io:包含处理I/O文件的类。

n java.util:包含为任务设置的实用程序类,如随机数发生、定义系统特性和使用与日期日历相关的函数。

Java API文档详细说明了Java API的使用方法。Java API文档是一组等级制布局的HTML文件,因而主页列出所有的包为超链接。如果选中了一个特殊包的热链接,作为那个包成员的类将被列出。从一个包页选中一个类的热链接将提交一页有关那个类的信息。

下载Java2 SE Version 1.5的文档并解压缩,打开/api/Index.html 文件。

一个类文档的主要部分包括:

n 类层次

n 类和类的一般目的描述

n 成员变量列表

n 构造函数列表

n 方法列表

n 变量详细列表及目的和用途的描述

n 构造函数详细列表及描述

n 方法详细列表及描述

内容总结

n 一个类由属性、方法、构建器构成。

n private实现信息的封装,只有这个类自身内部可以访问这个属性或方法。

n CLASSPATH环境变量是Java虚拟机查找类的路径,在编译和运行时会使用到它。

n import告诉编译器:“未使用完整类限定名的类可以使用导入的类来匹配”,如果能匹配到则按照完整限定名使用它,这是动态导入的概念,这意味着编译成功的类完全可以在运行时发生不能查找到类的错误。

n API文档是我们使用已有类完成任务的参考手册。

n 会进行简单的实际问题的解决。

独立实践

n 练习API文档的使用,查找Date类,根据API文档说明写出一个程序演示输出当前日期。

n 写一个猫吃老鼠的实例。

n 对上面的类增加包,要求猫、老鼠、演示类在不同的包中,练习使用 CLASSPATH环境变量。

n 编写一个类:Person,包含一个属性:name及方法:getName(),画出它的类图。

n 给Person类加上注释,练习javadoc命令,生成文档。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: