第2周 对象交互
2.1 对象交互
- 面向对象程序设计的第一步,就是在问题领域中识别出有效的对象,然后从识别出的对象中抽象出类来
- 面对纷繁复杂的显示问题,往往存在多种对象划分的方式,而不同的划分会带来类的设计的不同以至于程序结构的各种不同
- 本周课程举了一个数字钟的例子,希望通过这个例子表明对象划分的重要性,给我们一个感性的认识
- 一个对象可以由其他类的对象来组成,就像一个人体里面有心脏、肠胃一样。对象是由其他对象组成的,而类定义了这样的组合关系
- 当一个对象里有多个对象的时候,对象和对象之间的联系紧密程度叫作耦合,对象和对象的耦合程度越紧,表现在源代码上,就是他们的代码是互相依赖、互相牵制的
- 我们理想的模型,是对象和对象之间的耦合尽可能的松,平行的对象要尽量减少直接联系,让更高层次的对象来提供通信服务。这些就是在我们这个非常简单的数字钟的例子中所体现的。
如何识别对象?
一个时钟有
- 两个显示器对象✅
- 四个数字对象❌
- 一个时钟对象❌
- 我们在设计数字钟的时候,定义了子类Display和父类Clock,父类的成员变量是子类的对象,这就是类的交互
设计数字时钟
//Display class
public class Display {
private int value =0;
private int limit =0;
//构造函数
public Display(int limit)
{
this.limit=limit;
}
public void increase()
{
value++;
if(value==limit)
{
value=0;
}
}
public int getValue()
{
return value;
}
public static void main(String[] args) {
Display d= new Display(24);
for(;;)
{
d.increase();
System.out.println(d.getValue());
}
}
}
//Clock class
public class Clock {
private Display hour= new Display(24);
private Display minute=new Display(60);
public void start()
{
while(true)
{
minute.increase();
if (minute.getValue()==0)
{
hour.increase();
}
System.out.printf("%02d:%02d\n",hour.getValue(),minute.getValue());//带格式的输出;
}
}
public static void main(String[] args) {
Clock clock = new Clock();
clock.start();
}
}
2.2 访问属性
-
封装,就是把数据和对数据的操作放在一起,并且用这些操作把数据掩盖起来,是面向对象的基本概念之一,也是最核心的概念。
-
我们有一个非常直截了当的手段来保证在类的设计的时候做到封装:
- 所有的成员变量必须是private的,这样做避免了别人任意使用你的内部数据;
- 所有的public函数,只是用来实现这个类的对象 或 类自己要提供的服务的,而不是直接用来访问数据的。除非对数据的访问就是这个类及对象的服务。简单的说:给每个成员变量提供一对用于读写的get/set函数也是不合适的设计。
对象=属性+服务
-
数据:属性或形态(例如画圆时的圆心和半径)
-
操作:函数
-
把数据和对数据的操作放在一起(鸭蛋形态),数据不对外公开, 由操作去保护数据–>封装。
Java对封装,在具体语言上的实现为:所有的类的成员都可以设定访问属性
封闭的访问属性:private
-
private
关键字用于修饰成员变量和成员函数 -
习惯上,所有的成员变量都应定义为私有的
-
它表明,这个成员是这个类私有的,只有两种方式访问
- 在这个类的成员函数里头可以访问
- 在定义初始化时可以访问其他成员变量
private value = 0; private total = value;
-
main()
函数也是类的一个特殊成员,可以访问private
成员- 用
main()
函数调试类
- 用
-
值得注意,private关键字限制的是类而不是具体对象,类的内部可以访问–>对象之间可以访问
- Fraction类里头,成员函数plus可以访问到 作为传入参数的那个Fraction对象 的private成员变量
开放的访问属性:public
public
也是一个修饰词- 成员是开放的,“任何人”都能访问
- 其他类也能访问这个类的public成员
类前面也有关键字
- 如果类是
public
,就必须处在一个源代码文件里,且文件名与类名相同- 一个源代码文件–>一个.java文件–>编译单元
- 一个java文件可以有很多java类(比如第一周习题Fraction),但只能有一个类是
public
不加修饰词:friendly
- 和它位于同一个pakage的其他类可以访问
protected:继承部分详解
2.3 包
- 当你的程序越来越大的时候,你就会需要有一个机制帮助你管理一个工程中众多的类了。
- 包就是Java的类库管理机制,它借助文件系统的目录来管理类库,一个包就是一个目录,一个包内的所有的类必须放在一个目录下,那个目录的名字必须是包的名字。
- 作为初学者,你可以忽略不看包,反正一切靠Eclipse。但是作为一个Java程序员,你不能不懂包。要不然,在使用别人的类库和部署你的程序的时候,会遇到不少莫名其妙的麻烦。
- 因为,包治百病啊!
graph LR
A(project) ---> B(src)
A ---> C(bin)
B ---> D(pakage)
D ---> E(.java)
Aa(clock) ---> Bb(src)
Aa ---> Cc(bin)
Bb ---> Dd1(clock)
Bb ---> Dd2(display)
Dd1 ---> Ee(class Clock)
Dd2 ---> Ff(class Display)
package clock;
import java.util.Scanner;
import display.Display;
//用到的类不在当前包里头,就需要import它的全名;
//import里可以有.,表示目录的层次
2.4 类变量
-
类是描述,对象是实体。在类里所描述的成员变量,是位于这个类的每一个对象中的。
-
而如果某个成员有static关键字做修饰,它就不再属于每一个对象,而是属于整个类的了。
-
通过每个对象都可以访问到这些类变量和类函数,但是也可以通过类的名字来访问它们。类函数由于不属于任何对象,因此也没有办法建立与调用它们的对象的关系,就不能访问任何非static的成员变量和成员函数了。
类变量
static
的成员变量,称作类变量- 它不属于任何一个具体对象,而属于这个类
- 任何一个具体对象都拥有这个变量,但只有那一份
类函数
//static的类函数
public static void f(){
}
public static void main(String[] args) {
Display d1= new Display(10);
Display d2 = new Display(20);
d1.step=2;
System.out.println(d1.step);
System.out.println(d2.step);
//main()类函数调用f()类函数的三种方式
f();
Display.f();
d1.f();
}
-
static
的函数也不属于任何一个具体对象,而属于这个类 -
public static void main()
也是类函数- 在
main()
里头,具体对象通过.
运算符调用成员函数、访问成员变量(需要知道是哪一个对象的成员) d1.value=2;
- 在
-
static
的类函数在main()
类函数里可以有三种调用方式- 直接调用
- 通过具体对象名调用
- 通过类名调用
-
static
的类函数只能调用static的类函数和访问static的类变量,因为只有一份,这里调用成员变量/函数无法知道是哪一个对象的成员变量/函数 -
对static的初始化只做一次:static的成员变量只会在类进入程序时(装载时)被初始化,只有一份,static的初始化和对象的创建没关系