# 第四章 初始面向对象

# 面向对象编程基础

第2阶段:Java面向对象编程-第06章

学习面向对象内容的三条主线

  • Java类及类的成员:(重点)属性、方法、构造器;(熟悉)代码块、内部类

  • 面向对象的特征:封装、继承、多态、(抽象)

  • 其他关键字的使用:this、super、package、import、static、final、interface、abstract等

# 1. 面向对象编程概述(了解)

# 1.1 程序设计的思路

面向对象,是软件开发中的一类编程风格、开发范式。除了面向对象,还有面向过程指令式编程函数式编程。在所有的编程范式中,我们接触最多的还是面向过程和面向对象两种。

类比:史书类型
- 纪传体:以人物传记为中心,“本纪”叙述帝王,“世家”记叙王侯封国和特殊人物,“列传”记叙民间人物。
- 编年体:按年、月、日顺序编写。
- 国别体:是一部分国记事的历史散文,分载多国历史。
1
2
3
4

早期先有面向过程思想,随着软件规模的扩大,问题复杂性的提高,面向过程的弊端越来越明显,出现了面向对象思想并成为目前主流的方式。

1. 面向过程的程序设计思想(Process-Oriented Programming),简称POP

  • 关注的焦点是过程:过程就是操作数据的步骤。如果某个过程的实现代码重复出现,那么就可以把这个过程抽取为一个函数。这样就可以大大简化冗余代码,便于维护。
  • 典型的语言:C语言
  • 代码结构:以函数为组织单位。
  • 是一种“执行者思维”,适合解决简单问题。扩展能力差、后期维护难度较大。

2. 面向对象的程序设计思想( Object Oriented Programming),简称OOP

  • 关注的焦点是:在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,用类来表示。
  • 典型的语言:Java、C#、C++、Python、Ruby和PHP等
  • 代码结构:以为组织单位。每种事物都具备自己的属性行为/功能
  • 是一种“设计者思维”,适合解决复杂问题。代码扩展性强、可维护性高。

# 1.2 由实际问题考虑如何设计程序

思考1:如何开车?

面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”并将步骤对应成方法,一步一步,最终完成。 这个适合简单任务,不需要过多协作的情况。针对如何开车,可以列出步骤:

image-20230305151613060

面向过程适合简单、不需要协作的事务,重点关注如何执行。

思考2:如何造车?

造车太复杂,需要很多协作才能完成。此时我们思考的是“车怎么设计?”,而不是“怎么按特定步骤造车的问题”。这就是思维方式的转变,前者就是面向对象思想。所以,面向对象(Oriented-Object)思想更契合人的思维模式。

用面向对象思想思考“如何设计车”:

image-20230305151809214

自然地,我们就会从“车由什么组成”开始思考。发现,车由如下结构组成:

image-20230305152504316

我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤,...;这样,大家可以同时进行车的制造,最终进行组装,大大提高了效率。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,还是离不开面向过程思维!

因此,面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。 但是,具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。

注意:

我们千万不要把面向过程和面向对象对立起来。他们是相辅相成的。面向对象离不开面向过程!

类比举例2:人把大象装进冰箱

  • 面向过程

    1.打开冰箱
    
    2.把大象装进冰箱
    
    3.把冰箱门关住
    
    
    1
    2
    3
    4
    5
    6

    面向对象

    人{
        打开(冰箱){
    		冰箱.开门();	
        }
        操作(大象){
                 大象.进入(冰箱);
        }
        关闭(冰箱){   
              冰箱.关门();     
        }
    }
    
    冰箱{
         开门(){ }  
         关门(){ }
    }
    
    大象{
         进入(冰箱){  }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

**练习:**抽象出下面系统中的“类”及其关系

image-20230305152455163

# 1.3 如何掌握这种思想?

image-20230305152524823

# 2. Java语言的基本元素:类和对象

# 2.1 引入

人认识世界,其实就是面向对象的。比如,我们认识一下美人鱼(都没见过)

image-20230305152753576

经过“仔细学习”,发现美人鱼通常具备一些特征:

  • 女孩
  • 有鱼尾
  • 美丽

这个总结的过程,其实是抽象化的过程。抽象出来的美人鱼的特征,可以归纳为一个美人鱼类。而图片中的都是这个类呈现出来的具体的对象

# 2.2 类和对象概述

类(Class)对象(Object)是面向对象的核心概念。

1、什么是类

:具有相同特征的事物的抽象描述,是抽象的、概念上的定义。

2、什么是对象

对象:实际存在的该类事物的每个个体,是具体的,因而也称为实例(instance)

image-20230305153119400

可以理解为:类 => 抽象概念的人对象 => 实实在在的某个人

# 2.3 类的成员概述

面向对象程序设计的重点是类的设计

类的设计,其实就是类的成员的设计

现实世界的生物体,大到鲸鱼,小到蚂蚁,都是由最基本的细胞构成的。同理,Java代码世界是由诸多个不同功能的构成的。

现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、…

Java中用类class来描述事物也是如此。类,是一组相关属性行为的集合,这也是类最基本的两个成员。

  • 属性:该类事物的状态信息。对应类中的成员变量
    • 成员变量 <=> 属性 <=> Field
  • 行为:该类事物要做什么操作,或者基于事物的状态能做什么。对应类中的成员方法
    • (成员)方法 <=> 函数 <=> Method

image-20230305154814273

举例:

image-20230305154827453

# 2.4 面向对象完成功能的三步骤(重要)

# 步骤1:类的定义

类的定义使用关键字:class。格式如下:

[修饰符] class 类名{
	属性声明;
    方法声明;
}
1
2
3
4

举例1:

public class Person{
    //声明属性age
    int age ;	                   
    
    //声明方法showAge()
    public void eat() {        
	    System.out.println("人吃饭");
    }
}
1
2
3
4
5
6
7
8
9

举例2:

public class Dog{
    //声明属性
	String type; //种类
	String nickName; //昵称
	String hostName; //主人名称
	
    //声明方法
	public void eat(){ //吃东西
		System.out.println("狗狗进食");		
	}
}
1
2
3
4
5
6
7
8
9
10
11
public class Person{
    String name;
    char gender;
    Dog dog;
    
    //喂宠物
    public void feed(){
        dog.eat();
    }
}
1
2
3
4
5
6
7
8
9
10

# 步骤2:对象的创建

image-20230305155207657

  • 创建对象,使用关键字:new

  • 创建对象语法:

//方式1:给创建的对象命名
//把创建的对象用一个引用数据类型的变量保存起来,这样就可以反复使用这个对象了
类名 对象名 = new 类名();

//方式2:
new 类名()//也称为匿名对象
1
2
3
4
5
6
  • 举例
class PersonTest{
	public static void main(String[] args){
		//创建Person类的对象
		Person per = new Person();
		//创建Dog类的对象
		Dog dog = new Dog();
	}
}
1
2
3
4
5
6
7
8

# 步骤3:对象调用属性或方法

  • 对象是类的一个实例,必然具备该类事物的属性和行为(即方法)。
  • 使用"对象名.属性" 或 "对象名.方法"的方式访问对象成员(包括属性和方法)

举例1:

//声明Animal类
public class Animal { //动物类
    public int legs;

    public void eat() {
        System.out.println("Eating.");
    }

    public void move() {
        System.out.println("Move.");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
//声明测试类
public class AnimalTest {
    public static void main(String args[]) {
        //创建对象
        Animal xb = new Animal();
        xb.legs = 4;//访问属性
        System.out.println(xb.legs);
        xb.eat();//访问方法
        xb.move();//访问方法
    }
}
1
2
3
4
5
6
7
8
9
10
11

举例2:针对前面步骤1的举例2:类的实例化(创建类的对象)

public class Game{
    public static void main(String[] args){
        Person p = new Person();
        //通过Person对象调用属性
        p.name = "康师傅";
        p.gender = '男';
        p.dog = new Dog(); //给Person对象的dog属性赋值
        
        //给Person对象的dog属性的type、nickname属性赋值
        p.dog.type = "柯基犬";
        p.dog.nickName = "小白";
        
        //通过Person对象调用方法
        p.feed();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.5 匿名对象 (anonymous object)

  • 我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。

    • 如:new Person().shout();
  • 使用情况

    • 如果一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
    • 我们经常将匿名对象作为实参传递给一个方法调用。

# 3. 类的成员之一:成员变量(field)

# 3.1 如何声明成员变量

  • 语法格式:
[修饰符1] class 类名{
    [修饰符2] 数据类型 成员变量名 [= 初始化值]; 
}
1
2
3

说明:

  • 位置要求:必须在类中,方法外
  • 修饰符2(暂不考虑)
    • 常用的权限修饰符有:private、缺省、protected、public
    • 其他修饰符:static、final
  • 数据类型
    • 任何基本数据类型(如int、Boolean) 或 任何引用数据类型。
  • 成员变量名
    • 属于标识符,符合命名规则和规范即可。
  • 初始化值
    • 根据情况,可以显式赋值;也可以不赋值,使用默认值

实例:

public class Person{
	private int age;             //声明private变量 age
	public String name;    //声明public变量 name
}
1
2
3
4

# 3.2 成员变量 vs 局部变量

1、变量的分类:成员变量与局部变量

  • 在方法体外,类体内声明的变量称为成员变量。
  • 在方法体内部等位置声明的变量称为局部变量。

image-20230305161049511

image-20230305161056032

其中,static可以将成员变量分为两大类,静态变量和非静态变量。其中静态变量又称为类变量,非静态变量又称为实例变量或者属性。接下来先学习实例变量。

2、成员变量 与 局部变量 的对比

  • 相同点

    • 变量声明的格式相同: 数据类型 变量名 = 初始化值
    •    	变量必须先声明、后初始化、再使用。
      
    • 变量都有其对应的作用域。只在其作用域内是有效的
  • 不同点

1、声明位置和方式 (1)成员变量:在类中方法外 (2)局部变量:在方法体{}中或方法的形参列表、代码块中

2、作用域 (1)成员变量:通过对象就可以使用,本类中直接调用,其他类中“对象.实例变量” (2)局部变量:出了作用域就不能使用

3、对象属性的默认初始化赋值

当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。

image-20230305161330301

案例1:

云课第四章4.6输出图书相关信息

案例2:

声明员工类Employee,包含属性:编号id、姓名name、年龄age、薪资salary

声明EmployeeTest测试类,并在main方法中,创建2个员工对象,并为属性赋值,打印两个员工的信息

案例3:

(1)声明一个MyDate类,有属性:年year,月month,日day

(2)声明一个Employee类,包含属性:编码、姓名、年龄、薪资、生日(数据类型是MyDate)

(3)在EmployeeTest类中,创建两个对象,并为他们的姓名和生日赋值,并显示

# 4. 类的成员之二:方法(method)

# 4.1方法的引入

image-20230305164226764

《街霸》游戏中,每次人物出拳、出脚或跳跃等动作都需要编写50-80行的代码,在每次出拳、出脚或跳跃的地方都需要重复地编写这50-80行代码,这样程序会变得很臃肿,可读性也非常差。为了解决代码重复编写的问题,可以将出拳、出脚或跳跃的代码提取出来放在一个{}中,并为这段代码起个名字,这样在每次的出拳、出脚或跳跃的地方通过这个名字来调用这个{}的代码就可以了。

上述过程中,所提取出来的代码可以被看作是程序中定义的一个方法,程序在需要出拳、出脚或跳跃时调用该方法即可。

# 4.2 方法(method、函数)的理解

  • 方法是类或对象行为特征的抽象,用来完成某个 功能操作。在某些语言中也称为函数过程
  • 方法用来封装某一个功能
  • 将功能封装为方法的目的是,可以实现代码重用,减少冗余,简化代码
  • Java里的方法不能独立存在,所有的方法必须定义在类里。
  • 举例1:
    • Math.random()的random()方法
    • Math.sqrt(x)的sqrt(x)方法
    • System.out.println(x)的println(x)方法
    • new Scanner(System.in).nextInt()的nextInt()方法
    • Arrays类中的binarySearch()方法、sort()方法、equals()方法
  • 举例2:
public class Person{
    private int age;
    public int getAge()  {  //声明方法getAge()
		return age; 
    }
    public void setAge(int i) {  //声明方法setAge
		age = i;        //将参数i的值赋给类的成员变量age
    }
}
1
2
3
4
5
6
7
8
9

# 4.3 如何声明方法

1、声明方法的语法格式

[修饰符] 返回值类型 方法名([形参列表])[throws 异常列表]{
        方法体的功能代码
}
1
2
3

(1)一个完整的方法 = 方法头 + 方法体。

  • 方法头就是[修饰符] 返回值类型 方法名([形参列表])[throws 异常列表],也称为方法签名。通常调用方法时只需要关注方法头就可以,从方法头可以看出这个方法的功能和调用格式。
  • 方法体就是方法被调用后要执行的代码。对于调用者来说,不了解方法体如何实现的,并不影响方法的使用。

(2)方法头可能包含5个部分

  • 修饰符:可选的。方法的修饰符也有很多,例如:public、protected、private、static、abstract、native、final、synchronized等,后面会一一学习。

    • 其中,权限修饰符有public、protected、private。在讲封装性之前,我们先默认使用pulbic修饰方法。
    • 其中,根据是否有static,可以将方法分为静态方法和非静态方法。其中静态方法又称为类方法,非静态方法又称为实例方法。咱们在讲static前先学习实例方法。
  • 返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者。

    • 无返回值,则声明:void
    • 有返回值,则声明出返回值类型(可以是任意类型)。与方法体中“return 返回值”搭配使用
  • 方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”

  • 形参列表:表示完成方法体功能时需要外部提供的数据列表。可以包含零个,一个或多个参数。

    • 无论是否有参数,()不能省略
    • 如果有参数,每一个参数都要指定数据类型和参数名,多个参数之间使用逗号分隔,例如:
      • 一个参数: (数据类型 参数名)
      • 二个参数: (数据类型1 参数1, 数据类型2 参数2)
    • 参数的类型可以是基本数据类型、引用数据类型
  • throws 异常列表:之后章节再讲

(3)方法体:方法体必须有{}括起来,在{}中编写完成方法功能的代码

(4)关于方法体中return语句的说明:

  • return语句的作用是结束方法的执行,并将方法的结果返回去

  • 如果返回值类型不是void,方法体中必须保证一定有 return 返回值; 语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。

  • 如果返回值类型为void时,方法体中可以没有return语句,如果要用return语句提前结束方法的执行,那么return后面不能跟返回值,直接写return ; 就可以。

  • return语句后面就不能再写其他代码了,否则会报错:Unreachable code

补充:方法的分类:按照是否有形参及返回值

image-20230305164902191

2、代码示例:

/**
 * 方法定义案例演示
 */
public class MethodDefineDemo {
    /**
     * 无参无返回值方法的演示
     */
    public void sayHello(){
        System.out.println("hello");
    }

    /**
     * 有参无返回值方法的演示
     * @param length int 第一个参数,表示矩形的长
     * @param width int 第二个参数,表示矩形的宽
     * @param sign char 第三个参数,表示填充矩形图形的符号
     */
    public void printRectangle(int length, int width, char sign){
        for (int i = 1; i <= length ; i++) {
            for(int j=1; j <= width; j++){
                System.out.print(sign);
            }
            System.out.println();
        }
    }

    /**
     * 无参有返回值方法的演示
     * @return
     */
    public int getIntBetweenOneToHundred(){
        return (int)(Math.random()*100+1);
    }
    
    /**
     * 有参有返回值方法的演示
     * @param a int 第一个参数,要比较大小的整数之一
     * @param b int 第二个参数,要比较大小的整数之二
     * @return int 比较大小的两个整数中较大者的值
     */
    public int max(int a, int b){
        return a > b ? a : b;
    }
 }
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

# 4.4 如何调用实例方法

方法通过方法名被调用,且只有被调用才会执行。

1、方法调用语法格式

对象.方法名([实参列表])
1

2、示例

举例1:

/**
 * 方法调用案例演示
 */
public class MethodInvokeDemo {
    public static void main(String[] args) {
        //创建对象
        MethodDefineDemo md = new MethodDefineDemo();

        System.out.println("-----------------------方法调用演示-------------------------");

        //调用MethodDefineDemo类中无参无返回值的方法sayHello
        md.sayHello();
        md.sayHello();
        md.sayHello();
        //调用一次,执行一次,不调用不执行

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中有参无返回值的方法printRectangle
        md.printRectangle(5,10,'@');

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中无参有返回值的方法getIntBetweenOneToHundred
        md.getIntBetweenOneToHundred();//语法没问题,就是结果丢失

        int num = md.getIntBetweenOneToHundred();
        System.out.println("num = " + num);

        System.out.println(md.getIntBetweenOneToHundred());
        //上面的代码调用了getIntBetweenOneToHundred三次,这个方法执行了三次

        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中有参有返回值的方法max
        md.max(3,6);//语法没问题,就是结果丢失
        
        int bigger = md.max(5,6);
        System.out.println("bigger = " + bigger);

        System.out.println("8,3中较大者是:" + md.max(8,9));
    }
}
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

举例2:

//1、创建Scanner的对象
Scanner input = new Scanner(System.in);//System.in默认代表键盘输入

//2、提示输入xx
System.out.print("请输入一个整数:"); //对象.非静态方法(实参列表)

//3、接收输入内容
int num = input.nextInt();  //对象.非静态方法()
1
2
3
4
5
6
7
8

# 4.5 使用的注意点

(1)必须先声明后使用,且方法必须定义在类的内部

(2)调用一次就执行一次,不调用不执行。

(3)方法中可以调用类中的方法或属性,不可以在方法内部定义方法。

正确示例:

类{
    方法1(){
        
    }
    方法2(){
        
    }
}
1
2
3
4
5
6
7
8

错误示例:

类{
    方法1(){
        方法2(){  //位置错误
        
   		}
    }
}
1
2
3
4
5
6
7

# 4.6 关键字return的使用

  • return在方法中的作用:
    • 作用1:结束一个方法
    • 作用2:结束一个方法的同时,可以返回数据给方法的调用者
  • 注意点:在return关键字的直接后面不能声明执行语句

案例1:

(1)创建Person类的对象,设置该对象的name、age和gender属性

调用study方法,输出字符串"studying";

调用showAge()方法,返回age值

调用addAge(int addAge)方法给对象的age属性值增加addAge岁.比如:2岁

案例2:

云课4.4:简单的学生管理系统

案例3:

云课4.7:学生管理系统

# 方法的重载

练习:方法重载的练习

用已有的知识编写下面代码:

需求:

定义一个方法求两个整数的和

定义一个方法求三个整数的和

定义一个方法求四个整数的和

# 什么是方法重载

在同一个类中,定义了多个同名的方法,这些同名的方法具有多种功能

每个方法具有不同的参数类型或者参数个数,这些同名的方法,就构成了重载关系

简单一点来说:方法名相同,参数列表不同。与返回值无关

参数不同:个数不同、类型不同、顺序不同

image-20230119002548699

Java虚拟机会通过参数的不同来区分同名的方法

**案例1:**区分以下方法是否构成重载

image-20230305183454745

image-20230305183545644

案例2:根据类型比较

需求:使用方法重载的思想,设计比较两个整数是否相同的方法

要求:兼容全整数(byte short,int ,long)

最近更新: 5/20/2025, 2:44:56 PM
失败才是人生的主旋律   |