6.1 类与对象
- 类就是数据类型
- 对象就是一个具体的实例
- 属性(成员变量)不赋值的话,有默认值,规则和数组一致
6.2 对象在内存中的存在形式
6.3 类和对象的内存分配机制
6.4 方法的调用机制原理
6.5 成员方法传参机制
6.5.1 基本数据类型的传参机制
- 基本数据类型,传递的是值(拷贝一份),形参的改变不影响实参
6.5.2 引用数据类型的传参机制
-
引用数据类型,传递的是地址,可以通过形参影响实参
-
p=null;
和p=new Pewson();
是把方法开辟的栈空间中的地址p改变,主栈中的地址p和地址指向的内存不受影响
6.5.3 练习
编写一个方法 copyPerson,可以复制一个 Person 对象,返回复制的对象。克隆对象, 注意要求得到新对象和原来的 对象是两个独立的对象,只是他们的属性相同
6.6 方法递归调用
6.6.1 递归案例
public class Recursion01 {
//编写一个 main 方法
public static void main(String[] args) {
T t1 = new T();
t1.test(4);//输出什么? n=2 n=3 n=4
int res = t1.factorial(5);
System.out.println("5 的阶乘 res =" + res);
}
}
class T {
//打印问题
public void test(int n) {
if (n > 2) {
test(n - 1);
}
System.out.println("n=" + n);
}
//factorial 阶乘
public int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
}
6.6.1.1 打印问题
6.6.1.2 阶乘问题
6.6.2 递归重要规则
- 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
- 方法的局部变量是独立的,不会相互影响,比如n变量
- 如果方法中使用的是引用类型变量(比如数组、对象),就会共享该引用类型的数据
- 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,死龟了
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时但方法执行完毕或者返回时,该方法也就执行完毕,将栈空间的控制权、数据的分配权释放
6.6.3 练习
-
public class RecursionExer01 { public static void main(String[] args) { T t1 = new T(); System.out.println(t1.fibonacci(7)); } } class T { /* n = 1 斐波那契数 -> 1 n = 2 斐波那契数 -> 1 n >= 3 斐波那契数 -> 前两个数的和 */ public int fibonacci(int n) { if(n >= 1){ if(n == 1 || n == 2) return 1; else return fibonacci(n-1) + fibonacci(n-2); }else{ System.out.println("请输入大于一的整数!"); return -1; } } }
-
/* 猴子每次吃一半多一个桃子,第十天剩一个,原本有几个 反推: day = 10 时,有1个桃子 day = 9 时,有(day10+1)* 2 = 4 day = 8 时,有(day9+1)* 2 = 10 ...... */ public class RecursionExer02 { public static void main(String[] args) { T t1 = new T(); System.out.println(t1.eatPeach(8)); } } class T { public int eatPeach(int day) { if(day == 10) { return 1; } else if (day >= 1 && day <= 9){ return (eatPeach(day + 1) + 1) * 2; } else { System.out.println("输入1-10"); return -1; } } }
6.6.4 迷宫
见代码MiGong.java
6.6.5 汉诺塔
6.6.6 八皇后
6.7 方法重载(overload)
同名不同参(个数、类型、顺序),返回类型无要求
public int calculate(int n1, int n2) {
System.out.println("calculate(int n1, int n2) 被调用");
return n1 + n2;
}
//没有构成方法重载, 仍然是错误的,因为是方法的重复定义
//public void calculate(int n1, int n2) {
// System.out.println("calculate(int n1, int n2) 被调用");
// int res = n1 + n2;
//}
6.8 可变参数
6.8.1 概念用法
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
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;
}
int res = sum(1, 2);
int res = sum(1, 2, 3);
6.8.2 使用细节
- 可变参数的实参可以是0或者任意多个
- 可变参数的实参可以是数组
- 可变参数的本质就是数组
- 可变参数可以和普通类型的参数一起放在参数列表,但必须保证可变参数在最后
- 一个参数列表中只能出现一个可变参数
6.8.3 练习
public class VarParameterExercise {
public static void main(String[] args) {
HspMethod hsp = new HspMethod();
System.out.println(hsp.showScore("李明", 85, 90, 94));
System.out.println(hsp.showScore("张华", 70, 85, 75, 60));
}
}
class HspMethod {
public String showScore(String name, double... scores) {
double sum = 0;
for (int i = 0; i < scores.length; i++) {
sum += scores[i];
}
return name + scores.length + "门课成绩的总分为:" + sum;
}
}
6.9 作用域
6.9.1 基本使用
- 在Java编程中,主要的变量就是属性(成员变量)和局部变量
- 局部变量一般是值成员方法中定义的变量,还有就是代码块中定义的变量
- 作用域的分类
- 全局变量:也就是属性,作用域为整个类体(成员方法可以直接使用)
- 局部变量:属性之外的其他变量,作用域为定义它的代码块中
- 全局变量可以不赋值,直接使用,因为有默认值;局部变量必须赋值后,才能使用,因为没有默认值
6.9.2 使用细节
- 属性和局部变量可以重名,访问时遵循就近原则
- 在同一个作用域中,两个局部变量不能同名
- 属性生命周期长,伴随着对象的创建而创建,伴随着对象的销毁而销毁;局部变量生命周期短,伴随着它的代码块执行而创建,伴随着代码块的结束而销毁,即在一次方法调用过程中
- 作用范围不同
- 全局变量/属性:可以被本类使用,或者其他类使用(通过对象调用)
- 局部变量:只能在本类中对应的方法中使用
- 修饰符不同
- 全局变量/属性可以加修饰符
- 局部变量不可以加修饰符
6.10 构造方法/构造器
完成对对象的初始化
6.10.1 基本语法
[修饰符] 方法名 (形参列表) {
方法体;
}
6.10.2 使用细节
- 构造器的修饰符可以是默认、public、protected或者private
- 构造器没有返回值
- 方法名和类名一致(大小写)
- 参数列表和成员方法规则一致(可以无参、多参或者全参)
- 构造器的调用由系统完成,在创建对象时,系统会自动的调用该类的构造器完成对象的初始化
- 没有定义构造器时,系统会自动生成一个无参构造器
- 定义自己的构造器后,默认的构造器被覆盖了,就不能再使用默认的无参构造器,除非显式地定义一下,即:
Dog(){}
6.11 对象创建的流程分析
class Person {
int age = 90;
String name;
Person(String n, int a) {
name = n;
age = a;
}
}
Person p = new Person("小倩", 20);
流程:
- 加载Person类信息(Person.class),只会加载一次
- 在堆中分配空间(地址)
- 完成对象初始化
- 默认初始化,规则和数组一致
- 显式初始化,age = 90,name = null
- 构造器初始化,age = 20,name = “小倩”
- 把对象在堆中的地址,返回给p(p是对象名,也可以理解成对象的引用)
6.12 this关键字
-
哪个对象调用,this就代表哪个对象
-
this关键字可以用来访问本类的属性、方法、构造器
-
访问成员方法的语法:
this.方法名(参数列表);
-
访问构造器语法:
this(参数列表);
注意只能在构造器中使用(即只能在构造器中访问另外一个构造器,必须放在第一条语句)-
class T { private String name; private int age; //this访问构造器举例 public T() { this("jack", 100); System.out.println("T()构造器被调用"); } public T(String name, int age) { System.out.println("T(String name, int age)构造器被调用"); } //this访问成员方法举例 public void f1() { System.out.println("f1()方法···"); } public void f2() { System.out.println("f2()方法···"); f1(); //调用本类的f1的第一种方法 this.f1(); //调用本类的f1的第二种方法,有区别 } }
-
-
-
this用于区分当前类的属性和局部变量
-
this不能在类定义的外部使用,只能在类定义的方法中使用