05 - 面向对象编程(基础部分二)

一、方法递归调用

基本介绍

递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂问题,同时可以让代码变得简洁。

递归举例

1)打印问题

public class Recursion01 {
	
	public static void main(String[] args) {
	//打印问题
	PrintTest printTest = new PrintTest();
	printTest.test(4);//输出什么? n=2 n=3 n=4
	} 
}

class PrintTest {
	//分析
	public void test(int n) { 
		if (n > 2) {
			test(n - 1); //调用自己
		}
		System.out.println("n=" + n); 
	}
}

//结果:
//n = 2
//n = 3
//n = 4

2)阶乘问题

public class Recursion01 {
	
	public static void main(String[] args) {
	//阶乘问题
	int res = t1.factorial(5); 
	System.out.println("5 的阶乘 res =" + res);
	} 
}

class T {
	//factorial 阶乘
	public int factorial(int n) {
		if (n == 1) { 
			return 1; //找出口
		} else {
			return factorial(n - 1) * n;
		} 
	}
}

递归规则

1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2)方法的局部变量是独立的,不会相互影响,比如 n 变量
3)如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据。
4)递归必须向退出递归的条件逼近,否则就是无限递归,出现*Error。
5)当一个方法执行完毕,或者遇到return,就会返回。
遵守谁调用,就将结果返回给谁。
同时当方法执行完毕或者返回时,该方法也就执行完毕。

二、方法重载(OverLoad)

基本介绍

Java 允许同一个类中,多个同名方法的存在,但要求 形参列表不一致

重载的好处

1)减轻了起名的麻烦
2)减轻了记名的麻烦

重载案例

1) calculate(int n1, int n2) //两个整数的和
2) calculate(int n1, double n2) //一个整数,一个 double 的和
3) calculate(double n2, int n1) //一个 double,一个 Int 和
4) calculate(int n1, int n2,int n3) //三个 int 的和

注意事项

1)方法名:必须相同
2)形参列表:必须不同(形参类型、个数 或 顺序,至少有一样不同,参数名无要求)
3)返回类型:无要求

三、可变参数

基本介绍

Java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
这就可以通过可变参数实现

基本语法

访问修饰符 返回类型 方法名(数据类型... 形参名) {

}

使用案例

//1. int... 表示接受的是可变参数,类型是 int,即可以接收多个 int(0-多)
//2. 使用可变参数时,可以当做数组来使用,即 nums 可以当做数组
//3. 遍历 nums 求和即可
public int sum(int... nums) {
	//System.out.println("接收的参数个数=" + nums.length);
	int res = 0;
	for(int i = 0; i < nums.length; i++) {
		res += nums[i];
	}
	return res;
}

注意事项

1)可变参数的实参可以为 0 个或任意多个
2)可变参数的实参可以为数组
3)可变参数的本质就是数组
4)可变参数可以和普通类型的参数一起放在形参列表,
但必须保证可变参数在最后一项
5)一个形参列表中只能出现一个可变参数

四、作用域

基本使用

1)在Java编程中,主要的变量就是属性(成员变量)和局部变量。
2)局部变量一般是指在成员方法中定义的变量。
3)Java中作用域的分类:
	全局变量:也就是属性,作用域为整个类体。
	局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中。
4)全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后才能使用,因为没有默认值。
class Cat {
	//全局变量:也就是属性,作用域为整个类体 Cat 类:cry eat 等方法使用属性 
	//属性在定义时,可以直接赋值
	int age = 10; //指定的值是 10
	//全局变量(属性)可以不赋值,直接使用,因为有默认值, 
	double weight; //默认值是 0.0

	public void hi() { 
		//局部变量必须赋值后,才能使用,因为没有默认值 
		int num = 1;
		String address = "北京的猫"; 
		System.out.println("num=" + num); 
		System.out.println("address=" + address); 
		System.out.println("weight=" + weight);//属性
	}
	
	public void cry() {
		//1. 局部变量一般是指在成员方法中定义的变量 
		//2. n 和 name 就是局部变量
		//3. n 和 name 的作用域在 cry 方法中
		int n = 10;
		String name = "jack";
		System.out.println("在 cry 中使用属性 age=" + age);
	}
}

注意事项

1)属性和局部变量可以重名,访问时遵循就近原则。
2)在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名。
3)属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。
4)作用域范围不同
	全局变量/属性:可以被本类使用,或其他类使用。(通过对象调用)
	局部变量:只能在本类中对应的方法中使用。
5)修饰符不同
	全局变量/属性可以加修饰符。
	局部变量不可以加修饰符。

五、构造方法/构造器

基本语法

[修饰符] 方法名(形参列表) {
	方法体;
}

说明:
1) 构造器的修饰符可以默认,也可以是 public、protected、private。
2) 构造器没有返回值。
3) 方法名 和 类名字必须一样。
4) 参数列表 和 成员方法一样的规则。
5) 构造器的调用, 由系统完成

基本介绍

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
它有几个特点:
方法名 和 类名相同
没有返回值
在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。

使用案例

public class Constructor01 {
	public static void main(String[] args) {
	//当我们 new 一个对象时,直接通过构造器指定名字和年龄 
		Person p1 = new Person("smith", 80);
		System.out.println("p1 的信息如下");
		System.out.println("p1 对象 name=" + p1.name);//smith 
		System.out.println("p1 对象 age=" + p1.age);//80
	}
}

class Person {
	String name;
	int age;
	
	//构造器
	//1. 构造器没有返回值, 也不能写 void 
	//2. 构造器的名称和类 Person 一样
	//3. (String pName, int pAge) 是构造器形参列表,规则和成员方法一样
	public Person(String pName, int pAge) {
		System.out.println("构造器被调用~~ 完成对象的属性初始化");
		name = pName;
		age = pAge;
	}
}

注意事项

1)一个类可以定义多个不同的构造器,即构造器重载。
	比如:我们可以再给 Person类 定义一个构造器。
	用来创建对象的时候,只指定人名,不需要指定年龄。
2)构造器名字 和 类名要相同。
3)构造器没有返回值。
4)构造器是完成对象的初始化,并不是创建对象。
5)在创建对象时,系统自动的调用该类的构造方法。
6)如果程序员没有定义构造器,系统会自动给类生成一个默认的无参构造器(也叫默认构造器)
	比如Dog () {}    使用javap指令反编译看看
7)一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下
	即:Dog () {}

六、对象创建的流程分析

Class Person{
	Int age = 20;
	String name;
	
	Person(String n, int a) {
		Name = n;
		Age = a;
	}
}

Person p = new Person(“jack”, 20);

流程分析:

1)加载xxx类信息,只会加载一次
2)在堆中分配空间(地址)
3)完成对象初始化
	1 - 默认初始化 如:name = null; age = 0;
	2 - 显示初始化,类中属性定义好了的值 int age = 20
	3 - 构造器的初始化 name = “jack”, int age = 20
4)将对象在堆中的地址返回给 p

七、This关键字

public Dog(String name, int age) {//构造器
	//this.name 就是当前对象的属性 name
	this.name = name;
	//this.age 就是当前对象的属性 age
	this.age = age;
	System.out.println("this.hashCode=" + this.hashCode());
}

1) this 关键字可以用来访问本类的属性、方法、构造器。
2) this 用于区分当前类的属性和局部变量。
3) 访问成员方法的语法:this.方法名(参数列表);
4) 访问构造器语法:this(参数列表);
注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一条语句)
5) this 不能在类定义的外部使用,只能在类定义的方法中使用。

This案例

定义 Person 类,里面有 name、age 属性
并提供 compareTo 比较方法,用于判断是否和另一个人相等
提供测试类 TestPerson 用于测试
名字和年龄完全一样,就返回 true, 否则返回 false。
public class TestPerson {
	//编写一个 main 方法
	public static void main(String[] args) {
	
	Person p1 = new Person("mary", 20); 
	Person p2 = new Person("mary", 20);
	
	System.out.println("p1 和 p2 比较的结果=" + p1.compareTo(p2)); 
	}
}

class Person {
	String name;
	int age;
	//构造器
	public Person(String name, int age) {
		this.name = name;
		this.age = age; 
	}
	//compareTo 比较方法
	public boolean compareTo(Person p) {
	//名字和年龄完全一样
	// if(this.name.equals(p.name) && this.age == p.age) { 
	// 		return true;
	// } else {
	// 		return false;
	// }
	return this.name.equals(p.name) && this.age == p.age;
	}
}

注:本博客引用韩顺平老师Java课程

上一篇:swift 元组的创建和取值


下一篇:C++ 类和对象--对象的初始化和清理