目录
8.11.5 多态注意事项和细节讨论(instanceof重要)
08 面向对象编程(中级部分)
8.1 IDE(集成开发环境)-IDEA
8.1.1IDEA 介绍
-
IDEA 全称 IntelliJ IDEA
-
在业界被公认为最好的 Java 开发工具
-
IDEA 是 JetBrains 公司的产品,总部位于捷克的首都布拉格
-
除了支持 Java 开发,还支持 HTML,CSS,PHP,MySQL,Python 等
8.2 IDE(集成开发环境)-Eclipse
8.2.1Eclipse 介绍
-
Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。
-
最初是由 IBM 公司耗资 3000 万美金开发的下一代 IDE 开发环境
-
2001 年 11 月贡献给开源社区
-
Eclipse 是目前最优秀的 Java 开发 IDE 之一
8.3 IDE(集成开发环境)-IDEA 的使用
8.3.1IDEA 的安装
-
官网: JetBrains: Essential tools for software developers and teams
-
IDEA 下载后,就可以开始安装。
-
看老师给同学们演示如何安装
-
IDEA 工作界面介绍
8.3.2IDEA 的基本介绍和使用
使用 IDEA 创建 Java 项目(project),看看 IDEA 是如何使用的,IDEA 是以项目的概念,来管理我们的 java 源码的
-
创建一个 java 项目 - hello
-
5min 练习一下
public class Hello {
public static void main(String[] args){
System.out.println("Hello,idea");
}
}
8.3.3IDEA 使用技巧和经验
✓ 设置字体 [如图] 和 颜色主题
菜单 file -> settings
✓ 字符编码设置
8.3.4课堂练习
使用 IDEA 开发一个 java 项目 testpro01,创建一个类 MyTools, 编写一个方法,可以完成对 int 数组冒泡排序的功能 学员练习 , 使用快捷键的开发项目
8.3.5IDEA 常用快捷键
-
删除当前行, 默认是 ctrl + Y 自己配置 ctrl + d
-
复制当前行, 自己配置 ctrl + alt + 向下光标
-
补全代码 alt + /
-
添加注释和取消注释 ctrl + / 【第一次是添加注释,第二次是取消注释】
-
导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可
-
快速格式化代码 ctrl + alt + L
-
快速运行程序 自己定义 alt + R
-
生成构造器等 alt + insert [提高开发效率]
-
查看一个类的层级关系 ctrl + H [学习继承后,非常有用]
-
将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]
-
自动的分配变量名 , 通过 在后面假 .var [老师最喜欢的]
-
还有很多其它的快捷键...
8.3.6模板/自定义模板
//sout模板快捷键
System.out.println();
//fori模板
for (int i = 0; i < ; i++) {
}
8.4 包
8.4.1看一个应用场景
8.4.2包的三大作用
8.4.3包基本语法
8.4.4包的本质分析(原理)
8.4.5快速入门
8.4.6包的命名
8.4.7常用的包
8.4.8如何引入包
package com.hspedu.pkg;
import java.util.Arrays;
//注意:
//老师建议:我们需要使用到哪个类,就导入哪个类即可,不建议 *导入
//import java.util.Scanner;//表示只会引入java.util 包下的Scanner
//import java.util.*;//表示将ava.util 包下的所有类都引入(导入)
public class Import01 {
public static void main(String[] args) {
//使用系统提供 Arrays 完成 数组排序
int[] arr = {-1,20,2,13,3};
//比如对其进行排序
//传统方法是,自己编写排序(冒泡)
//系统是提供了相关的类,可以方便完成 Arrays
Arrays.sort(arr);
//输出排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
8.4.9注意事项和使用细节
//package的作用是声名当前类所在的包,需要放在类(或者文件的最上面)的最上面,
// 一个类中最多只有一句package
package com.hspedu.pkg;
//import指令 位置放在package的下面,在类定义面前,可以有多聚且没有顺序要求
import java.util.Arrays;
import java.util.Scanner;
//arr
//类定义
public class PkgDetail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] arr = {0,-1};
Arrays.sort(arr);
}
}
8.5 访问修饰符
8.5.1基本介绍
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
-
公开级别:用 public 修饰,对外公开
-
受保护级别:用 protected 修饰,对子类和同一个包中的类公开
-
默认级别:没有修饰符号,向同一个包的类公开.
-
私有级别:用 private 修饰,只有类本身可以访问,不对外公开.
8.5.24 种访问修饰符的访问范围(背下来)
8.5.3使用的注意事项
package com.hspedu.modifier;
public class A {
//四个属性,分别使用不同的访问修饰符来修饰
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public void m1(){
//在同一类中,可以访问public protected 默认 private 修饰属性和方法
System.out.println("n1=" + n1 + " n2=" + n2 + " n3=" + n3 + " n4=" + n4);
}
protected void m2(){ }
void m3(){ }
private void m4(){ }
public void hi(){
//在同一类中,可以访问public protected 默认 private 修饰属性和方法
m1();
m2();
m3();
m4();
}
}
package com.hspedu.modifier;
public class B {
public void say(){
A a = new A();
//在同一个包下,可以访问public ,protected 和 默认,不能访问private 属性或方法
System.out.println("n1=" + a.n1 + " " + a.n2 + " " + a.n3);
a.m1();
a.m2();
a.m3();
//a.m4();错误的
}
}
package com.hspedu.modifier;
public class Test {
public static void main(String[] args) {
A a = new A();
a.m1();
B b = new B();
b.say();
}
}
//只有 默认和public 可以修饰类
class Tiger{ }
8.6 面向对象编程三大特征
8.6.1基本介绍
面向对象编程有三大特征:封装、继承和多态。
8.6.2封装介绍
8.6.3封装的理解和好处
8.6.4封装的实现步骤 (三步)
8.7 快速入门案例
✓ 看一个案例
package com.hspedu.encap;
public class Encapsulation01 {
public static void main(String[] args) {
//如果要使用快捷键 alt+r, 需要先配置主类
//第一次,我们使用鼠标点击形式运算程序,后面就可以用
Person person = new Person();
person.setName("Jack");
person.setAge(30);
person.setSalary(30000);
System.out.println(person.info());
System.out.println(person.getSalary());
//如果我们使用构造器指定属性
Person smith = new Person("Smitth",2000,5000);
System.out.println("====smith的信息====");
System.out.println(smith.info());
}
}
/*
那么在 java 中如何实现这种类似的控制呢?
请大家看一个小程序(com.hspedu.encap: Encapsulation01.java), 不能随便查看人的年龄,工资等隐私,
并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 1-120, 年龄, 工资不能直接查看 , name 的长度在 2-6 字符 之间
*/
class Person {
public String name;//名字公开
private int age;//age 私有化
private double salary;//薪水私有化
public void say(int n,String name){
}
//构造器 alt+insert
public Person() {
}
//有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将set方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
//自己写 setXxx 和 getXxx 太慢,我们使用快捷键
//然后根据要求来完善我们的代码.
public String getName() {
return name;
}
public void setName(String name) {
//加入对数据的校验,相当于增加了业务逻辑
if(name.length() >= 2 && name.length() <= 6) {
this.name = name;
}else{
System.out.println("名字的长度不对,需要(2-6)个字符,默认名字");
this.name = "无名人";
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
//判断
if(age >= 1 && age <= 120) {
this.age = age;
}else{
System.out.println("你设置年龄不对,需要在 (1-120), 给默认年龄 18");
this.age = 18;//给一个默认年龄
}
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写一个方法,返回属性信息
public String info(){
return "信息为 name=" + name + " age=" + age + " 薪水=" + salary;
}
}
8.7.1将构造器和 setXxx 结合
看一个案例
//有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将set方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
8.7.2课堂练习
package com.hspedu.encap;
/**
* 创建程序,在其中定义两个类:Account 和 AccountTest 类体会 Java 的封装性。
* Account 类要求具有属性:姓名(长度为 2 位 3 位或 4 位)、余额(必须>20)、
* 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
* 通过 setXxx 的方法给 Account 的属性赋值。
* 在 AccountTest 中测试
*/
public class Account {
//为了封装,将三个属性设置为private
private String name;
private double balance;
private String pwd;
//提供两种构造器
public Account() {
//设置无参构造器是因为写了有参构造器,覆盖了默认无参构造器,现在显性无参构造器
}
public Account(String name, double balance, String pwd) {
setName(name);
setBalance(balance);
setPwd(pwd);
}
public String getName() {
return name;
}
//姓名(长度为 2 位 3 位或 4 位)
public void setName(String name) {
if(name.length() > 1 && name.length() < 5) {
this.name = name;
}else{
System.out.println("名字的长度不对,需要(2-4)个字符,默认名字");
this.name = "无名人";
}
}
public double getBalance() {
return balance;
}
//余额(必须>20)
public void setBalance(double balance) {
if(balance > 20) {
this.balance = balance;
}else{
System.out.println("账户余额错误,需要大于20,默认余额");
this.balance = 20;
}
}
public String getPwd() {
return pwd;
}
//密码(必须是六位)
public void setPwd(String pwd) {
if(pwd.length() == 6) {
this.pwd = pwd;
}else{
System.out.println("密码长度有误,需要6位,默认密码");
this.pwd = "000000";
}
}
//写一个方法,返回属性信息
public String info() {
//可以增加权限的校验
return "姓名为" + name + " 余额=" + balance + " 密码=" +pwd;
}
}
package com.hspedu.encap;
public class AccountTest {
public static void main(String[] args) {
Account smith = new Account("李华", 96000, "000000");
System.out.println(smith.info());
}
}
8.8 面向对象编程-继承
8.8.1为什么需要继承
8.8.2继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。画出继承的示意图
8.8.3继承的基本语法
8.8.4快速入门案例
我们对 Extends01.java 改进,使用继承的方法,请大家注意体会使用继承的好处
package com.hspedu.extend;
public class Extends01 {
//编写一个main方法
public static void main(String[] args) {
Pupil pupil = new Pupil();
pupil.name = "银角大王";
pupil.age = 10;
pupil.testing();
pupil.setScore(60);
pupil.shouInfo();
System.out.println("==========");
Graduate graduate = new Graduate();
graduate.name = "金角大王";
graduate.age = 22;
graduate.testing();
graduate.setScore(100);
graduate.shouInfo();
}
}
package com.hspedu.extend.improve_;
//父类,是Pupil 和Graduate的父类
public class Student {
//共有属性
public String name;
public int age;
private double score;
public void setScore(double score) {
this.score = score;
}
//共有方法
public void shouInfo(){
System.out.println("学生名 " + name + " 年龄" + age + " 成绩" + score);
}
}
package com.hspedu.extend.improve_;
//让Pupil 继承 Student类
public class Pupil extends Student{
public void testing(){
System.out.println("大学生" + name + " 正在考大学数学。。");
}
}
package com.hspedu.extend.improve_;
public class Graduate extends Student{
public void testing(){
System.out.println("大学生" + name + " 正在考大学数学。。");
}
}
8.8.5继承给编程带来的便利
-
代码的复用性提高了
-
代码的扩展性和维护性提高了
8.8.6继承的深入讨论/细节问题
-
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
-
子类必须调用父类的构造器, 完成父类的初始化
-
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。) [举例说明]
-
如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
-
super 在使用时,必须放在构造器第一行(super() 只能在构造器中使用)
-
super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
-
java 所有类都是 Object 类的子类, Object 是所有类的基类.
-
父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
-
子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。 思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
-
不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
package com.hspedu.extend;
import com.hspedu.extend.improve_.Sub;
public class ExtendsDetail {
public static void main(String[] args) {
// System.out.println("====第1个对象======");
// Sub sub = new Sub();//创建了子类对象 sub
// System.out.println("====第2个对象======");
// Sub sub2 = new Sub("jack");//创建了子类对象 sub2
System.out.println("====第3个对象======");
Sub sub3 = new Sub("king",10);//创建了子类对象 sub3
//sub.sayOk();
}
}
package com.hspedu.extend.improve_;
public class TopBase {//父类是 Object
public TopBase(){
//super(); Object 的无参构造器
System.out.println("构造器 TopBase() 被调用..");//1
}
}
package com.hspedu.extend.improve_;
public class Base extends TopBase{//父类
//4个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public Base() { //无参构造器
System.out.println("父类 Base()构造器被调用....");
}
public Base(String name, int age) {//有参构造器
//默认 super()
System.out.println("父类 Base(String name, int age)构造器被调用....");
}
public Base(String name) {//有参构造器
System.out.println("父类 Base(String name)构造器被调用....");
}
//父类提供一个 public 的方法,返回了 n4
public int getN4() {
return n4;
}
public void test100() {
System.out.println("test100");
}
protected void test200() {
System.out.println("test200");
}
void test300() {
System.out.println("test300");
}
private void test400() {
System.out.println("test400");
}
//call
public void callTest400() {
test400();
}
}
package com.hspedu.extend.improve_;
//输入ctrl + H 可以看到类的继承关系
public class Sub extends Base{//子类
public Sub(String name,int age){
//1.如若要调用父类的无参构造器,如下或者 什么都不写,默认就是调用super()
//super();//父类的无参构造器
//2.如若要调用父类的Base(String name)构造器
//super("hsp");
//2.如若要调用父类的Base(String name,int age)构造器
super("king",20);
System.out.println("子类sub(String name,int age)构造器被调用");
//super("king",20);错误,对super的调用必须是构造器中的第一个语句
}
public Sub(){//无参构造器
//super();//默认调用父类的无参构造器
super("smith",10);
System.out.println("子类sub()构造器被调用");
}
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
public Sub(String name){
super("tom",30);
//do nothing...
System.out.println("子类Sub(String name)构造器被调用");
}
public void sayOk(){//子类方法
//非私有的属性和方法可以在子类直接访问
//但私有的属性和方法不能在子类直接访问
System.out.println(n1 + " " + n2 + " " + n3);
test100();
test200();
test300();
//test400();错误
//要通过父类提供公共的方法去访问
System.out.println("n4=" + getN4());
callTest400();//
}
}
8.8.7继承的本质分析(重要)
✓ 案例
package com.hspedu.extend;
/**
* 讲解继承的本质
*/
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();//内存的布局
//?-> 这时请大家注意,要按照查找关系来返回信息
//(1)首先看子类是否有该属性
//(2)如果子类有这个属性,并且可以访问,则返回信息
//(3)如果子类没有这个属性,就看父类有没有该属性(如果父类有该属性,并且可以访问,就返回信息。。)
//(4)如果父类没有就按(3)的规则,继续找上级父类,直到Object。。。
System.out.println(son.name);//返回就是大头儿子
System.out.println(son.getAge());//返回就是39
System.out.println(son.hobby);//返回就是旅游
}
}
class GrandPa { //爷类
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {//父类
String name = "大头爸爸";
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //子类
String name = "大头儿子";
}
✓ 子类创建的内存布局
8.8.8课堂练习
-
案例 1 ExtendsExercise01.java
-
案例 2 ExtendsExercise02.java
package com.hspedu.extend.exercise; public class ExtendsExercise02 { public static void main(String[] args) { C c = new C(); } } class A {//A 类 public A() { System.out.println("我是 A 类"); } } class B extends A { //B 类,继承 A 类 //main 方法中: C c =new C(); 输出么内容? 3min public B() { System.out.println("我是 B 类的无参构造"); } public B(String name) { System.out.println(name + "我是 B 类的有参构造"); } } class C extends B { //C 类,继承 B 类 public C() { this("hello"); System.out.println("我是 c 类的无参构造"); } public C(String name) { super("hahah"); System.out.println("我是 c 类的有参构造"); } }
执行结果:
-
案例 3 ExtendsExercise03.java
编写 Computer 类,包含 CPU、内存、硬盘等属性,getDetails 方法用于返回 Computer 的详细信息
编写 PC 子类,继承 Computer 类,添加特有属性【品牌 brand】
编写 NotePad 子类,继承 Computer 类,添加特有属性【color】
编写 Test 类,在 main 方法中创建 PC 和 NotePad 对象,分别给对象中特有的属性赋值,以及从 Computer 类继承的 属性赋值,并使用方法并打印输出信息
package com.hspedu.extend.exercise;
//编写 Computer 类,包含 CPU、内存、硬盘等属性,getDetails 方法用于返回 Computer 的详细信息
public class Computer {
private String cpu;
private int memory;
private int disk;
public Computer(){//无参构造器
}
public Computer(String cpu,int memory,int disk){//有参构造器
this.cpu = cpu;
this.memory = memory;
this.disk = disk;
}
public String getDetails(){//返回 Computer 的详细信息
return "CPU is" + cpu + " 内存大小 is" + memory + " 硬盘大小 is" + disk;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
}
package com.hspedu.extend.exercise;
//编写 PC 子类,继承 Computer 类,添加特有属性【品牌 brand】
public class PC extends Computer {
private String brand;
public PC() {
}
//这里IDEA 根据继承的规则,自动把构造器的调用写好
//这里也体现:继承设计的基本思想,父类的构造器完成父类属性初始化
//子类的构造器完成子类属性初始化
public PC(String cpu, int memory, int disk, String brand) {
super(cpu, memory, disk);
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void printInfo1() {
System.out.println("PC 信息=");
// System.out.println(getCpu() + getMemory() + getDisk());
//调用父类的 getDetails 方法,得到相关属性信息..
System.out.println(getDetails() + " brand=" + brand);
}
}
package com.hspedu.extend.exercise;
public class NotePad extends Computer{
private String color;
public NotePad(){//无参构造器
}
public NotePad(String cpu, int memory, int disk, String color) {
super(cpu, memory, disk);
this.color = color;
}
public void printInfo2() {
System.out.println("NotePad 信息=");
// System.out.println(getCpu() + getMemory() + getDisk());
//调用父类的 getDetails 方法,得到相关属性信息..
System.out.println(getDetails() + " coolor=" + color);
}
}
package com.hspedu.extend.exercise;
/*
编写 Computer 类,包含 CPU、内存、硬盘等属性,getDetails 方法用于返回 Computer 的详细信息
编写 PC 子类,继承 Computer 类,添加特有属性【品牌 brand】
编写 NotePad 子类,继承 Computer 类,添加特有属性【color】//同学们自己写。
编写 Test 类,在 main 方法中创建 PC 和 NotePad 对象,分别给对象 中特有的属性赋值,
以及从 Computer 类继承的属性赋值,并使用方法并打印输出信息
*/
public class ExtendsExercise03 {
public static void main(String[] args) {
PC pc = new PC("AMD", 1024, 2048, "LEGION");
NotePad notePad = new NotePad("Inter",1024,3072,"red");
pc.printInfo1();
notePad.printInfo2();
}
}
8.9 super 关键字
8.9.1基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器
8.9.2基本语法
代码
package com.hspedu.super_;
public class Base {//父类是Object
public int n1 = 999;
public int age = 111;
public void cal(){
System.out.println("Base 类的 cal() 方法...");
}
public void eat(){
System.out.println("Base类的eat()......");
}
}
package com.hspedu.super_;
public class A extends Base {
//4 个属性
//public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public A() {
}
public A(String name) {
}
public A(String name, int age) {
}
public void cal() {
System.out.println("A 类的 cal() 方法...");
}
public void test100() {
}
protected void test200() {
}
void test300() {
}
private void test400() {
}
}
package com.hspedu.super_;
public class B extends A{
public int n1 = 888;
//编写测试方法
public void test() {
//super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用 super 去访问爷爷类的成员;
// 如果多个基类(上级类)中都有同名的成员,使用 super 访问遵循就近原则。A->B->C
System.out.println("super.n1=" + super.n1);
super.cal();
}
//访问父类的属性 , 但不能访问父类的 private 属性 [案例]super.属性名
public void hi(){
System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
}
//访问父类的方法,不能访问父类的 private 方法 super.方法名(参数列表);
public void ok(){
super.test100();
super.test200();
super.test300();
//super.test400();//不能访问父类private方法
}
public void cal() {
System.out.println("B 类的 cal() 方法...");
}
public void sum() {
System.out.println("B 类的 sum()");
//希望调用父类-A 的 cal 方法
//这时,因为子类 B 没有 cal 方法,因此我可以使用下面三种方式
//找 cal 方法时(cal() 和 this.cal()),顺序是:
// (1)先找本类,如果有,则调用
// (2)如果没有,则找父类(如果有,并可以调用,则调用)
// (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
//cal();
this.cal();//等价cal
//找cal方法(super.call()) 的顺序是直接查找父类,其他的规则一样
//super.cal();
//演示访问属性的规则
//n1 和this.n1 的规则是
//(1)先找本类,如果有,则调用
//(2)如果没有,则找父类(如果有,并可以调用,则调用)
//(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
//提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
System.out.println(n1);
System.out.println(this.n1);
//找n1(super.n1) 的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);//100
}
访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句!
public B(){
//super();
//super("jack",10);
//super("jack");
}
}
package com.hspedu.super_;
import com.hspedu.extend.improve_.Base;
public class Super01 {
public static void main(String[] args) {
B b = new B();//子类对象
//b.sum();
b.test();
}
}
8.9.3super 给编程带来的便利/细节
代码, 看前面的案例即可:
8.9.4super 和 this 的比较
8.10 方法重写/覆盖(override)
8.10.1 基本介绍
8.10.2 快速入门
代码
package com.hspedu.override_;
public class Animals {
public void cry() {
System.out.println("动物叫唤..");
}
public Object m1(){
return null;
}
public String m2(){
return null;
}
public AAA m3(){
return null;
}
protected void eat(){
}
}
package com.hspedu.override_;
public class Dog extends Animals{
//老师解读
//1.因为Dog 是 Animals子类
//2.Dog的 cry方法和Animals的 cry定义形式一样(名称、返回类型、参数)
//3.这时我们就说 Dog的cry方法,重写了Animals的cry方法
public void cry() {
System.out.println("小狗汪汪叫..");
}
//细节:子类的返回方法和父类方法返回类型一样
// 或者是父类返回类型的子类VT比如 父类 返回类型是Object,
// 子类方法返回类型是String
public String m1(){
return null;
}
//这里Object 不是 String的子类,因此编译错误
// public Object m2(){
// return null;
// }
// public BBB m3(){
//
// }
//细节:子类方法不能缩小父类方法的访问权限
//public > protected > 默认 > private
public void eat(){
}
}
class AAA{
}
class BBB extends AAA{
}
package com.hspedu.override_;
public class Override01 {
public static void main(String[] args) {
//演示方法的情况
Dog dog = new Dog();
dog.cry();//ctl + b
}
}
8.10.3 注意事项和使用细节
方法重写也叫方法覆盖,需要满足下面的条件
8.10.4 课堂练习
✓ 题 1
请对方法的重写和重载做一个比较
✓ 题 2
-
编写一个 Person 类,包括属性/private(name、age),构造器、方法 say(返回自我介绍的字符串)。
-
编写一个 Student 类,继承 Person 类,增加 id、score 属性/private,以及构造器,定义 say 方法(返回自我介绍的信息)。
-
在 main 中,分别创建 Person 和 Student 对象,调用 say
package com.hspedu.override_;
//编写一个 Person 类,包括属性/private(name、age),构造器、方法 say(返回自我介绍的字符串
public class Person {
private String name;
private int age;
public Person() {//无参构造器
}
public Person(String name, int age) {//有参构造器
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say(){
return "名字是" + name + " 年龄是" + age;
}
}
package com.hspedu.override_;
//编写一个 Student 类,继承 Person 类,增加 id、score 属性/private,以及构造器,定义 say 方法(返回自我介绍的信息)。
public class Student extends Person{
private String id;
private int score;
public Student() {//无参构造器
}
public Student(String name, int age, String id, int score) {//有参构造器
super(name, age);//调用父类构造器
this.id = id;
this.score = score;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String say(){//这里体现super的一个好处,代码复用
return super.say() + " id是" + id + " 成绩是" + score;
}
}
package com.hspedu.override_;
public class OverrideExercise {
public static void main(String[] args) {
Person person = new Person("Jim",10);
System.out.println(person.say());
Student amy = new Student("Amy", 11, "123456", 98);
System.out.println(amy.say());
}
}
8.11 面向对象编程-多态
8.11.1 先看一个问题
· 使用传统的方法来解决(private 属性)
· 传统的方法带来的问题是什么? 如何解决?
问题是: 代码的复用性不高,而且不利于代码维护
解决方案: 引出我们要讲解的多态
8.11.2 多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
8.11.3 多态的具体体现
-
方法的多态 PloyMethod.java
重写和重载就体现多态 [案例说明:]
package com.hspedu.poly_.objpoly_;
public class PolyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println("B say() 方法被调用...");
}
}
class A extends B {//子类
public int sum(int n1, int n2){//和下面 sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3){
return n1 + n2 + n3;
}
public void say() {
System.out.println("A say() 方法被调用...");
}
}
-
对象的多态 (核心,困难,重点)
代码
package com.hspedu.poly_.objpoly_;
public class Animals {
public void cry(){
System.out.println("Animals cry() 动物在叫....");
}
}
package com.hspedu.poly_.objpoly_;
public class Cat extends Animals{
@Override
public void cry() {
System.out.println("Cat cry()小猫喵喵叫...");
}
}
package com.hspedu.poly_.objpoly_;
public class Dog extends Animals{
@Override
public void cry() {
System.out.println("Dong cry()小狗汪汪叫...");
}
}
package com.hspedu.poly_.objpoly_;
public class PolyObject {
public static void main(String[] args) {
//体现对象多态特点
//animals 编译类型就是 Animals,运行类型 Dog
Animals animals = new Animals();
//因为运行时,这时即执行到该行时,animals运行类型是Dog的cry
animals.cry();//小狗汪汪叫...
//animals 编译类型就是 Animals,运行类型 Cat
animals = new Cat();
animals.cry();//小猫喵喵叫...
}
}
8.11.4 多态快速入门案例
使用多态的机制来解决主人喂食物的问题,走代码。 Poly01.java
8.11.5 多态注意事项和细节讨论(instanceof重要)
com.hspedu.poly.detail 包 : PolyDetail.java
多态的前提是:两个对象(类)存在继承关系
多态的向上转型
多态向下转型
package com.hspedu.poly_.detail_;
public class Animals {
String name = "动物";
int age = 10;
public void sleep() {
System.out.println("睡");
}
public void run() {
System.out.println("跑");
}
public void eat(){
System.out.println("吃");
}
public void show(){
System.out.println("hello,你好");
}
}
package com.hspedu.poly_.detail_;
public class Cat extends Animals{
public void eat(){//方法重写
System.out.println("猫吃鱼");
}
public void catchMouse(){//Cat 特有方法
System.out.println("猫抓老鼠");
}
}
package com.hspedu.poly_.detail_;
public class Dog extends Animals{//是animals子类
}
package com.hspedu.poly_.detail_;
public class PolyDetail {
public static void main(String[] args) {
//向上转型: 父类的引用指向子类的对象
//语法:父类类型引用名 = new 子类类型();
Animals animals = new Cat();
//Object obj = new Cat();//可以,Object 也是 Cat的父类
//向上转型调用方法的规则如下:
//(1)可以调用父类中的所有成员(须遵守访问权限)
//(2)但是不能调用子类中的特有的成员
//(3)因为在编译阶段,能调用那些成员,是由编译类型决定的
// animals.catchMouse();//错误
//(4)最终运行效果看子类的具体实现,即调用方法时,按照从子类开始查找方法
// 然后调用,规则和前面我们讲的方法调用规则一致
animals.eat();//猫吃鱼
animals.run();//跑
animals.show();//hello,你好
animals.sleep();//睡
//老师希望,可以调用Cat的catchMouse()方法
//多态的向下转型
//(1)语法:子类类型 引用名 =(子类类型)父类引用;
//问一个问题? cat 的编译类型 Cat,运行类型是 Cat
Cat cat = (Cat) animals;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
// Dog dog = (Dog) animals;//错
}
}
✓ 属性没有重写之说!属性的值看编译类型 PolyDetail02.java
package com.hspedu.poly_.detail_;
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);// ? 看编译类型 10
Sub sub = new Sub();
System.out.println(sub.count);// 20
}
}
class Base { //父类
int count = 10;//属性
}
class Sub extends Base {//子类
int count = 20;//属性
}
✓ instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型【举例说明】PolyDetail03.java
package com.hspedu.poly_.detail_;
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);//true
System.out.println(bb instanceof AA);//true
//aa 编译类型 AA, 运行类型是BB
AA aa = new BB();
System.out.println(aa instanceof AA);//true
System.out.println(aa instanceof BB);//true
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA{}//父类
class BB extends AA{}//子类
8.11.6 课堂练习
请说出下面的每条语言,哪些是正确的,哪些是错误的,为什么? 2min 后老师评讲
PolyExercise02.java 3min
8.11.7 java 的动态绑定机制(非常非常重要.)
Java 重要特性: 动态绑定机制
1.当调用对象对象方法时,该方法会和该对象的内存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声名,那里使用
package com.hspedu.poly_.dynamic_;
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 20
}
}
class A {//父类
public int i = 10;
//动态绑定机制:
public int sum() {//父类 sum()
return getI() + 10;//20 + 10
}
public int sum1() {//父类 sum1()
return i + 10;//10 + 10,
}
public int getI() {//父类 getI
return i;
}
}
class B extends A {//子类
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {//子类 getI()
return i;
}
// public int sum1() {
// return i + 10;
// }
}
8.11.8 多态的应用
-
多态数组 com.hspedu.poly.polyarr 包 PloyArray.java
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组 中,并调用每个对象
say 方法.
应用实例升级:如何调用子类特有的方法,比如
Teacher 有一个 teach , Student 有一个 study
怎么调用?
package com.hspedu.poly_.polyarr_;
public class Person {
private String name;
private int age;
public Person() {//无参构造器
}
public Person(String name, int age) {//有参构造器
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say(){
return name + "\t" + age;
}
}
package com.hspedu.poly_.polyarr_;
public class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//重写父类的say方法
@Override
public String say() {
return "老师是 " + super.say() + " salary" + salary;
}
//特有方法
public void teach(){
System.out.println("老师 " + getName() + " 正在授java课");
}
}
package com.hspedu.poly_.polyarr_;
public class Student extends Person {
private double score;
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//重写父类say
@Override
public String say() {
return "学生是 " + super.say() + " score" + score;
}
//特有的方法
public void study(){
System.out.println("学生 " + getName() + " 正在学java");
}
}
package com.hspedu.poly_.polyarr_;
public class PolyArray {
public static void main(String[] args) {
//应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、
// 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法
Person[] persons = new Person[5];
persons[0] = new Person("marry",20);
persons[1] = new Student("jack",18,100);
persons[2] = new Student("smith",19,30.1);
persons[3] = new Teacher("scott",30,20000);
persons[4] = new Teacher("king",50,25000);
//循环遍历多态数组,调用say
for (int i = 0; i < persons.length; i++) {
//提示:person[i] 编译类型是 Person ,运行类型是根据实际情况由JVM来判断
System.out.println(persons[i].say());//动态绑定机制
//这里大家聪明,使用类型判断 + 向下转型
if(persons[i] instanceof Student){//判断person[i]的运行类型是不是Student
Student student = (Student) persons[i];//向下转型
student.study();
//也可以使用一条语句((Student)persons[i]).study();
} else if(persons[i] instanceof Teacher){
Teacher teacher = (Teacher)persons[i];
teacher.teach();
}else if(persons[i] instanceof Person){
}else{
System.out.println("你的类型有误,请自己检查...");
}
}
}
}
-
多态参数
package com.hspedu.poly_.polyparameter_;
public class Employee {
private String name;
private double salary;
public Employee() {
}
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
//得到年工资的方法
public double getAnnual(){
return 12 * salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.hspedu.poly_.polyparameter_;
public class Worker extends Employee{
public Worker(String name, double salary) {
super(name, salary);
}
public void work(){
System.out.println("普通员工 " + getName() + " is working");
}
@Override
public double getAnnual() {//因为普通员工二u其他收入,则直接调用父类方法
return super.getAnnual();
}
}
package com.hspedu.poly_.polyparameter_;
public class Manager extends Employee{
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage(){
System.out.println("经理 " + getName() + " is managing");
}
//重写获取年薪方法
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
package com.hspedu.poly_.polyparameter_;
public class PolyParameter {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager milan = new Manager("milan", 5000, 200000);
PolyParameter polyParameter = new PolyParameter();
polyParameter.showEmpAnnual(tom);
polyParameter.showEmpAnnual(milan);
polyParameter.testWork(tom);
polyParameter.testWork(milan);
}
//showEmpAnnual(Employee e)
//实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()]
public void showEmpAnnual(Employee e){
System.out.println(e.getAnnual());//动态绑定机制,
}
//添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法
public void testWork(Employee e){
if(e instanceof Worker){
((Worker) e).work();//有向下转型操作
}else if(e instanceof Manager){
((Manager) e).manage();//有向下转型操作
}else{
System.out.println("do nothing...");
}
}
}
8.12 Object 类详解
8.12.1 equals 方法
✓==和 equals 的对比 [面试题]
package com.hspedu.Object_;
public class Equals01 {
public static void main(String[] args) {
A a = new A();
A b = a;
A c = b;
System.out.println(a == c);//true
System.out.println(b == c);//true
B bObj = a;
System.out.println(bObj == c);//true
//equals 方法,源码怎么查看。
//把光标放在equals方法,直接输入ctrl + b
/*
//带大家
public boolean equals(Object anObject) {
if (this == anObject) {//如果是同一个对象
return true;//返回 true
}
if (anObject instanceof String) {//判断类型
String anotherString = (String)anObject;//向下转型
int n = value.length;
if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])
return false;
i++;
}
return true;//如果两个字符串的所有字符都相等,则返回 true
}
}
return false;//如果比较的不是字符串,则直接返回 false
}
*/
"hello".equals("abc");
//看看Object类的 equals 是
/*
//即Object 的equals 方法默认就是比较对象地址是否相同
//也就判断两个对象是不是同一个对象
public boolean equals(Object obj) {
return (this == obj);
}
*/
/*
//从源码可以看出 Integer 也重写了Object的equals方法,
//变成了判断两个值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
*/
Integer integer1 = new Integer(5);
Integer integer2 = new Integer(5);
System.out.println(integer1 == integer2);//false
System.out.println(integer1.equals(integer2));//true
String str1 = new String("hspedu");
String str2 = new String("hspedu");
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//false
}
}
class B { }
class A extends B{ }
8.12.2 如何重写 equals 方法
-
应用实例: 判断两个 Person 对象的内容是否相等,如果两个 Person 对象的各个属性值都一样,则返回 true,反之 false。
EqualsExercise01.java
package com.hspedu.Object_;
import jdk.nashorn.internal.ir.CallNode;
public class EqualsExercise01 {
public static void main(String[] args) {
Person person0 = new Person("amy", 16, '女');
Person person1 = new Person("amy", 16, '女');
// Person person1 = new Person("Jim", 15, '男');
System.out.println(person0.equals(person1));
}
}
//判断两个 Person 对象的内容是否相等,
//如果两个 Person 对象的各个属性值都一样,则返回 true,反之 false
class Person{//extends Object
private String name;
private int age;
private char gender;
//重写Object 的equals方法
public boolean equals(Object obj){
//判断如果比较的两个对象是同一个对象,则直接返回 true
if(this == obj){
return true;
}
//类型判断
if(obj instanceof Person){//instanceof判断的是是运行类型,obj编译类型是Object,运行类型是Person
//进行 向下转型,因为我需要得到obj的各个属性
//向下转型后可以调用子类类型的所有成员
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
// if(this.name != ((Person) obj).name){//判断条件错了,只能判断两个name的地址
// return false;
// }else if(this.age != ((Person) obj).age){
// return false;
// }else if(this.gender != ((Person) obj).gender){
// return false;
// }else{
// return true;
// }
}else{//如果不是Person,则直接返回false
return false;
}
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
-
-
习题三
8.12.4 hashCode 方法
★ 6 个小结:
-
提高具有哈希结构的容器的效率!
-
两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
-
两个引用,如果指向的是不同对象,则哈希值是不一样的
-
哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址
-
案例演示[HashCode_.java]: obj.hashCode() [测试:A obj1 = new A(); A obj2 = new A(); A obj3 = obj1]
-
后面在集合,中 hashCode 如果需要的话,也会重写, 在讲解集合时,老韩在说如何重写 hashCode()
package com.hspedu.Object_;
public class HashCode_ {
public static void main(String[] args) {
AA aa = new AA();
AA aa1 = new AA();
AA aa2 = aa;
System.out.println("aa.hashCode()=" + aa.hashCode());//460141958
System.out.println("aa1.hashCode()=" + aa1.hashCode());//1163157884
System.out.println("aa2.hashCode()=" + aa2.hashCode());//460141958
}
}
class AA{}
8.12.5 toString 方法
-
基本介绍
默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】
子类往往重写 toString 方法,用于返回对象的属性信息
-
重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式
案例演示:Monster [name, job, sal] 案例: ToString_.java
-
当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用monster.toString()
package com.hspedu.Object_;
public class ToString_ {
public static void main(String[] args) {
/*
Object的toString()源码
(1)getClass().getName() 类的全类名(包名+类名)
(2)Integer.toHexString(hashCode()将对象的hashCode值转成16进制字符串
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
*/
Monster monster = new Monster("小妖怪", "巡山的", 1000);monster.toString();
System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
System.out.println("==当直接输出一个对象时,toString 方法会被默认的调用==");
System.out.println(monster);
}
}
class Monster{
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
//重写toString方法,输出对象的属性
//使用快捷键即可 alt+insert -> toString
@Override
public String toString() {//默认重写后,一般是把对象的属性输出,当然程序员也可以自己定制
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
8.12.6 finalize 方法
-
当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作【演示】
-
什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize 方法。
-
垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制,测 试:Car [name]
老韩提示: 我们在实际开发中,几乎不会运用 finalize , 所以更多就是为了应付面试.
package com.hspedu.Object_;
//演示 Finalize的用法
public class Finalize_ {
public static void main(String[] args) {
Car bmw = new Car("宝马");
//这时 car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象,在销毁对象前,会调用该对象的finalize方法
//,程序员就可以在 finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
//,如果程序员不重写 finalize,那么就会调用 Object类的finalize,及默认处理
//,如果程序员重写了finalize,就可以实现自己的逻辑
bmw = null;
System.gc();//主动调用垃圾回收器
System.out.println("程序退出了....");
}
}
class Car{
private String name;
public Car(String name) {
this.name = name;
}
//重写finalize
//快捷键就可以生成
@Override
protected void finalize() throws Throwable {
System.out.println("我们销毁 汽车" + name);
System.out.println("释放了某些资源...");
}
}
8.13 断点调试(debug)
8.13.1 一个实际需求
8.13.2 断点调试介绍
8.13.3 断点调试的快捷键
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)
F7:跳入方法内
F8: 逐行执行代码.
shift+F8: 跳出方法
8.13.4 断点调试应用案例
看几段代码,演示调试过程
8.13.5 断点调试应用案例
-
案例 1 com.hspedu.debug_ 包 Debug01.java
看一下变量的变化情况等
package com.hspedu.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("i=" + i);
System.out.println("sum=" + i);
}
System.out.println("退出 for....");
}
}
-
案例 2
看一下数组越界的异常 Debug02.jav
package com.hspedu.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");
}
}
-
案例 3
演示如何追源码,看看 java 设计者是怎么实现的。(提高编程思想)。
小技巧:将光标放在某个变量上,可以看到最新的数据。 Debug03.java
package com.hspedu.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");
}
}
}
-
案例 4
演示如何直接执行到下一个断点 F9 resume。
小技巧: 断点可以在 debug 过程中,动态的下断点
package com.hspedu.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");
}
}
8.13.6 断点调试课后练习
8.14 项目-零钱通
8.14.1 项目开发流程
8.14.2 项目需求说明
使用 Java 开发 零钱通项目 , 可以完成收益入账,消费,查看明细,退出系统等功能.
8.14.3 项目的界面
化繁为简.
-
先完成显示菜单,并可以选择
-
完成零钱通明细.
-
完成收益入账
-
消费
-
退出
8.14.4 项目代码实现
编写文件 SmallChangeSys.java 完成基本功能 (过程编程)
老师提示:先使用过程编程,后面改成 OOP 版本,请小伙伴体会 OOP 编程带来的好处