第4章 对象与类
4.1 面向对象程序设计概述
OOA、OOD、OOP
OO,Object-Oriented,面向对象。OO方法是一种把面向对象的思想应用于软件开发过程中,指导开发活动的系统方法。
- OOA,Object-Oriented Analysis,面向对象分析
- OOD,Object-Oriented Design,面向对象设计
- OOP,Object-Oriented Programming,面向对象编程
类是构造对象的模板或蓝图。由类构造对象的过程称为创建类的实例(instance)。
Java方法创建
方法的定义(方法名首字母小写,驼峰命名法)
1
2
3访问修饰符 返回值类型 方法名(){
方法主体
}类的创建及类与对象的关系
类的定义(类名首字母大写)
1
2
3
4class 类名称{
属性;
方法;
}类与对象的关系:对象是类的实例,类是对象的模板。类是抽象的概念,而对象是具体实例。
Java面向对象思想编程
面向对象三大特性:
- 封装 对外部不可见
- 继承 扩展类的功能
- 多态 1.方法的重载 2.对象的多态性
Java方法递归调用
eg:
1
2
3
4
5
6
7
8
9
10public static void main(String[] args){
System.out.println(addNumber(100));
}
public static int addNumber(int num){
if (num == 1){//程序出口
return 1;
}else{
return num+addNumber(num-1);
}
}
对象的三个主要特性:
- 行为(behavior)——可以对对象施加哪些操作/方法
- 状态(state)——施加方法时,对象是如何响应的
- 标识(identity)——如何辨别具有相同行为与状态的不同对象
类之间的关系
- 依赖(“uses-a”),如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。但这种依赖性应减少。
- 聚合(“has-a”),聚合关系意味着类A的对象包含着类B的对象。
- 继承(“is-a”),是一种表示特殊与一般的关系。一般而言,如果类A扩展类B,类A不但包含从类B继承的方法,还会拥有一些额外的功能。
UML(Unified Modeling Language),统一建模语言,用于绘制类图,用来描述类之间的关系。类用矩形表示,类之间的关系用带有各种修饰符的箭头表示。
4.2 使用预定义类
对象与对象变量
- 对象,在构造器前加上new操作符,即可构造出新对象。
- 一个对象变量,并没有实际包含一个对象,而仅仅引用一个对象。
- 对象存储在堆内存中,而对象变量也即引用存储在栈内存中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public class People {
String name;
int age;
// 构造器(constructor),是一种特殊的方法,又称构造方法
// 如果自己不重新构造,系统会默认自动生成无参的构造方法;
// 相反,如果自己写了构造方法,如若需要无参的构造方法,则需手动添加无参的构造方法。
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
// 此处的chinese只是一个对象变量,既不是对象,也没有引用对象
People chinese;
// chinese初始化后,对象变量chinese引用了一个对象,我们也称chinese为“引用”
// 此处的 new People("张三",22) 构造了新对象,存储在堆内存中
chinese = new People("张三",22);
}
}Java类库中的Date类、LocalDate类
Date类存在问题,很多方法已经被弃置了,不用。
LocalDate类,需使用静态工厂方法构造新对象。
1
4.3 用户自定义类
类的定义(类名首字母大写)
1
2
3
4class 类名称{
属性;
方法;
}一个源文件,只能有一个公共类,但可以有任意数目的非公有类。公共类的名称与源文件名称应完全相同。当一个源文件有多个类时,经编译器编译后,会生成多个.class字节码文件。
构造器
- 构造器与类同名
- 每个类可以有一个以上的构造器
- 构造器可以有0个、1个或多个参数
- 构造器没有返回值
- 构造器总是伴随着new操作一起调用
隐式参数与显示参数
- 在每一个方法中,关键字this表示隐式参数。
- 位于方法名后面括号中的参数,称为显示参数。
封装性
- 目的:保护某些属性和方法不被外部所看见
- 封装的实现:
- 为属性和方法进行封装是通过关键字private声明的
- 实现该属性的set和get方法,为外部所访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45class Person {
private int age;
private String name;
//快捷生成方式:右击->source->Generate Getter and Setter……
//get方法
public int getAge() {
return age;
}
//set方法
public void setAge(int age) {
if(age>0&&age<150){
this.age = age;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void tell(){
System.out.println("姓名:"+getName()+" "+"年龄:"+getAge());
}
}
public class Demo01 {
public static void main(String[] args) {
Person per = new Person();
// per.name = "张三";
// per.age = 30;
// per.setAge(-30);//最后age结果为0
per.setAge(30);//设置
per.setName("张三");
per.tell();
//使用 对象.属性/方法 进行使用
System.out.println("姓名:"+per.getName()+" "+"年龄:"+per.getAge());
}
}final关键字
修饰类。当用final去修饰一个类的时候,表示这个类不能被继承。
注意:
- 被final修饰的类,final类中的成员变量可以根据自己的实际需要设计为fianl。
- final类中的成员方法都会被隐式的指定为final方法。
在JDK中,被设计为final类的有String、System等。
修饰方法。被final修饰的方法不能被重写。
注意:- 一个类的private方法会隐式的被指定为final方法。
- 如果父类中有final修饰的方法,那么子类不能去重写。
修饰成员变量。
注意:- 必须初始化值,而且是只能初始化一次。
- 被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、全部在构造方法中赋初值。
- 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。
- 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。
4.4 静态域与静态方法
若将域定义为static,则该域为静态域,每个类中只有一个这样的域。静态域属于类,而不属于任何独立的对象。
静态方法是一种不能面向对象实施操作的方法。也就是说,不需要对象就能调用。
静态方法不可以调用非静态方法,但非静态方法可以调用静态方法。
使用静态方法的情况:
- 一个方法不需要访问对象状态,其所需参数都是通过显示参数提供(例如Math.pow)。
- 一个方法只需要访问类的静态域。
工厂方法。
类似LocalDate和NumberFormat的类使用静态工厂方法来构造对象。
1
2
3
4
5
6
7
8
9public static void main(String[] args) {
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
NumberFormat percentFormat = NumberFormat.getPercentInstance();
double x = 0.111;
System.out.println(currencyFormat.format(x));
System.out.println(percentFormat.format(x));
}结果为:
1
2¥0.11
11%为什么NumberFormat等类不利用构造器完成这些操作呢?原因如下:
- 无法命名构造器。构造器的名字必须与类名相同,但是,这里希望将得到的货币实例和百分比实例采用不同的名字。
- 当使用构造器时,无法改变所构造的对象类型。而Factory方法将返回一个DecimalFormat类对象,这是NumberFormat子类。
4.5 方法参数
- Java程序设计语言总是采用按值调用。
- 方法参数共有两种类型:
- 基本数字类型(数字、布尔值)
- 对象引用
4.6 对象构造
重载(overloading)。在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
1
2
3
4
5
6public void getAge() {
System.out.println("默认值18");
}
public void getAge(int age) {
System.out.println("年龄:"+age);
}通过关键字“this”,构造器可以调用同一个类的另一个构造器。
对象析构与finalize方法
- 由于Java有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器。
- finalize方法会在垃圾回收器清除对象之前调用,回收内存。但尽量不要使用,因为很难知道这个方法什么时候才能够调用。
4.7 包
- 使用import语句导入一个特定的类或整个包。import语句要在package语句后面,源文件的顶部。
- 关于包的引入,在开发过程中,会有提示,直接引入即可。
4.8 类路径
- 类存储在文件系统的子目录中。类的路径必须与包名匹配。
- 类也可存储在JAR(Java归档)文件中。
4.9 文档注释
JavaDoc注释,可生成API文档,使用“/** */”。eclipse中的快捷键:打出“/**”,然后回车即可。
具体的注释内的内容,视情况而定。
4.10 类设计技巧
- 一定要保证数据私有
- 一定要对数据初始化
- 不要再类中使用过多的基本类型。也即,用其他的类代替多个相关的基本类型的使用。
- 不是所有的域都需要独立的域访问器和域更改器。
- 将职责过多的类进行分解
- 类名和方法名要能够体现他们的职责
- 优先使用不可变的类。如果类是不可变的,就可以安全地在多个线程间共享其对象。