断点调试(debug)
鼠标左击行的内容即可以在指定的位置下断点
右键选择debug
案例 1
com.edu.debug_ 包 Debug01.java
看一下变量的变化情况等
package com.edu.debug_;public class Debug01 { public static void main(String[] args) { //演示逐行执行 int sum = 0; for (int i = 0; i < 5; i++) { sum =+ i; System.out.println("sum="+sum); } System.out.println("退出了for循环"); }}
设置好断点之后 ,右键debug执行 之后 ,通过点击step over 可以实现逐行执行
当我们查看别人的代码 ,如果看不懂 ,可以通过debug的方法逐行执行 F8
案例 2
看一下数组越界的异常 Debug02.java
package com.edu.debug_;public class Debug02 { public static void main(String[] args) { int[] arr = {1, 10, -1}; for (int i = 0; i <= arr.length; i++) { System.out.println(arr[i]); } System.out.println("退出 for"); }}
通过debug的调试可以清楚的看到变量的值通过循环逐行执行不断地变化
同时我们还可以将鼠标指针放到变量上面点击加号 ,查看变量的详细信息
当代码执行到这里可以看到出现了错误 : 发现了一个无效的数组范围
再次执行报错了 ,因此我们就可以发现原因是出现了超出了范围的错误
案例 3
演示如何追源码,看看 java 设计者是怎么实现的。(提高编程思想)。
小技巧:将光标放在某个变量上,可以看到最新的数据。 Debug03.java
package com.edu.debug_;import java.util.Arrays;public class Debug03 { public static void main(String[] args) { int[] arr = {1, -1, 10, -20, 100}; //我们看看 Arrays.sort 方法底层实现.->Debug Arrays.sort(arr); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + "\t"); } }}
如果想要进入sort方法中可以输入快捷键F
可以发现不但数组被排序完成 ,而且在上方的数组右边可以看到发生变化的数组元素 ,以一种特别的颜色注释显示了出来
而为什么F7没有进入这个方法 ,这个时候我们可以通过 force step into 或者 快捷键 alt+shift+F7
可以看到成功进入到了目标的源码中去了
另外一种解决方法就是通过配置的方式进行解决
点击 Setting - > Build ,Execution ,Deployment -> Debugger -> Stepping
将Do not step into the classes 中的java.* ,javax.* 取消勾选 , 其他的随意即可
接下来F7就可以成功进入其源码了
也就是说 默认情况下是不让我们进入类中去的 ,因此我们需要自己去配置
此时进入到新的方法当中我们仍然还可以通过F7来继续深入到其中的方法中去
从这里进入之后
可以看到内部的代码量十分之多 ,同时这是一个双组快排的算法
而此时光标定位到了这个代码当中去之后 ,如果我们想要回到原来的主方法的时候 ,就可以一层层的再跳转回去
即 shift+F8跳出方法
或者点击这里的step out
当我们跳转回去的时候 ,可以看到sort方法已经执行完毕了 ,同时也可以继续逐行执行
这个过程有点类似递归
案例 4
演示如何直接执行到下一个断点 F9 resume。
小技巧: 断点可以在 debug 过程中,动态的下断点
package com.edu.debug_;import java.util.Arrays;//演示执行到下一个断点,同时支持动态的下断点.public class Debug04 { public static void main(String[] args) { int[] arr = {1, -1, 10, -20, 100}; //我们看看 Arrays.sort 方法底层实现.->Debug Arrays.sort(arr); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + "\t"); } System.out.println("hello100"); System.out.println("hello200"); System.out.println("hello300"); System.out.println("hello400"); System.out.println("hello500"); System.out.println("hello600"); System.out.println("hello700"); }}
在程序执行之前下两个断点
我们如果不想看中间执行的过程 直接看下一个断点的执行内容 就可以点击F9
也就是这个位置
可以看到代码不仅跳转到了下一个断点 ,同时也将中间的循环数组也执行完毕了
而如果我们想要直接执行到hello600的位置 ,那也是可以的 ,只需要在那一行代码上面下一个断点即可
同时我们不仅可以给自己写的代码添加断点 ,同时也可以给系统的JDK源码下断点
进入到系统的双轴快排源码中去
这里通过下断点 ,直接跳转到了这一行的代码中去
这种技巧对以后的多线程开发是十分有用的 ,查看代码对应的业务逻辑就可以使用这个debug调试方法
断点调试练习
DebugExercise.java
使用断点调试的方法 ,追踪下一个对象的创建过程 ,Person[name,age,构造器...]
我们使用断点调试 ,查看动态绑定机制的如何工作
package com.edu.debug_;//debug对象创建的过程,加深对调试的理解public class DebugExercise { public static void main(String[] args) { //创建对象的流程 //1.加载Person类信息 //2.初始化 默认属性初始化 ,显式初始化 ,构造器初始化 //3.返回对象的地址 Person jack = new Person("jack",20); System.out.println(jack); }}class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }}
首先通过调试可以得出第一步加载类信息
进入到了类加载器中
即加载这个类
下一步就是进入到构造器中 ,对属性进行初始化操作
接下来执行到这个位置的时候 ,会调用到toString方法
在 String s = String.valueOf(x); 这行调用到toString方法
obj是否为空 ,否则就调用 toString
由于obj的运行类型是Person ,因此就会进入到Person的toString方法
此时s接收到了toString发过来的字符串
到这里信息就输出出来了
我们使用断点调试 ,查看动态绑定机制的如何工作
找到我们之前学习多态的时候联系的代码 ,将这个代码
step into到a.sum()上
此时由于没有找到父类的sum方法 ,因此跳转到子类当中去
由于a对象的运行类型是B因此当调用getI方法的时候 ,会根据动态绑定机制 ,调用到子类的getI方法中去