一、类与对象
二、成员方法
三、成员方法传参机制
1.基本数据类型的传参机制
基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参。
public class MethodParameter01 {
public static void main(String[] args) {
int a = 10;
int b = 20;
AA obj = new AA();
obj.swap(a, b);
System.out.println("main方法中:a=" + a + "b=" + b); //a=10 b=20
}
}
class AA {
public void swap(int a, int b) {
//swap方法:完成参数a和b的交换
System.out.println("交换前的参数:a=" + a + "b=" + b); //a=10 b=20
int temp = a;
a = b;
b = temp;
System.out.println("交换后的参数:a=" + a + "b=" + b); //a=20 b=10
}
}
2.引用数据类型的传参机制
引用数据类型,传递的是地址(传递的也是值,但是值是地址),可以通过形参影响实参。
案例:
(1)B类中编写一个方法test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?有
public class MethodParameter02 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
B b = new B();
b.test100(arr);
System.out.println("main中的arr数组:"); //200 2 3
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
class B {
public void test100(int[] arr) {
arr[0] = 200;
System.out.println("test100中的arr数组:"); //200 2 3
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
System.out.println(" "); //换行
}
}
(2)B类中编写一个方法test200,可以接收一个Person对象,在方法中修改该对象属性,看看原来的对象是否变化?有
思考:1)如果test200执行的是 p = null,输出的结果是多少?1
2)如果test200执行的是 p = new Person();... ,输出的结果是多少?1
public class MethodParameter02 {
public static void main(String[] args) {
Person p = new Person();
p.name = "小明";
p.age = 1;
B b = new B();
b.test200(p);
System.out.print(p.age); //10000
//如果test200执行的是 p = null,输出的结果是1
//如果test200执行的是 p = new Person();... ,输出的结果是1
}
}
class Persom {
String name;
int age;
}
class B {
public void test200(Person p) {
//p.age = 10000;
//思考:p=null会输出什么呢?
//p = null;
//思考:
p = new Person();
p.name = "tom";
p.age = 10;
}
}
3.克隆对象
需求:编写一个方法copyPerson,可以赋值一个Person对象,返回赋值的对象。注意,要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同。
public class MethodExercise02 {
public static void main(String[] args) {
Person p = new Person();
p.name = "milan";
p.age = 100;
Mytools tools = new Mytools();
Person p2 = tools.copyPerson(p);
//到此,p和p2是Person对象,但是是两个独立的对象,属性相同
System.out.println("原来的对象p的属性:name=" + p.name + "\tage=" + p.age); //milan 100
System.out.println("新的对象p2的属性:name=" + p2.name + "\tage=" + p2.age); //milan 100
//老师提示:可以进行对象比较看看是否为同一个对象
System.out.println(p == p2); //false
}
}
class Person {
String name;
int age;
}
class Mytools {
//编写思路:
//1.方法的返回类型 Person
//2.方法的名字 copyPerson
//3.方法的形参 (Person p)
//4.方法体 创建一个新对象,并复制属性,返回即可
public Person copyPerson(Person p) {
//创建一个新的对象
Person p2 = new Person();
p2.name = p.name; //把原来对象的名字赋给p2.name
p2.age = p.age; //把原来对象的年龄赋给p2.age
return p2;
}
}
4.方法递归调用
(1)基本介绍
递归就是方法调用自己,每次调用时传入不同的变量。
(2)递归能解决什么问题?
1)各种数学问题:8皇后问题、汉诺塔、阶乘问题、迷宫问题、球和篮子问题。
2)各种算法中也会使用到递归,比如快排、归并排序、二分查找、分治算法等。
3)将用栈解决的问题-->递归代码比较简洁。
(3)递归举例
1)打印问题
2)阶乘问题
public class Recursion01 {
//编写一个main方法
public static void main(String[] args) {
T t1 = new T();
t1.test(4); //输出什么?
int res = t1.factorial(5);
System.out.println("5的阶乘 res=" + res);//120
}
}
class T {
//1.打印问题
public void test(int n) {
//(1)输出n=2,n=3,n=4
if(n > 2) {
test(n - 1);
}
System.out.println("n=" + n);
//(2)只输出n=2
// if(n > 2) {
// test(n - 1);
// }else{
// System.out.println("n=" + n);
// }
}
//2.阶乘问题
public int factorial(int n) {
if(n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
}
(4)递归重要规则
1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间)。
2)方法的局部变量是独立的,不会相互影响。
3)如果方法中使用的是引用类型变量(比如数组、对象),就会共享该引用类型的数据。
4)递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError(死龟了)。
5)当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回,该方法也就执行完毕。
(5)课堂练习
1)递归斐波那契
请使用递归的方式求出斐波那契数1,1,2,3,5,8,13...给你一个整数n,求出它的值是多少?
2)猴子吃桃
猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个。以后每天猴子都吃其中的一半,然后再多吃一个。当到第10天时(即还没吃),发现只有1个桃子了。问:最初共多少个桃子?
public class RecursionExercise01 {
public static void main(String[] args) {
//1.递归斐波那契
T t1 = new T();
int n = 7;
int res = t1.fibonacci(n);
if(res != -1) {
System.out.println("整数" + n + "对应的斐波那契数是:" + res);
}
//2.猴子吃桃问题
int day = 1;
int peachNum = t1.peach(day);
if(peachNum != -1) {
System.out.println("第" + day + "天有" + peachNum + "个桃子");
}
}
}
class T {
/*
请使用递归的方式求出斐波那契数1,1,2,3,5,8,13...给你一个整数n,求出它的值是多少?
思路分析:
1.当n=1时,斐波那契数是1
2.当n=2时,斐波那契数是1
3.当n>=3时,斐波那契数是前两个数的和
4.这里就是一个递归的思路
*/
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("要求输入>=1的整数n");
return -1;
}
}
/*
猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个。
以后每天猴子都吃其中的一半,然后再多吃一个。当到第10天时(即还没吃),发现只有1个桃子了。
问:最初共多少个桃子?
思路分析 逆推
1.day=10时,有1个桃
2.day=9时,有(day10 + 1) * 2
3.day=8时,有(day9 + 1) * 2
4.规律就是 前一天的桃子 = (后一天的桃子 + 1) * 2
5.递归
*/
public int peach(int day) {
if(day == 10) {
return 1;
} else if(day >=1 && day <=9 ) {
return (peach(day + 1) + 1) * 2;
}else {
System.out.println("day在1-10");
return -1;
}
}
}
3)迷宫问题
1.老鼠走的路径,和程序员设置的找路策略有关,即:找路的上下左右的顺序相关。
2.扩展思考:如何求出最短路径?
方法一:穷举;方法二:图→求出最短路径。
public class MiGong {
public static void main(String[] args) {
/*
思路:
1.先创建迷宫,用二维数组表示
2.先规定 map 数组元素值:0表示可以走,1表示障碍物
*/
int[][] map = new int[8][7];
//3.将最上面的一行和最下面的一行,全部设置为1
for(int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
//4.将最左边的一列和最右面的一列,全部设置为1
for(int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}
map[3][1] = 1;
map[3][2] = 1;
map[2][2] = 1;
//输出当前的地图
for(int i = 0;i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " ");
}
//换行
System.out.println();
}
T t1 = new T();
t1.findWay(map, 1, 1);
System.out.println("\n======找路的情况如下=======\n");
for(int i = 0;i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " ");
}
//换行
System.out.println();
}
}
}
class T {
//解读:
//1.findWay方法就是专门来找出迷宫的路径
//2.如果找到就返回true,否则返回false
//3.map就是二维数组,即表示迷宫
//4.i,j就是老鼠的位置,初始化的位置是(1,1)
//5.因为我们是递归地找路,所以我先规定map数组的各个值的含义
// 0:表示地图中可以走;1:表示地图中障碍物;2.表示路线可以走;3:表示走过,但走不通。
//6.当map[6][5]==2就说明找到通路,就可以结束,否则就继续找
//找路策略:下-右-上-左
public boolean findWay(int[][] map ,int i, int j){
if(map[6][5] == 2) { //说明已经找到
return true;
}else {
if(map[i][j] == 0) { //当前这个位置为0,表示可以走
//我们假定可以走通
map[i][j] = 2;
//使用找路策略,来确定该位置是否真的可以走通
//下-右-上-左
if(findWay(map, i + 1, j)) {//先走下
return true;
}else if(findWay(map, i, j + 1)) {//右
return true;
}else if(findWay(map, i - 1, j)) {//上
return true;
}else if(findWay(map, i, j - 1)) {//左
return true;
}else {
map[i][j] = 3;
return false;
}
}else { //map[i][j] = 1,2,3
return false;
}
}
}
//找路策略:上-右-下-左
public boolean findWay2(int[][] map ,int i, int j){
if(map[6][5] == 2) { //说明已经找到
return true;
}else {
if(map[i][j] == 0) { //当前这个位置为0,表示可以走
//我们假定可以走通
map[i][j] = 2;
//使用找路策略,来确定该位置是否真的可以走通
//上-右-下-左
if(findWay2(map, i - 1, j)) {//先走上
return true;
}else if(findWay2(map, i, j + 1)) {//右
return true;
}else if(findWay2(map, i + 1, j)) {//上
return true;
}else if(findWay2(map, i, j - 1)) {//左
return true;
}else {
map[i][j] = 3;
return false;
}
}else { //map[i][j] = 1,2,3
return false;
}
}
}
}
4)汉诺塔
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
public class HanoiTower {
public static void main(String[] args) {
Tower tower = new Tower();
tower.move(5, 'A', 'B', 'C');
}
}
class Tower {
//num 表示要移动的个数,a:A塔(起点塔);b:B塔(中间塔);C塔(终点塔)
public void move(int num char a, char b, char c) {
if(num == 1) {
System.out.println(a + "->" + b);
}else {
//如果有多个盘,可以看成两个,最下面的和上面的所有盘
//(1)先移动上面所有的盘到b,借助c
move(num - 1, a, c, b);
//(2)把最下面的这个盘,移动到c
System.out.println(a + "->" + c);
//(3)再把b塔的所有盘,移动到c,借助a
move(num - 1, b, a, c);
}
}
}
5)八皇后
四、重载(overload)
1.基本介绍
Java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致。
比如:System.out.println();out是PrintStream类型。
重载的好处:(1)减轻了起名的麻烦;(2)减轻了记名的麻烦。
2.注意事项和使用细节
(1)方法名:必须相同。
(2)形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)。
(3)返回类型:无要求。
public class OverLoad01 {
public static void main(String[] args) {
MyCalculator mc = new MyCalculator();
System.out.println(mc.calculate(1, 3));
}
}
class MyCalculator {
public int calculate(int n1, int n2) {
return n1 + n2;
}
//没有构成重载,而是方法的重复定义
// public void calculate(int n1, int n2) {
// int res = n1 + n2;
// }
//没有构成重载,而是方法的重复定义
// public int calculate(int a1, int a2) {
// return a1 + a2;
// }
public double calculate(int n1, double n2) {
return n1 + n2;
}
public double calculate(double n1, int n2) {
return n1 + n2;
}
public int calculate(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
}
3.课堂练习
(1)选择题
(2)编程题
public class OverLoadExercise {
public static void main(String[] args) {
Methods methods = new Methods();
methods.m(10);
methods.m(10, 20);
methods.m("abcdefg");
System.out.println(methods.max(10, 20));//20
System.out.println(methods.max(34.0, 12.4));//34.0
System.out.println(methods.max(11.2, 22.3, 30));
//调用max(double, double, int),因为它不用做数据转换;
//如果只有max(double, double, double),也可以执行,自动做数据转换 int->double
}
}
class Methods {
public void m(int n) {
System.out.println("平方=" + (n * 2));
}
public void m(int n, int m) {
System.out.println(n * m);
}
public void m(String str) {
System.out.println("传入的str=" + str);
}
public int max(int n1, int n2) {
return n1 > n2 ? n1 : n2;//三元运算符,判断n1是否大于n2,如果大于,则返回n1,否则返回n2
}
public double max(double n1, double n2) {
return n1 > n2 ? n1 : n2;
}
public double max(double n1, double n2, double n3) {
double max = n1 > n2 ? n1 : n2;
return max = max > n3 ? max : n3;
}
public double max(double n1, double n2, int n3) {
double max = n1 > n2 ? n1 : n2;
return max = max > n3 ? max : n3;
}
}