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命令,生成文档。
学习目标 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命令,生成文档。
相关文章推荐
- Java基础笔记整理---【08】面向对象程序设计-包、继承、访问权限
- android基础篇------------java基础(4) (面向对象程序设计)
- java基础教程:面向对象之抽象类(16)
- Java基础视频教程第05天_面向对象入门及this关键字
- Java基础教程(4)--面向对象概念
- Java基础复习---面向对象程序设计
- java基础教程:面向对象之接口(17)
- Java基础知识<3>-面向对象程序设计
- 理解Java面向对象的程序设计思想-Java基础-Java-编程开发
- Java基础视频教程第10天_面向对象之异常2、包
- java基础系列之三:java的面向对象程序设计
- java基础教程:面向对象之多态(18)
- Java基础笔记整理---【09】面向对象程序设计-上转型对象
- 第四章 JAVA面向对象程序设计基础知识--知识回顾与疑点解析
- Java基础视频教程第07天_面向对象之继承、抽象、接口
- Java基础视频教程第09天_面向对象之内部类、异常1
- java基础---面向对象程序设计
- Java 面向对象程序设计的基础知识
- Java基础笔记整理---【06】面向对象程序设计-封装
- Java基础笔记整理---【07】面向对象程序设计-类和对象