类
创建
- 类的属性和方法创建
//类的属性和方法创建
public class ClassCreation {
public static void main(String[] args) {
Person p1 = new Person();
p1.speak();
}
}
class Person {
String name;
int age;
public void speak() {
System.out.println("ddsds");
}
}
- 要注意在类的创建过程中jvm中的内存机制:
public class ClassDemo {
public static void main(String[] args) {
Cat cat = new Cat(); //创建一个cat对象
Cat cat1 = new Cat(); //创建cat1对象
cat.name = "king"; //对cat赋值
cat.age = 13;
cat1 = cat; //这里是引用赋值,cat1与cat共享一个堆空间,cat1改变,cat也会改变
// cat1 = null; //将cat1置空,使cat1与堆空间的连接断掉
System.out.println("名称:" + cat.name + " " + "年龄:" + cat.age);
System.out.println(cat1.name + " " + cat1.age); //如果将cat1 = null,会使这里报错,因为此时cat1与cat已经没有了关系。
}
}
class Cat{ //创建一个Cat类
String name;
int age;
}
方法调用机制
- 当程序调用方法时,会开辟一个栈空间,然后就会按照计息算计系统课程中函数调用那一节的方法执行P过程和Q过程,最后得到返回值。
- 方法的必要性:比如有一个二维数组需要遍历,用双重循环做,如果要对其进行10次遍历,代码量就会大大提升。而将遍历做成方法看,就调用十次放方法即可。
- 重要!!!:一个方法最多有一个返回值,如果想返回多个返回值怎么办?
- 答:可以将多个返回值利用数组存储起来,返回一个数组即可:
public class ClassCreation { public static void main(String[] args) { Person p1 = new Person(); int[] pres = p1.speak(2,5); //创建一个pres数组接受返回类型为数组的值 System.out.println(pres[0] + " " + pres[1] ); //输出得到的数组 } } class Person { String name; int age; public int[] speak(int m, int n) { //定义int[]类型 int[] res = new int[2]; res[0] = m + n; res[1] = m - n; return res; } }
- 方法里面不可以再定义方法,但是可以调用方法。
跨类方法调用
- 同包下的不同类之间的方法调用:需要被调用的函数时public类型。并且需要调用时先创建被调用函数所在类的对象:
public class MethodCall1 {
public static void main(String[] args) {
A a = new A();
a.f1();
}
}
class A {
public void f1() {
System.out.println("调用了f1");
B b = new B(); //创建类B的对象b
b.f2();
}
}
class B {
public void f2(){
System.out.println("f2被调用");
}
}
方法传参机制
- 注:当实参和形参是数组,对象时,都是引用传递。传的是地址,可以通过形参影响实参。
- 当参数为对象时
public class Method {
public static void main(String[] args) {
Person1 per11 = new Person1();
per11.age = 20;
System.out.println(per11.age);
Person2 per2 = new Person2();
per2.per1(per11);
System.out.println(per11.age);
}
}
class Person1 {
int age;
String name;
}
class Person2 {
public void per1(Person1 p){
p.age = 10;
}
}
- 输出结果为20,10。说明对象传参为引用传参。
- 当参数为数组时:
public class Method1 {
public static void main(String[] args) {
x1 x = new x1();
int[] a = {1,2,3};
x.aaa(a);
System.out.println("调用函数后");
for (int i = 0; i < a.length; i++){
System.out.print(a[i] + " ");
}
}
}
class x1 {
public int[] aaa(int[] p) {
//传参前
System.out.println("在函数中传参前");
for (int i = 0; i < p.length; i++){
System.out.print(p[i] + " ");
}
System.out.println();
p[0] = 5;
//传参后
System.out.println("在函数中传参后");
for (int i = 0; i < p.length; i++){
System.out.print(p[i] + " ");
}
System.out.println();
return p;
}
}
- 输出结果:
- 发现数组和对象传参时都是引用传参,形参会改变实参。
- 如果想创建与原来对象独立相同的一个对象,则在函数里新创建一个对象,将原对象的属性赋值给新对象,再返回新对象即可。
方法递归调用
- 递归能解决什么问题
- 各种数学问题,8皇后问题,汉诺塔,阶乘问题,迷宫问题,球和篮子的问题
- 各种算法中也会用到递归,比如快排,归并排序,二分查找,分治算法
- 递归在栈中,先找到最里层的函数和值,依次往外输。
- 求n的阶乘:
public class Factorial {
public static void main(String[] args) {
Factorial1 p = new Factorial1();
double op = p.factorial2(4);
System.out.println(op);
}
}
class Factorial1 { //阶乘类
public double factorial2(int n) { //方法
if(n == 1){
return 1;
}else {
return factorial2(n - 1) * n; //n * (n-1) * ...
}
}
}
斐波那契数列(递归)
- 1,1,2,3,5,8,13…,给出一个n,求值为多少?
- 思路:如果n == 1 || n == 2 时会返回1;其他情况等于f(n - 1 ) + f (n - 2);
- 代码:
import java.util.Scanner;
public class Feibonaqi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int index = input.nextInt();
Sa sa = new Sa();
int res = sa.feibonaqi(index);
System.out.println(res);
}
}
class Sa {
public int feibonaqi(int n) {
if(n == 1 || n == 2) {
return 1;
}else if(n == 0){
return 0;
}else {
return feibonaqi(n -1) + feibonaqi(n - 2);
}
}
}
老鼠走迷宫(韩顺平老师讲得真的好!!)
-
如图:
-
问题:如图的迷宫,老鼠需要从(1,1)这个位置走到(6,5)这个位置,需要找到该路径
-
原迷宫:
- 1表示障碍,0表示可以走的位置
- 思路:为什么用递归:因为是要从一个方向走,知道找到该位置才可以
-
代码:
public class Migong {
public static void main(String[] args) {
int[][] map = new int[8][7];
for (int i = 0; i < map.length; i++) {
for (int j =0; j < map[i].length; j++) {
if (i == 0 || i == 7) {
map[i][j] = 1;
}else if(j == 0 || j ==6) {
map[i][j] = 1;
}else {
map[i][j] = 0;
}
}
}
map[3][1] = 1;map[3][2] = 1;
A1 a1 = new A1();
a1.findWay(map,1,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();
}
}
}
//int[][] map 表示这个迷宫的二维数组
//i,j表示当前位置
//0表示二维数组中不为1,即不为障碍物;1表示障碍物;2表示能走通;3表示走过但不通;
//可以将递归看成一个自动的过程,直到遇到结束标志后停止
//从代码的递归顺序可以看出,优先顺序为下,右,上,左
class A1 {
public boolean findWay(int[][] map, int i, int j) {
if (map[6][5] == 2){ //结束标志
return true;
}else {
if (map[i][j] == 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 true;
}
}else {
return false;
}
}
}
}
汉诺塔问题
- 思路,利用递归:
- 先判断盘子个数,也是递归的停止条件
m == 1
。 - 整体思路为无论多少个盘子,始终看成2个,一个是最下面的,一个是上面m - 1 个盘子,也就是说把m - 1个盘子看成一个整体。
- 所以思路就是先将m - 1个盘子移到B柱,再将A柱上的一个盘子移到C柱,最后将B柱的移到C 柱。如此形成一个递归。
- 先判断盘子个数,也是递归的停止条件
- 代码:
public class Hanoi {
public static void main(String[] args) {
Test test = new Test();
test.test1(3 , 'a' , 'b', 'c');
}
}
class Test {
public void test1(int m, char a, char b, char c) {
if (m == 1){
System.out.println(a + "->" + c);
}else {
//借助c,将m-1个盘移动到b
test1(m -1, a, c, b);
//将最后一个盘移动到c
System.out.println(a + "->" + c);
//借助a,将b上m-1盘移动到c
test1(m - 1, b, a, c);
}
}
}
- 结果如图: