断点调试
断点调试是指在程序的某一行设置一个断点,调试时,程序运行到断点就会停住,然后可以一步步往下调试运行,调试过程中可以看到各个变量当前的值,出错的话,调试到出错的代码行即显示错误停下。此时程序员可以进行分析从而找到找个Bug
DeBug也可以帮助程序员查看java底层源代码的执行过程
重点在DeBug时,是运行状态,是以对象的运行类型来执行的。
DeBug单步执行
在IDEA集成开发环境软件中有众多快捷键来帮助程序员进行断点调试
F7:跳入
F8:单步执行 StepOver
Shift+F8:跳出
F9:执行到下一个断点(resum)
用一段代码来了解debug
public class Test01 {
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < 3; i++) {
System.out.println("i = "+i);
sum+=i;
System.out.println("sum = "+sum);
}
System.out.println("循环结束了");
}
}
如果只是运行只能看到控制台输出运行后的语句。而无法看到是怎么输出的,debug就可以看到变量的创建和一步步变化
上面是debug时的控制界面
F8:单步执行 StepOver
当点击这个按钮时,就会执行一步代码,例如点击一下就会生成变量sum,并赋值 0
当在debug时,可以看下方的debug区看变量情况,也可以看源码区,也会有变量的实时情况
DeBug异常显示
debug是用于超出bug,找出异常的,下面用数组下标越界异常,来测试看看debug会怎么显示
使用F8单步执行 StepOver
public class Test01 {
public static void main(String[] args) {
int [] a = {1,2,3};
for (int i = 0; i <= a.length; i++) {
System.out.println(a[i]);
}
}
}
可以看到上面 数组 a的空间只有3,for循环用的是i<=a.length允许i自增到3,但是数组的下标只有0/1/2.没有3所以肯定会报下标越界异常
可以看到开没有进入for循环的时候就已经提示了会有数组下标异常
继续执行i = 3 时,输出台还没有显示异常,但是debug区已经报异常了
因此可以根据报的错误信息,进行修改
使用F7step into追源码和Shift +F8 step Out退出
当debug时,遇到使用方法,如果继续用F8 step over单步执行,就会跳转到方法执行后的样子,无法看到方法执行。
因此当debug到使用某个方法时,需要使用F7 step into,进入方法内部。如果方法里面调用的是另一个方法,也可以使用step into继续进入。当不想看方法内部时 可以使用Shift +F8 step Out,推出方法,继续执行程序的下一步。
注意:直接使用F7step into时需要配置一下 (File–Settings–BuildExecutionDeployment–Debugger–Stepping)将java和javax取消勾选,否则只能使用 Alt+Shift+F7 force step into强制进入
使用一段代码加深印象
public class Test01 {
public static void main(String[] args) {
int [] arr = {-10,54,21,-1};
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
在Arrays.sort(arr);处添加断点,运行debug。
使用F7 进入方法 可以看到跳转到了另一个类的方法里
由于这个方法是调用另一个了类的方法,所以可以继续F7进入
当不想继续看了时,使用Shift+F8退出,原路返回到程序,但是不是一步到位,而是沿途返回
【main方法–F7–A类的方法–F7–B类的方法–Shift+F8–A类的方法–Shift+F8–main方法】
返回继续执行完毕 输出排序好的数组
使用F9 Resume Program 跳转到下一个断点
案例演示
public class Test01 {
public static void main(String[] args) {
int [] arr = {-10,54,21,-1};
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("100");
System.out.println("200");
System.out.println("300");
System.out.println("400");
System.out.println("500");
}
}
如图在第8行和第13行下断点,当使用debug时,首先会运行到第8行停下,我们可以使用F8一步步下去,如果不关系下面的,只想快速到某一行,就需要使用F9 Resume Program 跳转到下一个断点停下。
输出结果:
第一次断点
使用F9
可以看到已经将排序好的数组数组,而且100也输出了
- F9 Resume Program 跳转到下一个断点也可以用来判断业务逻辑,例如上面的 Arrays.sort(arr),可以在别的类中方法定一个断点,看看debug会不会执行到那去,如果执行到那去就是相关的,如果还是在原来的地方运行就是没有逻辑关系
A类运行main方法,B类的某个方法中下断点
使用debug看对象创建的过程
public class Test02 {
public static void main(String[] args) {
Person p1 = new Person("李想",22);
System.out.println(p1);
}
}
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 +
'}';
}
}
当断点在 Person p1 = new Person(“李想”,22);,时可以使用强制进入看看具体的创建过程
alt+shift+F7强制进入可以看到进入了class load(加载类)的loadClass类加载方法
再使用shift+f8退出到main方法继续
可以看到将传入的实参到构造方法赋值给对象
接着F8继续 进入到重写的toString方法,输出属性,执行完毕输出 :Person{name=‘李想’, age=22}
debug看动态绑定机制
public class Test01 {
public static void main(String[] args) {
A a = new B();
System.out.println(a.sum());
}
}
class A{
int i = 10;
public int sum(){
return get()+10;
}
public int get(){
return i;
}
}
class B extends A{
int i = 20;
public int sum(){
return get()+10;
}
public int get(){
return i;
}
}
断点打在 System.out.println(a.sum());
使用强制进入看看
可以看到由于运行类型是B,所以进入的是B类的sum方法,由由于此sum方法中调用了get方法放,又会进入到B类的get方法