`
p330294088
  • 浏览: 14485 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
最近访客 更多访客>>
社区版块
存档分类
最新评论
阅读更多

在学习函数这章之前,我们有必要了解一下类的知识.

在前面我们写的程序可以说是面向过程的,大家可以看到面向过程写程序,会导致代码长,大量出现重复的代码,相信大家深有体会了.

传统的面向过程的思想是一个线性过程,要求现实系统的业务管理规范,处理数据齐全.面向过程思想以过程为中心进行功能组合,软件的扩充和复用能力较差.

比如:下面用常见的象棋戏作为例子进一步说明面向过程与面向对象思想的区别,面向过程思想主要着眼于各个步骤,按照先后顺序来实现,如下所示:
1. 棋局初始化
2. 开始游戏
3. 红方先走
4. 判断是否满足规则
5. 判断是否吃子
6. 绘制画面
7. 判断输赢
8. 黑子后走.
9. 判断是否满足规则.
10. 判断是否吃子
11. 绘制画面
12. 判断输赢.
13. 返回步骤3
14. 输出游戏结果
通过把上面的每个步骤用函数实现,象棋游戏的问题就解决了.

面向对象思想则是从另外的思路来解决问题,整个象棋可以分为以下几个类
 棋盘类:负责棋局初始化,绘制棋盘等.
 玩家类:记录棋子位置,吃子情况等.
 规则类:负责判断是否满足象棋规则,输赢情况等.
玩家类的对象负责接受用户的输入,并告知棋子布局的变化.
棋盘类的对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,
规则类的对象来对棋局进行判定.
从上面的思路可以看出面向对象的编程思路是分功能来划分问题的.同样是绘制棋局,这样的行为在面向过程的设计中分散在了很多步骤中,由于通常会考虑到实际情况进行各种各样的变化,因此,很可能出现不同的绘制版本,而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一和完整性.
此外,面向对象思想提供了更好的程序功能扩展性,如加入悔棋,记录棋局等功能,如果要改动面向过程的设计,那么从头到尾一连串的都需要进行改动,甚至步骤之间的顺序都要进行大规模调整.如果是面向对象的设计,只需要改动棋盘类就可以实现这些新增的功能.

 面向对象程序设计思想倾向于建立一个整体的对象模型,能够近似地反应客观世界实体间的相互关系.其本质与人类认知事物所通常采用的方法较为近似.

类的基础
本书从一开始就使用了类,但是到现在为止,只使用了类的最简单形式.在前面章节中,创建的类都封装在main()方法中,我们用该方法来演示基本的Java语法,而实质上,类的功能比你目前看到的要强大得多.

理解类的最重要的事情就是它定义了一种新的数据类型。一旦定义后,就可以使用这个新类型创建该类型的对象.因此,类是对象的模板,而对象就是类的实例,因为对象是类的一个实例,所以对象和实例这两个词可以互换使用.

总之,一定要记住,在Java中,类是一种自定义的抽象的数据类型,可以想像成某种类型事物的统称,比如, 小张,小李,小赵都是学生,那到底学生是个什么东西呢,我们可以想像一样,学生就是具有姓名,年龄,班级,学习成绩,需要上学,放学,写作业的一类抽象事物的统称.
请看下图
       
大家可以想像一下, 你是学生,我也是学生,大家都是学生, 我们有一个共同的特性就是都是学生,不同的是,我们的姓名,年龄,班级,学习成绩可能不一样.这时,都是学生这个共同的特性我们可以提出来,比如我们说每个学生都有姓名,年龄,班级,学习成绩,只不过每个学生姓名和成绩可能不一样.

面向对象的思想的出发点就是为了能更加直接地描述客观世界中存在的事物及其相互间的关系.面向对象的思想将现实世界中的客观事物描述成具有属性和行为的对象,通过抽象出同一类对象的共同属性和行为,形成类.
比如上图,我们可以将小张,小李,小赵共同的特点抽象出来,因为它们都是学生,所以他们共同的特点抽象出来后,就可以形成一个学生类.反过来说,小张,小李,小赵是学生的一个对象(实例,实体).

比如说学生有姓名, 性别, 年龄, 语文成绩, 数学成绩, 英文成绩这些特点, 那我们在程序中怎么表示这些特点呢, 小张, 小李, 小赵这三个学生又怎么表示呢. 请看下面的代码(StudentDemo01.java):
class Student
{
 String stdName; //学生姓名
 String stdSex; //学生性别
 int stdAge; //学生年龄
 double chineseMark; //语文成绩
 double mathMark; //数学成绩
 double englishMark; //英文成绩
}

class StudentDemo01
{
 public static void main(String[] args)
 {
  //实例化学生小张
  Student stdZhang = new Student();
  //初始化各个属性
  stdZhang.stdName = "小张";
  stdZhang.stdSex = "男";
  stdZhang.stdAge = 20;
  stdZhang.chineseMark = 98;
  stdZhang.mathMark = 99;
  stdZhang.englishMark = 100;
  System.out.println("自我介绍");
  System.out.println("我的名字是:" + stdZhang.stdName);
  System.out.println("我的性别是:" + stdZhang.stdSex);
  System.out.println("我的年龄是:" + stdZhang.stdAge);
  System.out.println("我的语文成绩是:" + stdZhang.chineseMark);
  System.out.println("我的数学成绩是:" + stdZhang.mathMark);
  System.out.println("我的英文成绩是:" + stdZhang.englishMark);
  System.out.println();

  //实例化学生小李
  Student stdLi = new Student();
  //初始化各个属性
  stdLi.stdName = "小李";
  stdLi.stdSex = "女";
  stdLi.stdAge = 18;
  stdLi.chineseMark = 88;
  stdLi.mathMark = 89;
  stdLi.englishMark = 90;
  System.out.println("自我介绍");
  System.out.println("我的名字是:" + stdLi.stdName);
  System.out.println("我的性别是:" + stdLi.stdSex);
  System.out.println("我的年龄是:" + stdLi.stdAge);
  System.out.println("我的语文成绩是:" + stdLi.chineseMark);
  System.out.println("我的数学成绩是:" + stdLi.mathMark);
  System.out.println("我的英文成绩是:" + stdLi.englishMark);
  System.out.println();

  //实例化学生小赵
  Student stdZhao = new Student();
  //初始化各个属性
  stdZhao.stdName = "小赵";
  stdZhao.stdSex = "女";
  stdZhao.stdAge = 22;
  stdZhao.chineseMark = 78;
  stdZhao.mathMark = 79;
  stdZhao.englishMark = 70;
  System.out.println("自我介绍");
  System.out.println("我的名字是:" + stdZhao.stdName);
  System.out.println("我的性别是:" + stdZhao.stdSex);
  System.out.println("我的年龄是:" + stdZhao.stdAge);
  System.out.println("我的语文成绩是:" + stdZhao.chineseMark);
  System.out.println("我的数学成绩是:" + stdZhao.mathMark);
  System.out.println("我的英文成绩是:" + stdZhao.englishMark);
  System.out.println();
 }
}

我们可以看到声明类要使用class关键词,在一个class内定义的数据或变量称为成员变量,比如stdName……
我们现在还没有涉及到方法(函数).

大家可以看到我这里把两个class写在了一个文件中.
一个是Student类,它是抽象数据模型类
一个是StudentDemo01. 它是程序运行类.
在编译这个程序时,创建了两个.class文件,一个为Student.class, 一个为StudentDemo01.class. Student和StudentDemo01可以不必是在同一个文件中,可以把每个类分别放到它们各自的文件中,并分别称为Student.java和StudentDemo01.java,要运行此程序,必须执行带有main()方法的StudentDemo01.class

如程序所示,每个对象都能够保存自己实例变量的值,这意味着,如果有两个Student对象,则每个实例都会有自己的属性值,重要是的,改变一个对象的实例变量是不会影响到另一个对象的实例变量的.
大家可以看到小张,小李,小赵的数据完全分离.
创建对象
如前所述,当创建一个类时,就创建了一个新的数据类型,可以使用该类型来声明对象,实际上,获取类的对象是一个分为两步的过程,
首先,必须声明该类型的一个引用,这个引用不定义一个对象,它只是一个可以引用一个对象的引用,
其次,必须为该对象分配实际的物理内存,就是用new关键字来分配内存, 然后将引用和分配的内存进行绑定. 就像我们用摇控控制电视机一样.
Student stdZhao; //这里只是申请了一个遥控
stdZhao = new Student(); //这里才是给了你一个电视机, 并且让遥控与电视机进行绑定,让你的遥控可以控制电视机.
简写形式为: Student stdZhao = new Student();

new关键字来分配内存时的模拟图
 
类和对象之间的区别:类创建一种新的数据类型, 可以使用这种新的数据类型来创建对象,也就是类创建一个定义它的成员之间关系的逻辑框架.当声明一个类的对象时,就是正在创建该类的一个实例,因此,类是一个逻辑结构,而对象具有物理真实性(即对象在内存中占有空间).

给对象的引用赋值
你认为下面的代码片段会做什么?
Student std1 = new Student();
Student std2 = std1;

千万记住,执行完这段代码后, std1, std2将引用同一个对象,即两个遥控器控制一台电视机. std2或std1之间任何的变动,都会影响到对方.因为它们是同一个对象,可以将对方看作是对象的别名,记住此时是两个遥控器控制一台电视机.

 

此时,std1和std2指向同一个对象, 如果我想让std2脱离控制,可以使用语句
std2 = null;
null 非常特殊,它是万能对象,可以表示任何对象, 它在内在中不存在内存空间, null用来表示一个引用没有实例存在
比如下面的例子
String str1 = null; str1是null,那么内存根本没创建字符串对像
String str2 = ””; 确实存在一个由str2引用的字符串对像,只不过这个字符串的值是""

null是没有地址
""是有地址但是里面的内容是空的

好比做饭 null说明连锅都没有 而""则是有锅没米
虽然二者看起来都是没有米 但是意义却不同

方法介绍
类通常由两个方面组成: 成员变量和方法,方法是个很大的主题,因为Java给予了它强大的功能和灵活性,现在先介绍一些基础知识,以便可以开始给类添加方法.

以下是方法的一般形式:
type name(parameterList)
{
 ...方法的实现
}
其中type指定了该方法返回的数据类型. 这可以是任何有效的类型, 包括创建的类的类型,如果该方法不返回值, 它的返回类型一定得是void,
方法名是由name指定,可以自己定义,但是得有意义,不能定义成a,b,c等等无意义的名字.
parameterList参数列表是一个用逗号分开的类型和标识符序列,参数本质上是变量,对应于方法被调用时所需要的实际参数.如果方法没有参数,则参数列表将为空.

返回类型不是void的方法将使用下面的形式return语句把一个值返回给调用程序.
return value;  其中value是返回的值.

比如上例中,
我们看到学生在自我介绍时出现了大量重复的代码,我们现在可能会想到自我介绍这个功能最好由Student类来处理.为此,我们可以把一个自我介绍的方法添加到Student中去.
请看示例StudentDemo02.java
可以看到在类Student中,加入了以下代码:
void introductionSelf()
 {
  System.out.println("自我介绍");
  System.out.println("我的名字是:" + stdName);
  System.out.println("我的性别是:" + stdSex);
  System.out.println("我的年龄是:" + stdAge);
  System.out.println("我的语文成绩是:" + chineseMark);
  System.out.println("我的数学成绩是:" + mathMark);
  System.out.println("我的英文成绩是:" + englishMark);
  System.out.println();
 }
这的void是没有返回值, introductionSelf()是方法名, 括号里没有参数列表,则说明这个方法不需要传递参数.大括号内的内容是方法的实现部分.
然后我们在程序中调用时可以通过stdZhang.introductionSelf(); 来调用此方法.
这就是最简单的没有返回值,没有参数列表的方法的写法.简单吧...

有参数列表,没有返回值的方法的写法
StudentDemo01示例中,我们可以看到在初始化各个对象的属性值的时候也出现了大量重复的代码, 我们也可以在Student类中加入一个属性值初始化的方法.请看示例StudentDemo03.java

有返回值,没有参数列表的方法的写法.
如果我现在想加一个算成绩平均分的功能,可以在Student类中加一个算平均分的方法即可.请看StudentDemo04.java

有返回值,有参数列表的方法的写法
如果我需要在两个学生之间比较一下成绩分数的大小,可以在Student类中添加一个比较的方法, 请看示例StudentDemo05.java


static的作用
如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。 

有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。
声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。

静态变量:类变量,为此类所有对象共享
静态方法:静态方法里没有this引用
不能在静态方法中访问非静态的成员变量和方法
可以直接通过类访问静态成员,即使不存在该类的对象

声明为static的方法有以下几条限制:
1. 它们仅能调用其他的static 方法。
2. 它们只能访问static数据。
3. 它们不能以任何方式引用this 或super

static块程序是在类被装载的时候开始执行。而不是在创建对象的时候执行。

递归方法
拿一个阶乘的例子来说比较容易理解
public class Test {
 static int multiply(int n){
  if(n==1) {
   return  n;
}
  else {
return  n * multiply ( n-1 );
}
 }

 public static void main(String[] args){
  System.out.println(multiply(5));
 }
}

上面的multiply是一个阶乘的例子。其实递归,从字面上解释就是在方法本身调用自己的方法,或者间接调用;看上面的程序,拿multiply(5)来说:
multiply(5)
n=5;执行 5*multiply(4);
--------------------
这时候看multiply(4)
n=4 执行 4*multiply(3);
-------------------
看multiply(3)
n=3,执行 3*multiply(2);
---------------
mulitply(2);
n=2 执行 2*mulitply(1);
---------------
mulitply(1);
n=1 执行return 1;

这时候,return 1;往上返回
2*1向上返回
3*(2*1)向上返回
4*(3*(2*1)) 向上返回
5*(4*(3*(2*1)) ) = 120

所以程序输出120;
这事简单的递归的例子;所以可以看出来递归的关键得有递归出口(本体的If语句).

一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
注意:
  (1) 递归就是在过程或函数里调用自身;
(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics