一、方法递归调用
基本介绍
递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂问题,同时可以让代码变得简洁。
递归举例
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课程