第7章:面向对象编程(基础部分)

本文深入探讨了面向对象编程的基础概念,包括类与对象的关系、对象的内存存在形式、属性和成员变量的定义及访问、对象创建与访问属性的语法。文章通过养猫猫问题阐述了引入类与对象的原因,并详细分析了类和对象在内存中的分配机制,强调了成员方法的重要性和使用细节,以及方法的传参机制。此外,还涵盖了递归调用的原理和应用场景,以及方法重载和可变参数的基本概念和使用。最后,介绍了构造方法的作用和使用,以及this关键字的解释和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

7.1 类与对象

7.1.1 看一个养猫猫问题

张老太养了两只猫猫:一只名字叫小白,今年 3 岁,白色。还有一只叫小花,今年 100 岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示 张老太没有这只猫猫。

7.1.2 使用现有技术解决

【常规操作】

    1. 单独的定义变量解决 => 不利于数据的管理
    1. 使用数组解决
    • (1)数据类型体现不出来
    • (2) 只能通过[下标]获取信息,造成变量名字和内容的对应关系不明确
    • (3) 不能体现猫的行为(猫的方法)
public class Object01{
   
   
	public static void main(String[] args){
   
   
		//需求:
		//张老太养了两只猫猫:一只名字叫小白,今年 3 岁,白色。
		//还有一只叫小花,今年 100 岁,花色。
		//请编写一个程序,当用户 输入小猫的名字时,就显示该猫的名字,年龄,颜色。
		//如果用户输入的小猫名错误,则显示 张老太没有这只猫猫。
		//思路分析:
		//单独变量来解决 => 不利于数据的管理(你把一只猫的信息拆解)
		//
		//第一只猫的信息
		String cat1Name = "小白";
		int cat1Age = 3;
		String cat1Color = "白色";

		//第二只猫的信息
		String cat2Name = "小花";
		int cat2Age = 100;
		String cat2Color = "花色";

		//数组 ===>(1) 数据类型体现不出来
		//		   (2) 只能通过[下标]获取信息,造成变量名字和内容的对应关系不明确
		//		   (3) 不能体现猫的行为
		//第1只猫信息
		String[] cat1 = {
   
   "小白", "3", "白色"};

		//第二只猫的信息
		String[] cat2 = {
   
   "小花", "100", "花色"};
	}
}

7.1.3 现有技术解决的缺点分析

不利于数据的管理,以往的技术使用效率低 ===》 引出我们的新知识点 类与对象;

Java 设计者 引入 类与对象(OOP) ,根本原因就是现有的技术,不能完美的解决新的需求。


public class Object01 {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   

		/*
		张老太养了两只猫猫:一只名字叫小白,今年3岁,白色。 
		还有一只叫小花,今年100岁,花色。请编写一个程序,当用户输入小猫的名字时,
		就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,
		则显示 张老太没有这只猫猫。
		 */

		//使用OOP面向对象解决
		//实例化一只猫[创建一只猫对象]
		//爱摸鱼的TT~解读
		//1. new Cat() 创建一只猫(猫对象【真实】)
		//2. Cat cat1 = new Cat(); 把创建的猫赋给 cat1【别称/名】 
		//3. cat1 就是一个对象(对象的引用)
		Cat cat1 = new Cat();
		cat1.name = "小白";
		cat1.age = 3;
		cat1.color = "白色";
		cat1.weight = 10;
		//创建了第二只猫,并赋给 cat2
		//cat2 也是一个对象(猫对象)
		Cat cat2 = new Cat();
		cat2.name = "小花";
		cat2.age = 100;
		cat2.color = "花色";
		cat2.weight = 20;

		//怎么访问对象的属性呢
		System.out.println("第1只猫信息" + cat1.name 
			+ " " + cat1.age + " " + cat1.color + " " + cat1.weight);

		System.out.println("第2只猫信息" + cat2.name 
			+ " " + cat2.age + " " + cat2.color + " " + cat2.weight);
	}
}
//使用面向对象的方式来解决养猫问题
//
//定义一个猫类 Cat -> 自定义的数据类型
class Cat {
   
   
	//属性/成员变量/filed字段
	String name; //名字
	int age; //年龄
	String color; //颜色
	double weight; //体重

	//行为

}

在这里插入图片描述

7.1.4 类与对象的关系示意图

  1. 在这里插入图片描述

  2. 在这里插入图片描述

7.1.5 类和对象的区别和联系

通过上面的案例和讲解,我们可以看出:

    1. 类是抽象的,概念的,代表一类事物,比如人类,猫类…,即它是数据类型;
    1. 对象是具体的,实际的,代表一个具体事物, 即 是实例;
    1. 类是对象的模板,对象是类的一个个体,对应一个实例。

7.1.6 对象在内存中存在形式(重要的)

对象在内存中存在堆内存里

在这里插入图片描述

7.1.7 属性/成员变量/field字段

基本介绍

    1. 从概念或叫法上看: 成员变量 = 属性 = field(字段) (即 成员变量是用来表示属性的,在之后统一叫 属性) 案例演示:Car(name,price,color) Object02.java
public class Object02 {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   
	}
}

class Car {
   
   
	String name;//属性, 成员变量, 字段 field
	double price;
	String color;
	String[] master;//属性可以是基本数据类型,也可以是引用类型(对象,数组)
}
    1. 属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。比如我们前面定义猫类 的 int age 就是属性。

注意事项和细节说明

PropertiesDetail.java

    1. 属性的定义语法同变量一致,示例:访问修饰符 属性类型 属性名;

这里简单的介绍访问修饰符: 控制属性的访问范围
有四种访问修饰符 public, proctected, 默认, private ,后面我会详细介绍

    1. 属性的定义类型可以为任意类型,包含基本类型或引用类型
    1. 属性如果不赋值,有默认值,规则和数组一致。

默认值: int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000, boolean false,String null

public class PropertiesDetail {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   
		//创建Person对象
		//p1 是对象名(对象引用)
		//new Person() 创建的对象空间(数据) 才是真正的对象
		Person p1 = new Person();

		//对象的属性默认值,遵守数组规则:
		//int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
	
		System.out.println("\n当前这个人的信息");
		System.out.println("age=" + p1.age + " name=" 
				+ p1.name + " sal=" + p1.sal + " isPass=" + p1.isPass) ;
	}
}

class Person {
   
   
	//四个属性
	int age;
	String name;
	double sal;
	boolean isPass;
}

在这里插入图片描述

7.1.8 如何创建对象

    1. 先声明再创建
Cat cat ; //声明对象 cat是对象名(对象引用),在栈空间,指向为null【因为没有真正的对象空间(没分配空间)】
cat = new Cat(); //创建 new Cat() 创建的对象空间(数据),在堆内存 才是真正的对象
    1. 直接创建
Cat cat = new Cat();// 先在堆内存分配好空间,然后赋值给栈内存,栈内存就指向该地址

7.1.9 如何访问属性

基本语法

对象名(对象引用).属性名; 

案例演示赋值和输出

cat.name ; 
cat.age; 
cat.color; 

7.1.10 类和对象的内存分配机制(重要)

我们先思考一道题:
在这里插入图片描述

采用内存分析方法来解决:
在这里插入图片描述

Java 内存的结构分析

    1. 栈: 一般存放基本数据类型(局部变量)
    1. 堆: 存放对象(Cat cat , 数组等)
    1. 方法区:常量池(常量,字符串…), 类加载信息

Java 创建对象的流程简单分析

Person p = new Person(); 
p.name = “jack”; 
p.age = 10;
  1. 先加载 Person 类信息(属性和方法信息到方法区, 只会加载一次)
    2) 在堆中分配空间, 进行默认初始化(看和数组规则一样) 【有数据就有地址】
    3) 把地址赋给 p , p 就指向该对象
    4) 进行指定初始化, 比如 p.name =”jack” p.age = 10

例如:看一个练习题,并分析画出内存布局图,进行分析
在这里插入图片描述

分析(一步到位):你们在分析过程可以一步一步执行,就能明白了。
在这里插入图片描述

7.2 成员方法

7.2.1 基本介绍

在某些情况下,我们要需要定义成员方法(简称方法)。比如人类:除了有一些属性外( 年龄,姓名…),我们人类还有一些行为比如:可以说话、跑步… 通过学习,还可以做算术题。这时就要用成员方法才能完成。现在要求对 Person 类进行完善。

7.2.2 成员方法快速入门

下面有4个方法实例进行实现:
1) 添加 speak 成员方法,输出 “我是一个好人”
2) 添加 cal01 成员方法,可以计算从 1+…+1000 的结果
3) 添加 cal02 成员方法,该方法可以接收一个数 n,计算从 1+…+n 的结果
4) 添加 getSum 成员方法,可以计算两个数的和

public class Method01 {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   
		//方法使用
		//1. 方法写好后,如果不去调用(使用),不会输出
		//2. 先创建对象 ,然后调用方法即可
		Person p1 = new Person();
		p1.speak(); //调用方法
		p1.cal01(); //调用cal01方法
		p1.cal02(5); //调用cal02方法,同时给n = 5
		p1.cal02(10); //调用cal02方法,同时给n = 10
		
		//调用getSum方法,同时num1=10, num2=20
		//把 方法 getSum 返回的值,赋给 变量 returnRes
		int returnRes = p1.getSum(10, 20); 
		System.out.println("getSum方法返回的值=" + returnRes);
	}
}

class Person {
   
   
	
	String name;
	int age;
	//方法(成员方法)
	//添加speak 成员方法,输出 “我是一个好人”
	//爱摸鱼的TT~解读
	//1. public 表示方法是公开
	//2. void : 表示方法没有返回值
	//3. speak() : speak是方法名, () 形参列表
	//4. {} 方法体,可以写我们要执行的代码
	//5. System.out.println("我是一个好人"); 表示我们的方法就是输出一句话
	
	public void speak() {
   
   
		System.out.println("我是一个好人");
	}

	//添加cal01 成员方法,可以计算从 1+..+1000的结果
	public void cal01() {
   
   
		//循环完成
		int res = 0;
		for(int i = 1; i <= 1000; i++) {
   
   
			res += i;
		}
		System.out.println("cal01方法 计算结果=" + res);
	}
    
	//添加cal02 成员方法,该方法可以接收一个数n,计算从 1+..+n 的结果
	//爱摸鱼的TT~解读
	//1. (int n) 形参列表, 表示当前有一个形参 n, 可以接收用户输入
	public void cal02(int n) {
   
   
		//循环完成
		int res = 0;
		for(int i = 1; i <= n; i++) {
   
   
			res += i;
		}
		System.out.println("cal02方法 计算结果=" + res);
	}

	//添加getSum成员方法,可以计算两个数的和
	//爱摸鱼的TT~解读
	//1. public 表示方法是公开的
	//2. int :表示方法执行后,返回一个 int 值
	//3. getSum 方法名
	//4. (int num1, int num2) 形参列表,2个形参,可以接收用户传入的两个数
	//5. return res; 表示把 res 的值, 返回
	public int getSum(int num1, int num2) {
   
   
		int res = num1 + num2;
		return res;
	}
}

在这里插入图片描述

那底层是如何呢?

7.2.3 方法的调用机制原理(重要!-示意图!!!)

提示:画出程序执行过程[就针对getSum()方法分析]+说明
在这里插入图片描述

7.2.4 为什么需要成员方法

我们先看一个需求:请遍历一个数组 , 输出数组的各个元素值。

  • 解决思路 1,传统的方法,就是使用单个 for 循环,将数组输出,大家看看问题是什么?
    • 假如我们需要输出很多数组值,那采用该思路就只能不断重复写for循环这几行代码
    • 要修改for循环代码,那也只能每个代码都需修改
public class Method02 {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   

		//请遍历一个数组 , 输出数组的各个元素值
		int [][] map =  {
   
   {
   
   0,0,1},{
   
   1,1,1},{
   
   1,1,3}};

		//遍历map数组
		//传统的解决方式就是直接遍历
		for(int i = 0; i < map.length; i++) {
   
   
		 	for(int j = 0; j < map[i].length; j++) {
   
   
		 		System.out.print(map[i][j] + "\t");
		 	}
		 	System.out.println();
		}

		//....
		//
		//要求再次遍历map数组
		for(int i = 0; i < map.length; i++) {
   
   
		 	for(int j = 0; j < map[i].length; j++) {
   
   
				System.out.print(map[i][j] + "\t");
		 	}
		 	System.out.println();
		}

		//...再次遍历
		//
		for(int i = 0; i < map.length; i++) {
   
   
		 	for(int j = 0; j < map[i].length; j++) {
   
   
		 		System.out.print(map[i][j] + "\t");
		 	}
		 	System.out.println();
		}
	}
}
  • 解决思路 2: 定义一个类 MyTools ,然后写一个成员方法,调用方法实现,看看效果又如何。
public class Method02 {
   
    

	//编写一个main方法
	public static void main(String[] args) {
   
   

		//请遍历一个数组 , 输出数组的各个元素值
		int [][] map =  {
   
   {
   
   0,0,1},{
   
   1,1,1},{
   
   1,1,3}};

		//使用方法完成输出, 创建MyTools对象 
		MyTools tool = new MyTools();

		//遍历map数组
		//传统的解决方式就是直接遍历
		// for(int i = 0; i < map.length; i++) {
   
   
		// 	for(int j = 0; j < map[i].length; j++) {
   
   
		// 		System.out.print(map[i][j] + "\t");
		// 	}
		// 	System.out.println();
		// }
		//使用方法
		tool.printArr(map);

		//....
		//
		//要求再次遍历map数组
		// for(int i = 0; i < map.length; i++) {
   
   
		// 	for(int j = 0; j < map[i].length; j++) {
   
   
		// 		System.out.print(map[i][j] + "\t");
		// 	}
		// 	System.out.println();
		// }
		tool.printArr(map);


		//...再次遍历
		//
		// for(int i = 0; i < map.length; i++) {
   
   
		// 	for(int j = 0; j < map[i].length; j++) {
   
   
		// 		System.out.print(map[i][j] + "\t");
		// 	}
		// 	System.out.println();
		// }
		tool.printArr(map);

	}
}

//把输出的功能,写到一个类的方法中,然后调用该方法即可
class MyTools {
   
   
	//方法,接收一个二维数组
	
	public void printArr(int[][] map) {
   
   
		System.out.println("=======");
		//对传入的map数组进行遍历输出
		for(int i = 0; i < map.length; i++) {
   
   
			for(int j = 0; j < map[i].length; j++) {
   
   
				System.out.print(map[i][j] + "\t");
			}
			System.out.println();
		}
	}
}

7.2.5 成员方法的好处

  1. 提高代码的复用性 ;
    2) 可以将实现的细节封装起来,然后供其他用户来调用即可。

7.2.6 成员方法的定义

访问修饰符 返回数据类型 方法名(形参列表..{
   
   //方法体 
	语句; 
	return 返回值; 
}
  1. 形参列表:表示成员方法输入 cal(int n) , getSum(int num1, int num2)
    2) 返回数据类型:表示成员方法输出, void 表示没有返回值
    3) 方法主体:表示为了实现某一功能代码块
    4) return 语句不是必须的。 【如果有返回值那就需要return,反之可以不写】
    5) 爱摸鱼的TT~提示:结合前面的题示意图, 来理解

7.2.7 注意事项和使用细节

1. 访问修饰符 (作用:控制方法使用的范围)

  • 如果不写,就为默认访问,[有四种: public, protected, 默认, private], 具体在后面说。

2. 返回数据类型

  1. 一个方法最多有一个返回值 [思考,如何返回多个结果?—>采用 返回“数组” ]
//1. 一个方法最多有一个返回值  [思考,如何返回多个结果?]
	public int[] getSumAndSub(int n1, int n2) {
   
   

		int[] resArr = new int[2]; 
		resArr[0] = n1 + n2;
		resArr[1] = n1 - n2;
		return resArr;
	}
  1. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)

    3) 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 而且要求返回值类型必须和 return 的值类型一致或兼容
//3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 
//   而且要求返回值类型必须和return的值类型一致或兼容
	public double f1() {
   
   

		double d1 = 1.1 * 3;
		int n = 100;
		return n; // int ->double 
		//return d1; //ok? double -> int (x)
	}
  1. 如果方法是 void,则方法体中可以没有 return 语句,或者 只写 return ;
//如果方法是void,则方法体中可以没有return语句,或者 只写 return ; 
//爱摸鱼的TT~提示:在实际工作中,我们的方法都是为了完成某个功能,所以方法名要有一定含义最好是见名知意
	public void f2() {
   
   

		System.out.println("hello1");
		System.out.println("hello1");
		System.out.println("hello1");
		int n = 10;
        //return n; // 错误
		return ;
	}

3. 方法名

  • 遵循驼峰命名法,最好见名知义,表达出该功能的意思即可, 比如 得到两个数的和 getSum, 开发中按照规范。

4. 形参列表

  1. 一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开,比如:getSum(int n1, int n2)
  2. 参数类型可以为任意类型,包含基本类型或引用类型,比如:printArr(int[][] map)
  3. 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数!
  4. 方法定义时的参数称为形式参数,简称形参;方法调用时的传入参数称为实际参数,简称实参,实参和形参的类型要一致或兼容、个数、顺序必须一致。

在这里插入图片描述

5. 方法体

里面写完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用、但里面不能再定义方法!即:方法不能嵌套定义。

6. 方法调用细节说明(!!!)

  1. 同一个类中的方法调用:直接调用即可。比如 print(参数);

案例演示:A类 sayOk 调用 print()
在这里插入图片描述

  1. 跨类中的方法A类调用B类的方法:需要通过对象名调用。比如 对象名.方法名(参数);

案例演示:B类 sayHello 调用 print()

在这里插入图片描述

  1. 特别说明一下:跨类的方法调用和方法的访问修饰符相关,先暂时这么提一下,后面我们讲到访问修饰符时,还要再细说。

7.2.8 巩固习题

  1. 编写类 AA ,有一个方法:判断一个数是奇数 odd 还是偶数, 返回 boolean
public class MethodExercise01{
   
   
	public static void main(String[] args){
   
   
		//需求:
		//编写类 AA ,有一个方法:判断一个数是奇数 odd 还是偶数, 返回 boolean
		AA a = new AA();
        
		if(a.isOdd(12)){
   
   
			
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛涛同学debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值