---
url: /doc/Java/qmhbnokt/index.md
---
> 面向对象是一种开发软件的方法，使分析、设计和实现一个系统的方法尽可能接近人们认识一个系统的方法。包括三个方面：面向对象分析、面向对象设计、面向对象程序设计。
>
> Java 语言是纯面向对象的语言。其所有数据类型都有相应的类，程序可以完全基于对象编写

## 6.1 类与对象

> 从 类 到 对象，可以称为 创建一个对象，也可以说 实例化一个对象，或者 把对象实例化
>
> 1. 类 是抽象的、概念的，代表一类事物
> 2. 对象 是具体的、实际的，代表一个个具体事物
> 3. 类 是 对象 的模板，对象 是 类 的一个个体，对应一个实例

### 6.1.1 属性/成员变量

> 从概念或叫法上看：成员变量 = 属性 = field（字段）

```java
class Cat{
	String name;
	int age;
}
```

### 6.1.2 创建对象

注意事项：

1. 声明对象的场合，只是在内存中建立了一个引用。此时，该地址引用不指向任何内存空间。

   对象的引用，也被称为对象的句柄。

2. 使用 new 运算符创建对象实例时，会为对象分配空间，就会调用类的构造方法。那之后，会将该段内存的首地址赋给刚才建立的引用

### ==6.1.3 类与对象的内存访问机制==

> 栈：一般存放基本数据类型（局部变量）
>
> 堆：存放对象（如`Cat cat1 = new Cat()`，是在这里开辟的空间），所有的 java 对象都存储在堆中。
>
> 方法区：常量池（常量，比如字符串），类加载信息

1. 创建对象时，先加载 类 信息，然后在 堆 中分配空间，栈 中的对象名被赋予指向那个空间的地址。
2. 之后进行指定初始化。该对象的 属性 中，是 基本数据类型 的直接记录在 堆 中；是 字符串 的记录一个地址，该地址指向 方法区，那里的常量池有该字符串。

## 6.2 成员方法

> 使用 成员方法，能提高代码的复用性。而且能把实现的细节封装起来，供其他用户调用。

### ==6.2.1 方法的调用机制==

以前文代码为例：

```java
...
		int r = cat1.speak2(15, 135);
...
public int speak2(int n1, int n2){
   int res = n1 + n2;
   return res;
}
...
```

1. 当程序执行到方法时，在 栈 中开辟一个新的 栈空间。该空间里储存 `n1 = 15` `n2 = 135`，之后计算并储存结果 `res = 150`
2. 当方法执行完毕，或执行到 `return` 语句时，就会返回
3. 把 新栈空间 中的 `res = 150` 返回 main 栈 中调用方法的地方
4. 返回后，继续执行该方法的后续代码

### 6.2.2 使用细节

1. 调用细节：
   * 同一个类中的方法调用，可以直接调用。
   * 跨类的方法调用，需要创建新对象，然后再调用方法。

### ==6.2.3 成员方法传参机制==

\==Java 语言对对象采用的是 **值传递**，方法得到的总是那个传入对象的副本。==

方法参数共有两种类型：

1. 基本数据类型（数字、布尔值)
2. 对象引用。

* \==方法不能修改基本数据类型的参数。基本数据类型传递的是一个值，形参不影响实参==。

* \==方法可以改变对象参数的状态。==

  引用类型传递的是一个地址，形参和实参指向一处，两者总会相关。

  但改变那个形参地址指向的场合，实参的指向不会改变

> java 核心技术卷一：
>
> 4.5 方法参数
>
> \==按值调用==表示方法接收的是调用者提供的值。而按引用调用表示方法接受的是调用者提供的变量地址，一个方法可以修改传递引用所对应的变量值，而不能修改传递值调用所对应的变量值。
>
> java 程序设计语言总是采用按值调用，方法得到的是所有参数值的一个拷贝，特别是，方法不能修改传递给它的任何参数变量的内容。

```java
> double percent = 10;
> harry.raiseSalary(percent):
> 不必理睬这个方法的具体实现， 在方法调用之后， percent 的值还是10。
```

> 但作将对象应用作为参数就不一样了。
> 拷贝的是对象的引用变量而不是整个对象，拷贝的和原来的引用指向同一个对象，可以理解为拷贝的对象引用是它的别名，实质指的是一个东西。可以通过这个别名引用来改变原对象。

总结一下 Java 中方法参数的使用情况：

* \==一个方法不能修改一个基本数据类型的参数（即数值型或布尔型）。==
* \==一个方法可以改变一个对象参数的状态。==
* \==一个方法不能让对象参数引用一个新的对象。==

## 6.3 ==方法递归调用==

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

> 下面，示范一个斐波那契数列方法

```java
class T{
    public int fib(int n){
       if(n == 1 || n == 2){
          return 1;
        }else{
            return (fib(n - 1)) + (feb(n - 2));
       }
   }
}
```

### 6.3.1 使用细节

1. 执行一个方法时，就创建一个新的受保护的独立 栈空间。
2. 方法的局部变量是独立的，不会相互影响。
3. 如果方法中使用的是引用变量，就会共享数据。（因为\[\[#==6.2.3 成员方法传参机制==]]
4. 递归必须向退出递归的条件逼近，否则就是无限递归，会提示 `StackOverflowError` “死龟”
5. 当一个方法执行完毕，或遇到 `return` 就会返回。遵守谁调用就返回给谁。同时当方法执行完毕或返回时，该方法也执行完毕

## 6.4 方法重载

方法重载（Overload）：Java 中允许同一类中，多个同名方法的存在，但要求 形参列表 不一致。

## ==6.5 可变参数==

> Java 允许将同一个类中多个同名同功能但参数个数不同的方法，封装成一个方法。

语法：`访问修饰符 返回类型 方法名（数据类型... 形参名）{代码块;}`

```java
public void m(int... n){
	//此时，n 相当于一个 数组。
	int length = n.length;
	int num1 = n[0];
}
```

### 6.5.1 使用细节

1. 可变参数 的实参可以是 0 个，也可以是 任意多 个。

2. 可变参数 的实参可以是数组

3. 可变参数 本质就是数组

   因此，出现：

   ```java
   public void met(int... n){				//这个方法与下面的方法不能构成重载
   }
   ```

   的场合，不能有方法：

   ```java
   public void met(int[] n){				//这个方法与上面的方法不能构成重载
   }
   ```

4. 可变参数 和 普通参数 可以一起放在形参列表，但必须保证 可变参数 在最后

   ```java
   public void m(double dou, int... n) {}
   ```

5. 一个形参列表最多出现 一个 可变参数。

## 6.6 作用域

1. 在 Java 编程中，主要的变量就是 **属性（成员变量**）和 **局部变量。**
2. 我们说的 局部变量 一般是指在成员方法中定义的变量。
3. 作用域的分类
   * 全局变量：也就是 属性，作用域为整个类体
   * 局部变量：除了属性外的其他变量。作用域为定义它的代码块中
4. 全局变量（属性）可以不赋值直接使用，那个场合有默认值。==局部变量必须赋值使用==

### 6.6.1 使用细节

1. 属性 和 局部变量 ==可以重名==，访问时遵循==就近原则==

2. 在同一作用域中，两个局部变量不能重名

3. \==属性 的生命周期较长。其伴随对象的创建而创建，伴随**对象**的销毁而销毁。==

   \==局部变量 生命周期较短。其伴随代码块的执行而创建，伴随**代码块**的结束而销毁。==

4. 全局变量/属性 可以被本类使用，==也可以被其他类（通过对象）使用。==

   局部变量 只能被本类的对应方法中调用

5. 全局变量/属性 **可以加** 修饰符

   \==局部变量 **不能加** 修饰符==

## 6.7 构造方法、构造器

> 构造方法又叫构造器（constructor），是类的一种特殊的方法。它的主要作用是完成对新对象的初始化

1. 构造器的修饰符可以是默认。也可以是别的
2. 参数列表 规则同 成员方法

### 6.7.1 使用细节

1. 构造器本质也是方法(并不会继承)。所以，可以 构造器重载。
2. 构造器名 和 类名 相同
3. 构造器无返回值
4. \==构造器是完成对象的初始化，而不是创建==
5. \==创建对象时，系统自动调用构造器==
6. 如果提供了构造器，则不会提供默认构造器了。
7. \==一旦定义了自己的构造器，就不能用无参构造器了。除非显式的定义一个无参构造器==

### ==6.7.2 流程分析==

```java
Person p1 = new Person("Amy", 10);

...

class Person{
	String name;
	int age = 20;
	public Person(String pName, int pAge){
		name = pName;
		age = pAge;
	}
}
```

1. 加载 类信息（**方法区**）

2. 在 **堆** 中开辟空间（地址）

3. 完成对象初始化

   * 首先默认初始化。`age = 0; name = null`

   * 之后显式初始化。`age = 20; name = null` //定义时的赋值

     其中，==显式初始化和代码块初始化按编写的先后顺序依次进行==。

   * 之后构造器的初始化。`age = 10; name = "Amy"`

4. 把对象在 堆 中的 地址，返回给 `p1`

## ==6.8 this 关键字==

> JVM 会给每个对象分配 this 代表当前对象。
>
> 相当于在 堆 中，this 指向自己（对象）
>
> 在类定义的方法中，Java 会自动用 this 关键字把所有变量和方法引用结合在一起。
>
> 遇到有同名的局部变量的场合，需要程序员加入 this 关键字进行区分。不加入 this 关键字的场合，Java 遵循就近原则。

```java
class Example{
    int n = 0;
	public void act(int n) {}
}
```

上面这个类的 `act()` 方法实际有 2 个参数。对其调用：

```java
Example e = new Exmaple();
e.act(100);
```

可见，出现在方法名前的参数 `e`，以及出现在方法名后的括号中的参数 `100`

\==出现在方法名前的参数被称为 **隐式参数**（也称为 方法调用的 目标 或 接收者）==

\==出现在方法名后的参数被称为 **显式参数**，就是所谓的实参==

在每一个方法中，用 **this 指代隐式参数**。

```java
public void act(int n) {
    this.n = n;
}
```

此时，再以相同方式调用方法：

```java
e.act(100);					// <———— 相当于 e.n = 100;
```

### `super 与 this 关键字`

super 关键字：我们可以通过 super 关键字来实现对父类成员的访问，用来引用当前对象的父类。

this 关键字：指向自己的引用。

> 《java 核心技术卷 1》：5.1.3 子类构造器
>
> 1. this 有两个用途： 一是引用隐式参数(==所构造的对象==)， 二是调用该类其他的构造器
>
> 2. super 也有两个用途：一是调用超类的方法，二是调用超类的构造器。
>
> 在调用构造器的时候， 这两个关键字的使用方式很相似。==调用构造器的语句只能作为另一个构造器的第一条语句出现。====构造参数既可以传递给本类(this ) 的其他构造器， 也可以传递给超类(super ) 的构造器。==

### 6.8.1 使用方法

1. `this` 关键字可以用来访问本类的属性、方法、构造器

2. `this` 用于区分当前类的 属性 和 局部变量

3. 访问本类中成员方法的语法：`this.方法名`

4. 访问构造器的语法：`this(参数列表);`

   注意：==只能在构造器中访问另一个构造器。而且，如果有这个语法，必须放置在第一条语句。==

5. \==`this` 不能在类定义的 外部 使用，只能在类定义的 方法中 使用==

## 附录

### 迷宫游戏代码

```java
/**
*@author Melody
*@version v1.2.6
**/

//迷宫
import java.util.Scanner;
public class MazeOut{

    public static void main(String[] args){
        //tools 方便后面调用方法。 inP 可以接收用户输入
        T tools = new T();
        Scanner inP = new Scanner(System.in);

        //提示并接收用户输入信息
        System.out.println("\n输入迷宫宽度（至少为6）：");
        int x = inP.nextInt();
        System.out.println("\n输入迷宫长度（至少为6）：");
        int y = inP.nextInt();
        //若用户输入的长或宽超出范围，则将其重置为正常值
        if(x < 6){
            x = 6;
        } else if(x > 110){
        	x = 110;
        }
        if(y < 6){
            y = 6;
        } else if(y > 60){
        	y = 60;
        }
        System.out.println("\n输入迷宫的困难度（请输入1 - 6的数字，数字越高越不容易获胜）：");
        int hard = inP.nextInt();
        if(hard == 7){
        	System.out.println("\n\n您选择了找点麻烦");
        } else if (hard == 8 || hard == 9){
        	System.out.println("\n\n您选择了给自己添堵");
        }
        System.out.println("\n\t迷宫生产完毕\n");

        //设置一个 count 值，记录步数。设为数组，以便数据通用。第一位记录当前值，第二位为最大值。
        int[] count = {0, 0};
        //调用方法，生成迷宫
        char[][] maze =new char[y][x];
        tools.newMaze(maze.length, maze[0].length, maze, hard);
        //调用方法，展示迷宫
        tools.showMaze(maze);

        //提示用户开始游戏
        System.out.println("\n召唤一个探索者，来探索迷宫吧（随便输点什么吧）");
        //输入 r 或 c 则采用递归方法，其余采用爬墙方法
        char inC = inP.next().charAt(0);
        if(inC == 'c'){
            System.out.println("\n您触发了迷宫之神的眷顾。");
            if(hard > 5){
            	System.out.println("\n迷宫之神眉头一皱，发现事情并不简单。");
            }
            if(x > 12 || y > 12){
                System.out.println("看到地图这么大，迷宫之神悻悻而归。他只喜欢12格以下的地图。");
                return;
            }
        } else if(inC == 'r'){
            System.out.println("\n您引来了一群无畏小黄鸡。他们视死如归，一心想着寻找出口");
        } else {
            System.out.println("\n我们找来了一只小蜘蛛。试试看吧。");
        }
        System.out.println("\n");
        //调用方法，解密
        if(inC == 'r' || inC == 'c'){
            tools.outMazeRec(maze, inC, count);
        } else {
            tools.outMaze(maze, count);
        }

    }
}





class T{
    //=======================================================================================

    //方法 newMaze：让 n3 生成随机的 长 * 宽 = n1 * n2 的迷宫，其困难度为 n4
    public void newMaze(int n1, int n2, char[][] n3, int n4){
        //构建迷宫墙壁，以'#'表示。并随机向其中填充石块，以'O'表示
        ////墙壁是迷宫的 开头和结尾行 以及 每行的开头和结尾
        for(int i = 0; i < n1; i++){
            for(int j = 0; j < n2; j++){
                if(i == 0 || i == n1 - 1 ||j == 0 || j == n2 - 1){
                    n3[i][j] = '#';
                }else{
                    //ran 是一个随机值，此处是概率生成挡路的石块'O'。其概率与 n4 值的大小正相关
                    //此外，若 n4（即用户输入的难度值 hard）超过范围，则按照 难度6 计算
                    int ran;
                    if(n4 <= 9 && n4 >= 0){
                        ran = (int)(Math.random() * (9 - n4) + 1);
                    }else{
                        ran = (int)(Math.random() * 3 + 1);
                    }
                    n3[i][j] = (ran == 1) ? 'O' : ' ';
                }
            }
        }
        //生成起点、终点，优化地形
        n3[1][1] = 'B';
        n3[2][1] = ' ';
        n3[1][2] = ' ';
        n3[n1 - 2][n2 - 2] = 'F';
        n3[n1 - 3][n2 - 2] = ' ';
        n3[n1 - 2][n2 - 3] = ' ';
    }





    //方法 showMaze：展示一个迷宫
    public void showMaze(char[][] n1){
        for(int i = 0; i < n1.length; i++){
            for(int j = 0; j < n1[i].length; j++){
                System.out.print(" " + n1[i][j]);
            }
            System.out.println();
        }
    }
    //=======================================================================================






    //=======================================================================================
    //方法 outMazeRec：递归方法迷宫游戏入口。可以接入普通递归方法，或最短路径方法。
    public void outMazeRec(char[][] n1, char n2, int[] count){
        //out：是否走出迷宫
        boolean out = false;
        //将迷宫的起止位置记为通路
        n1[1][1] = ' ';
        n1[n1.length - 2][n1[0].length -2] = ' ';
        //如果输入的是'c'，则采用最短路径法。反之采用普通递归方法
        if(n2 == 'c'){
            out = outCountMaze(1, 1, n1, count);
        }else{
            out = outMazeRecursion(1, 1, n1, count);
        }
        //把迷宫起始位置重新标注出来
        n1[1][1] = 'B';
        //判断是否解谜成功。如果成功，迷宫终点显示'V'，并展示步数，否则显示'F'
        if(out){
            n1[n1.length - 2][n1[0].length -2] = 'V';
            showMaze(n1);
            System.out.println("\t YOU WIN！！！");
            System.out.println("通过路径为 " + count[1] + " 格");
        } else {
            n1[n1.length - 2][n1[0].length -2] = 'F';
            showMaze(n1);
            System.out.println("\t YOU LOSE");
        }

    }
    //=======================================================================================




    //=======================================================================================
    //方法 outMazeRecursion：迷宫游戏，普通递归方法
    public boolean outMazeRecursion(int y, int x, char[][] n3, int[] count){
        count[1]++;
        if(n3[n3.length - 2][n3[0].length - 2] == '.'){
            return true;
        } else if(n3[y][x] == ' '){
            n3[y][x] = '.';
            if(outMazeRecursion(y, x + 1, n3, count)){
                return true;
            } else if(outMazeRecursion(y + 1, x, n3, count)){
                return true;
            } else if(outMazeRecursion(y, x - 1, n3, count)){
                return true;
            } else if(outMazeRecursion(y - 1, x, n3, count)){
                return true;
            } else{
                count[1]--;
                n3[y][x] = '+';
            }
        } else {
            count[1]--;
            return false;
        }
        count[1]--;
        return false;
    }
    //=======================================================================================






    //=======================================================================================
    //方法 outCountMaze：迷宫游戏，最短路径法的入口。这个入口由普通递归法接入。
    public boolean outCountMaze(int y, int x, char[][] n, int[] count){

        //首先，创建一个里数组。该数组用于 part1，原数组用于 part2。
        //似乎没必要作此设计。但我还是予以保留。
        char[][] inMaze = new char[n.length][n[0].length];
        for(int i = 0; i < n.length; i++){
            for(int j = 0; j < n[0].length; j++){
                inMaze[i][j] = n[i][j];
            }
        }

        //首先进行 part1，然后必定进行 part2。因为 part1 总会返回一个 false
        if(countMazeRec(y, x, inMaze, count) || true){
            count[0] = 0;
            return outMazeRecC(y, x, n, count);
        }
        return false;
    }


    //方法 countMazeRec：迷宫游戏，最短路径法，part1
    //该方法是先统计最短路径。最终总会返回 false
    public boolean countMazeRec(int y, int x, char[][] n3, int[] count){
        count[0]++;
        if(y == n3.length - 2 && x == n3[0].length - 2){
            if(count[0] < count[1] || count[1] == 0){
                count[1] = count[0];
            }
        } else if(n3[y][x] == ' '){
            n3[y][x] = '.';
            if(countMazeRec(y, x + 1, n3, count)){
                return true;
            } else if(countMazeRec(y + 1, x, n3, count)){
                return true;
            } else if(countMazeRec(y, x - 1, n3, count)){
                return true;
            } else if(countMazeRec(y - 1, x, n3, count)){
                return true;
            } else{
                n3[y][x] = ' ';
                count[0]--;
                return false;
            }
        } else {
            count[0]--;
            return false;
        }
        count[0]--;
        return false;
    }






    //方法 outMazeRecC：迷宫游戏，最短路径法，part2
    //该方法是在 part1 统计完最短路径后，按最短路径走出迷宫，并绘制路径
    public boolean outMazeRecC(int y, int x, char[][] n3, int[] count){
        count[0]++;
        if(y == n3.length - 2 && x == n3[0].length - 2){
            if(count[0] <= count[1]){
                return true;
            } else {
                n3[n3.length - 2][n3[0].length - 2] = ' ';
                count[0]--;
                return false;
            }
        } else if(n3[y][x] == ' '){
            n3[y][x] = '.';
            if(outMazeRecC(y, x + 1, n3, count)){
                return true;
            } else if(outMazeRecC(y + 1, x, n3, count)){
                return true;
            } else if(outMazeRecC(y, x - 1, n3, count)){
                return true;
            } else if(outMazeRecC(y - 1, x, n3, count)){
                return true;
            } else{
                n3[y][x] = ' ';
                count[0]--;
                return false;
            }
        } else {
            count[0]--;
            return false;
        }

    }
    //=======================================================================================






    //=======================================================================================
    //方法 outMaze：爬墙方法迷宫游戏入口
    public void outMaze(char[][] n1, int[] count){
        //boolean out：记录是否走出迷宫
        boolean out = false;
        //角色光标 m
        n1[1][1] = 'm';

        //创建一系列变量，后面解释用法
        //创建 角色坐标
        int x = 1;
        int y = 1;
        //创建 辅助坐标 及 方向字符。初始方向为右。
        int xi = 1;
        int yi = 0;
        char dir = 'r';
        //创建 里迷宫，标记起止点。
        char[][] inMaze = new char[n1.length][n1[0].length];
        inMaze[1][1] = 'B';
        inMaze[n1.length - 2][n1[0].length - 2] = 'F';

        //开始走迷宫。
        //如果一个迷宫有出路，则沿着一侧的墙壁走就一定能走到出路。以下方法就是基于这个原理。
        //角色坐标 y,x 是角色所在的位置坐标。辅助坐标 yi，xi 是角色靠近的墙壁坐标。
        //dir 代表角色此时的朝向。只要角色按照墙壁延申的方向向前，就一定不会迷路。
        //里迷宫的大小和真迷宫相同，坐标也一一对应。目的是为了记录数据，这些数据不会被用户看到。
        //里迷宫记载了 起始点 和 终点 的位置。如角色回到起点，则必定失败。到达终点则成功。
        for(;;){

            //判断 是否走出迷宫。如若是，则展示迷宫，记录脱出为真，并退出寻路
            if(inMaze[y][x] == 'F'){
                n1[y][x] = 'V';
                n1[1][1] = 'B';
                showMaze(n1);
                out = true;
                break;
            }

            //通过爬墙方式试图走出迷宫
            //这是方向朝右时的情况
            if(dir == 'r'){
                //如果角色面对墙壁，意味着走到了墙角，则角色坐标不变，调整墙壁坐标，并转向
                if(n1[y][x + 1] == '#' || n1[y][x + 1] == 'O'){
                    dir = yi > y ? 'u' : 'd';
                    yi = y;
                    xi = x + 1;
                //如果面前有路，且墙壁延伸，则前进
                } else if (n1[yi][xi + 1] == '#' || n1[yi][xi + 1] == 'O'){
                    n1[y][x] = '.';
                    x++;
                    xi++;
                    n1[y][x] = 'm';
                    count[1]++;
                //如果面前有路，但墙壁不延伸，则是遇到了转角。角色移动，转向，但墙壁坐标不变
                } else {
                    dir = yi > y ? 'd' : 'u';
                    n1[y][x] = '.';
                    n1[y][x + 1] = '.';
                    y = yi;
                    x = xi + 1;
                    n1[y][x] = 'm';
                    count[1] += 2;
                }
            //这是方向朝左的情况
            } else if(dir == 'l'){
                if(n1[y][x - 1] == '#' || n1[y][x - 1] == 'O'){
                    dir = yi > y ? 'u' : 'd';
                    yi = y;
                    xi = x - 1;
                } else if(n1[yi][xi - 1] == '#' || n1[yi][xi - 1] == 'O'){
                    n1[y][x] = '.';
                    x--;
                    xi--;
                    n1[y][x] = 'm';
                    count[1]++;
                } else {
                    dir = yi > y ? 'd' : 'u';
                    n1[y][x] = '.';
                    n1[y][x - 1] = '.';
                    y = yi;
                    x = xi - 1;
                    n1[y][x] = 'm';
                    count[1] += 2;
                }
            //这是方向朝下的情况
            } else if(dir == 'd'){
                if(n1[y + 1][x] == '#' || n1[y + 1][x] == 'O'){
                    dir = xi < x ? 'r' : 'l';
                    yi = y + 1;
                    xi = x;
                } else if(n1[yi + 1][xi] == '#' || n1[yi + 1][xi] == 'O'){
                    n1[y][x] = '.';
                    y++;
                    yi++;
                    n1[y][x] = 'm';
                    count[1]++;
                } else {
                    dir = xi < x ? 'l' : 'r';
                    n1[y][x] = '.';
                    n1[y + 1][x] = '.';
                    y = yi + 1;
                    x = xi;
                    n1[y][x] = 'm';
                    count[1] += 2;
                }
            //这是方向朝上的情况
            } else if(dir == 'u'){
                if(n1[y - 1][x] == '#' || n1[y - 1][x] == 'O'){
                    dir = xi < x ? 'r' : 'l';
                    yi = y - 1;
                    xi = x;
                } else if(n1[yi - 1][xi] == '#' || n1[yi - 1][xi] == 'O'){
                    n1[y][x] = '.';
                    y--;
                    yi--;
                    n1[y][x] = 'm';
                    count[1]++;
                } else {
                    dir = xi < x ? 'l' : 'r';
                    n1[y][x] = '.';
                    n1[y - 1][x] = '.';
                    y = yi - 1;
                    x = xi;
                    n1[y][x] = 'm';
                    count[1] += 2;
                }
            }

            //判断 是否回到起点。如若是，则一定是迷宫无解。展示迷宫并退出寻路
            if(inMaze[y][x] == 'B'){
                showMaze(n1);
                break;
            }
        }
        //输出结果
        if(out){
            System.out.println("\t YOU WIN！！！\n\t您的步数为：" + count[1]);
        } else {
            System.out.println("\t YOU LOSE");
        }
    }
}
```

### 八皇后代码

```java
import java.util.Scanner;
public class EightQueen{

    public static void main(String[] args){
        T tools = new T();
        char[][] chess = new char[8][8];
        //调用方法，建立棋盘
        tools.buildChess(chess);
        //调用方法，开始游戏
        tools.eightQueen(chess);

    }
}



class T{
    //buildChess：建立一个新棋盘。该棋盘白色格子用' '表示，黑色格子用'#'表示
    public void buildChess(char[][] chess){
        for(int i = 0; i < chess.length; i++){
            for(int j = 0; j < chess[0].length; j++){
                chess[i][j] = ((i + j) % 2 == 0) ? ' ' : '#';
            }
        }
    }




    //eightQueen：八皇后游戏的接入口
    public void eightQueen(char[][] chess){
    	//建立 里棋盘 inward 及 计数数组 count。里棋盘用于计算问题，原棋盘输出给用户看。
    	//计数 count 使用数组，这样其数据在所有方法都能通用
        char[][] inward = new char[chess.length][chess[0].length];
        int[] count = {0} ;
        //进行游戏。因为穷举所有方法，最后返回的一定是 false。反正我们不在意。
        boolean isFinished = gameEQS(0, 0, chess, inward, count);
    }



    //gameEQS：八皇后游戏的基本方法
    //八皇后游戏方法。y 代表当前位置的纵坐标，x 是横坐标。chess 是棋盘，inward 是里棋盘，count 是计数数组
    public boolean gameEQS(int y, int x, char[][] chess, char[][] inward, int[] count){
        //当 y 超出棋盘 时，显然已经完成八皇后。
        //由于要进行穷举，此时我们计数并输出棋盘，然后返回 false 使其继续计算
        if(y == inward.length){
            count[0]++;
            System.out.println();
            gameEQS2(chess, inward, count);
            return false;
        //当 x 超出棋盘 时，显然棋盘该列已经无合法放置位置。我们返回 false
        } else if(x == inward[0].length){
            return false;
        //gameEQS1，这个方法是查看该格子是否是合法放置位置。如若是，返回 true，而且在该位置放置棋子'Q'
        //当这个位置合法，我们进入下一行，从头开始判断。
        //如果后面的判断为 false，我们就拿掉这枚棋子。如果后面判断为 true 说明我们找到了一个方法。
        //特别地，由于代码目前是穷举模式，我想我们永远不会在此输出 true
        } else if(gameEQS1(y, x, inward)){
            if(gameEQS(y + 1, 0, chess, inward, count)){
                return true;
            } else {
                inward[y][x] = ' ';
            }
        }
        //如果代码进行到这个位置，证明我们所在的格子不适合放置棋子。我们只好去看看下一格如何。
        return gameEQS(y, x + 1, chess, inward, count);
    }



    //gameEQS1：该方法是输入一个坐标，并输入里棋盘地址，在里棋盘上查看该位置是否合法
    //什么是合法的位置：就是该坐标的 同列、同行、同斜线 没有别的棋子
    //如果是合法位置，我们放置一个棋子，并返回 true
    public boolean gameEQS1(int y, int x, char[][] inward){
        for(int i = 0; i < inward.length; i++){
            for(int j = 0; j < inward[0].length; j++){
                if(j == x || i == y || i - j == y - x || i + j == y + x){
                    if(inward[i][j] == 'Q'){
                        return false;
                    }
                }
            }
        }
        inward[y][x] = 'Q';
        return true;
    }



    //gameEQS2：这个方法是把当前 里棋盘 的棋子放置到棋盘上，输出棋盘 并 输出计数。
    //在输出完成后，会清空棋盘。
    public void gameEQS2(char[][] chess, char[][] inward,int[] count){
        for(int i = 0; i < chess.length; i++){
            for(int j = 0; j < chess[0].length; j++){
                if(inward[i][j] == 'Q'){
                    chess[i][j] = 'Q';
                }
                System.out.print(" " + chess[i][j]);
            }
            System.out.println();
        }
        System.out.print("\n" + count[0] + "\n");
        buildChess(chess);
    }



    //gameEQSDebug
    //输出里棋盘。测试用。
    public void gameEQSDebug(char[][] inward){
        for(int i = 0; i < inward.length; i++){
            for(int j = 0; j < inward[0].length; j++){
                System.out.print(" " + inward[i][j]);
            }
            System.out.println();
        }
        System.out.println();
    }
}
```
