一、DeBug
// 01
package com.alice.debug_;
import java.util.Scanner;
public class Debug01 {
public static void main(String[] args) {
// 1、写好一个简单的程序,如何下断点,只需要鼠标左键点击左边
// 代码序号的右边,即可出现一个红点。
// 2、在编程和调试中,breakpoint 指的是程序执行到某一行代码时暂停的位置,
// 方便开发者检查变量、调用栈等信息。
// 这里不能run,我们需要的是Debug
// run的快捷键是Ctrl + Shift + F10
// debug的快捷键是Shift + F9
// debug后会在断点处停止,不会执行该断点的代码
// 3、在Debug窗口会有一些蓝色小箭头的图标,
// Step Over是逐行执行 F8
// Step Into是进入到方法体内 F7
// Force Step Into是强制进入到方法体内 Alt + Shift + F7
// Step Out是跳出方法 Shift + F8
// Resume Program 是可以执行到下一个断点 F9
// 4、断点可以动态的下断点,我们在Debug状态的时候也可以下断点
// 再次点击断点就会取消这个断点
// 点击红色小方块就结束整个Debug Stop ‘xxx’ Ctrl + F2
Scanner scanner = new Scanner(System.in);
int sum = 0; // 使用Debug可以看到这些变量的变化
System.out.print("请输入从0加到哪个数结束:"); // 如果看到Console出现黄色向下箭头闪动说明有输出
int end = scanner.nextInt();
for (int i = 0; i < end; i++) {
sum += i;
System.out.println("第" + (i + 1) + "次的和为->" + sum);
}
System.out.println("...end程序结束end...");
// 执行到最后一行,程序结束,在Variables窗口中提示Variables are not available变量无法获得。
// 5、DeBug的好处是,我们拿到别人的代码如果看不懂就可以使用Debug来看
}
}
//02
package com.alice.debug_;
import java.util.Arrays;
import java.util.Scanner;
public class Debug02 {
public static void main(String[] args) {
// 1、数组越界异常
Scanner scanner = new Scanner(System.in);
System.out.print("请输入int数组的大小:");
int size = scanner.nextInt();
int[] arr = new int[size]; // 将鼠标放到arr上面会出现加号,可以获知arr的信息
for (int i = 0; i < arr.length; i++) { // 如果这里写成<=出现ArrayIndexOutOfBoundsException
arr[i] = (int)(Math.random() * 100 + 1); // 终端会提示哪一行出现异常,点击蓝色字体跳转到这行提示
}
System.out.println("当前的int数组为--> " + Arrays.toString(arr));
System.out.println("程序结束...");
}
}
//03
package com.alice.debug_;
import java.util.Arrays;
import java.util.Scanner;
public class Debug03 {
public static void main(String[] args) {
// 1、创建一个数组,然后使用Arrays.sort()方法排序,想看源码怎么排序的
Scanner scanner = new Scanner(System.in);
System.out.print("请输入随机生成一维数组的大小:");
int size = scanner.nextInt();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * 100 + 1);
}
System.out.println("得到的随机数组------------>" + Arrays.toString(arr));
Arrays.sort(arr); // F7可以跳进方法,但是我们会发现数组已经排好了
// 那么为什么没有进去?
// 2、我们可以使用F7旁边的一个红色的向下箭头可以强制跳进去
// force强制
// 3、第二种方式是通过配置的方式(推荐)
// 点击Setting->Build,Execution,Deployment->Debugger->Stepping将Do not step into the
// classes中的java.*,javax.*取消勾选即可。然后再重新使用F7尝试发现成功,这里老韩也提供了一个文档
// 由于进入到Arrays.sort()还有一个调用,我们还需要F7追踪
// 真正帮助我们完成排序的是这个DualPivotQuicksort.sort,还可以继续追,这里还有一个sort(a,left,right,true);
// Sorts the specified range of the array by Dual-Pivot Quicksort.可以看到使用的算法 快排,后面讲解
// 可以看到源码非常复杂
// 目前我们已经追踪到真正的sort排序方法
// 已经知道是快排然后我们想要回到主方法只需要跳出Shift + F8
System.out.println("Arrays.sort()排序后的数组->" + Arrays.toString(arr));
}
}
//04
package com.alice.debug_;
import java.util.Arrays;
import java.util.Scanner;
public class Debug04 {
public static void main(String[] args) {
// 快速执行到下一个断点F9,且断点可以在Debug的过程中,动态的下断点
// 创建一个数组并且排序
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数组的大小:");
int size = scanner.nextInt();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 100 + 1);
}
System.out.println("原数组->" + Arrays.toString(arr));
Arrays.sort(arr); // 断点1 F9直接执行到下一个断点为止
System.out.println("现数组->" + Arrays.toString(arr));
// 很多的打印语句
System.out.println("ok100");
System.out.println("ok200");
System.out.println("ok300");
System.out.println("ok400");
System.out.println("ok500");
System.out.println("ok600");
System.out.println("ok700"); // 断点2 ,F9到下一个动态下的断点
System.out.println("ok800");
System.out.println("ok900"); // 动态下一个断点3
// 同理下断点可以在自己的代码,java本身的代码都可以下断点
// tip,下的断点不一定会到这个断点位置停止,因为前面如果有一些逻辑判断不通过可能走不到这个断点,
// 即,需要看代码本身的业务逻辑,断点需要结合业务逻辑
// 应用场景:多线程,判断业务逻辑
}
}
//05
package com.alice.debug_;
public class Debug05 {
public static void main(String[] args) {
// 1、课后练习题一
// 使用断点调试的方法,追踪到下一个对象创建的过程。Person[name,age,构造器...]
Person alice = new Person("alice", 18);
// 创建对象的流程
// 1)加载Person类信息
/*
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
} 将Person类信息加载
*/
// 2)初始化 1默认初始化 2显式初始化 3构造器初始化 第二次强制进入直接进入到构造器初始化,前面两部看不到
// 3)返回对象地址
System.out.println(alice); // 直接运行run看不到创建对象的过程,我们想要看到过程,在创建对象这行代码下断点
/*
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
追
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
追
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
*/
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) { // 开始直接F7进入到的是这里,我们想要直接到底层的可以强制进入
this.name = name; // 当前name是空,当执行完该语句之后为alice
this.age = age; // 当前age为0,当执行完成后为18
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//06
package com.alice.debug_;
public class Debug06 {
public static void main(String[] args) {
// 动态绑定机制
A a = new B();
System.out.println(a.sum()); // 调用方法看运行类型,当前运行类型是B,结果30
System.out.println(a.sum1()); // 同理,但是属性看当前的,结果20
}
}
class A {
public int i = 10;
public int sum() { // getI()看运行类型B的
return getI() + 10; // 20 + 10 = 30
}
public int sum1() { // A有sum1,i看编译类型A的,返回10 + 10 = 20
return i + 10; // 看当前10
}
public int getI() {
return i;
}
}
class B extends A{ // B中没有sum,但是继承了A类的sum掉A的
public int i = 20;
public int getI() { // B有,返回20
return i; // 属性看当前20
}
}
二、零钱通项目
// 面向过程版
package com.alice.smallchange;
import java.util.Scanner;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class SmallChangeSys {
public static void main(String[] args) {
// 1、菜单界面
// 2、零钱通明细
// 1)可以将收益入账和消费保存到数组
// 2)可以使用对象
// 3)可以使用String拼接 details
// 3、收益入账
/* 获取当前时间
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// 获取当前时间
LocalDateTime now = LocalDateTime.now();
// 定义格式(年月日 小时分钟)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");
// 格式化时间
String formattedTime = now.format(formatter);
System.out.println("当前时间: " + formattedTime);
}
}
字符串+=性能优化
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("some string");
}
String result = sb.toString();
*/
// 4、消费
// 定义新变量,保存消费的原因
// 5、退出
/*
改进
一、用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
关于这一段代码,老韩给出建议:
//老韩建议的代码,以后添加另外的符号,易于扩展,将代码细化,一块代码完成一件事情。
if("y".equals(choice) || "n".equals(choice)) { // 判断输入
break;
}
if(choice.equals("y")) { // 结束程序
loop = false;
}
//不推荐的写法
if("y".equals(choice)) { // 代码混在一起
loop = false;
break;
} else if ("n".equals(choice)) {
break;
}
二、在收益入账和消费的时候,判断金额是否合理,并给出相应的提示。
技巧:找不不正确金额的条件,然后给出提示即可,然后就不要执行下面的代码,直接break;
生活中:我们要做一件事情的时候一路跟过关斩将,如果遇到某一关不过我们打道回府,如果都通过了就ok;
if(money <= 0) {
System.out.println("收益入账金额需要大于0");
break;
}
if(money <= 0 || money > balance) {
System.out.println("你的消费金额应该在0-"+balance);
}
这样的代码更加简洁,且易于扩展。
以后还需要过关斩将的时候直接继续在后面写if。
if(){}
三、将面向规程的代码修改为面向对象的方法,编写SmallChangeSysOOP.java类,并使用SmallChangeSysApp.java完成测试
*/
Scanner scanner = new Scanner(System.in);
boolean noEnd = true;
String menuChoice = " ";
String leftAndRightLineOfMenu = "-----------------";
String leftBlankOfMenu = " ";
String titleOfMenu = "零钱通菜单";
String titleOfDetails = "零钱通明细";
String titleOfBreak = "退出零钱通";
// String details = ""; // StringBuilder sb = new StringBuilder();
StringBuilder details = new StringBuilder();
String detailsToString = "";
double balance = 0.0;
String[] menu = {"零钱通明细", "收益入账", "消费", "退 出"};
int lengthOfMenu = menu.length;
String formattedTime = "";
do {
System.out.println(leftAndRightLineOfMenu + titleOfMenu + leftAndRightLineOfMenu);
for (int i = 0; i < lengthOfMenu; i++) {
System.out.println(leftBlankOfMenu + (i + 1) + " " + menu[i]);
}
System.out.print("请选择(1-" + lengthOfMenu + "):");
menuChoice = scanner.next();
switch (menuChoice) {
case "1":
System.out.println(leftAndRightLineOfMenu + titleOfDetails +
leftAndRightLineOfMenu + detailsToString);
break;
case "2":
System.out.print("收益入账多少钱:");
double incomePosted = scanner.nextDouble();
if (incomePosted <= 0) {
System.out.println("收益的钱不能<=0!");
break;
}
balance += incomePosted;
// 格式化时间
formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
String itemIncomePosted = "\n" + "收益入账" + "\t +" + incomePosted + formattedTime +
"\t余额:" + balance;
details.append(itemIncomePosted); // 字符串+=性能问题
detailsToString = details.toString();
break;
case "3":
System.out.print("消费原因或地点:");
String spendingReason = scanner.next();
System.out.print("消费花销:");
double expense = scanner.nextDouble();
if (expense <= 0 || expense > balance) {
System.out.println("消费金额不能<=0元或者大于余额!");
break;
}
formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
balance -= expense;
String itemExpense = "\n" + spendingReason + "\t -" + expense + formattedTime +
"\t余额:" + balance;
details.append(itemExpense); // 字符串+=性能问题
detailsToString = details.toString();
break;
case "4":
// 用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
String yesOrNo = "";
boolean breakNow = false;
while (!breakNow) { // 无限循环危险结构警告,推荐使用显式循环条件
System.out.print("你确定要退出吗?y/n:");
yesOrNo = scanner.next();
if ("y".equals(yesOrNo) || "n".equals(yesOrNo)) {
breakNow = true;
}
}
if ("y".equals(yesOrNo)) {
noEnd = false;
break;
}
break;
default:
System.out.println("请正确输入");
}
} while (noEnd);
System.out.println(leftAndRightLineOfMenu + titleOfBreak + leftAndRightLineOfMenu);
}
}
// 面向对象版
package com.alice.smallchange.oop;
import java.util.Scanner;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class SmallChangeSysOOP {
Scanner scanner = new Scanner(System.in);
boolean noEnd = true;
String menuChoice = " ";
String leftAndRightLineOfMenu = "-----------------";
String leftBlankOfMenu = " ";
String titleOfMenu = "零钱通菜单";
String titleOfDetails = "零钱通明细";
String titleOfBreak = "退出零钱通";
// String details = ""; // StringBuilder sb = new StringBuilder();
StringBuilder details = new StringBuilder();
String detailsToString = "";
double balance = 0.0;
String[] menu = {"零钱通明细", "收益入账", "消费", "退 出"};
int lengthOfMenu = menu.length;
String formattedTime = "";
public void printMenu() {
System.out.println(leftAndRightLineOfMenu + titleOfMenu + leftAndRightLineOfMenu);
for (int i = 0; i < lengthOfMenu; i++) {
System.out.println(leftBlankOfMenu + (i + 1) + " " + menu[i]);
}
System.out.print("请选择(1-" + lengthOfMenu + "):");
menuChoice = scanner.next();
}
public void printDetails() {
System.out.println(leftAndRightLineOfMenu + titleOfDetails +
leftAndRightLineOfMenu + detailsToString);
}
public void printIncomePosted() {
System.out.print("收益入账多少钱:");
double incomePosted = scanner.nextDouble();
if (incomePosted <= 0) {
System.out.println("收益的钱不能<=0!");
return;
}
balance += incomePosted;
// 格式化时间
formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
String itemIncomePosted = "\n" + "收益入账" + "\t +" + incomePosted + formattedTime +
"\t余额:" + balance;
details.append(itemIncomePosted); // 字符串+=性能问题
detailsToString = details.toString();
}
public void printExpense() {
System.out.print("消费原因或地点:");
String spendingReason = scanner.next();
System.out.print("消费花销:");
double expense = scanner.nextDouble();
if (expense <= 0 || expense > balance) {
System.out.println("消费金额不能<=0元或者大于余额!");
return;
}
formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
balance -= expense;
String itemExpense = "\n" + spendingReason + "\t -" + expense + formattedTime +
"\t余额:" + balance;
details.append(itemExpense); // 字符串+=性能问题
detailsToString = details.toString();
}
public void breakApp() {
// 用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
String yesOrNo = "";
boolean breakNow = false;
while (!breakNow) { // 无限循环危险结构警告,推荐使用显式循环条件
System.out.print("你确定要退出吗?y/n:");
yesOrNo = scanner.next();
if ("y".equals(yesOrNo) || "n".equals(yesOrNo)) {
breakNow = true;
}
}
if ("y".equals(yesOrNo)) {
noEnd = false;
return;
}
}
public void runMain() {
do {
this.printMenu();
switch (menuChoice) {
case "1":
this.printDetails();
break;
case "2":
this.printIncomePosted();
break;
case "3":
this.printExpense();
break;
case "4":
this.breakApp();
break;
default:
System.out.println("请正确输入");
}
} while (noEnd);
System.out.println(leftAndRightLineOfMenu + titleOfBreak + leftAndRightLineOfMenu);
}
}
main
package com.alice.smallchange.oop;
public class SmallChangeSysApp {
public static void main(String[] args) {
new SmallChangeSysOOP().runMain();
}
}