文章目录
- IDE(集成开发环境)
- IDEA介绍
- idea运行
- 包
- 包的作用
- 包基本语法
- 包的本质分析(原理)
- 包的命名
- 命名规则
- 命名规范
- 常用的包
- 如何引入包
- 注意事项和使用细节
- 访问修饰符【modifier】
- 基本介绍
- 使用的注意事项
- 封装【encapsulation】
- 介绍
- 封装的好处和理解
- 封装的实现步骤
- 封装练习
- 继承【extends】
- 基本介绍和示意图
- 继承的基本语法
- 继承的优点
- 继承的细节
- 继承的本质分析[重点]
- 练一练
- super
- 基本介绍
- 基本语法
- super的使用细节
- super和this的比较
- 重写/覆盖[OverWrite]
- 基本介绍
- 注意事项和使用细节
- 重载和重写的对比
- 多态
- 多态基本介绍
- 多态的具体体现
- 多态的注意事项和细节讨论
- 多态的前提是:
- 什么叫向上转型:
- 向下转型
- 动态绑定机制
- 测试题
- 多态数组
- 多态参数
- Object类详解
- equals方法
- 如何重写equals方法
- hashCode方法
- toString方法
- 基本介绍
- finalize方法
- 断点调试
- debug 快捷键
- 项目-零钱通
- 化繁为简、先死后活
- 总结
- 作业
- 说出 == 和equals的区别
- 什么是多态,多态的具体体现
- java的动态绑定机制
IDE(集成开发环境)
IDEA介绍
idea运行
java代码运行快捷键: command + R
生成构造器: command + N
查看类继承关系: control + H
自动生成变量名: .var
查看idea的模板快捷键或者自定义模板快捷键: file → settings → editor → Live Templates
包
包的作用
-
区分相同名字的类。
-
当类很多时,可以很好的管理类。
-
控制访问范围。【访问修饰符时详细讲解】
包基本语法
package com.zhangch;
说明: package关键字,表示打包的操作。
com.zhangch: 表示包名。
包的本质分析(原理)
包的本质实际上就是创建不同的文件夹来保存类文件。
包的命名
命名规则
只能包含数字、字母、下划线、小圆点,但不能数字开头,不能是关键字或保留字
命名规范
一般是小写字母 + 小圆点
com.公司名.项目名.业务模块名
比如:
com.sina.crm.user // 用户模块
com.sina.crm.order // 订单模块
com.sina.crm.utils // 工具类
常用的包
java.lang.* // lang包是基本包,默认引入
java.util.* // util 包, 系统提供的工具包,工具类,比如之前使用的Scanner
java.net.* // 网络包,之后会用于网络开发
java.awt.* // java界面开发, GUI
如何引入包
// 建议:需要什么类,就导入对应的类。不建议使用*
import java.util.Scanner; // 表示只会引入java.util包下的Scanner类。
import java.util.*; //表示将java.util 包下的所有类都引入
注意事项和使用细节
1、package 的作用是声明当前类所在的包,需要放在文件的最上面,一个类中最多只有一句package。
2、import放在类package的下面,在类定义的前面,可以有多句且没有顺序要求
// 一个类中最多只有一个package语句,且放在最前面。
// package语句用来表示当前类所在的包。
package com.test;
// import放在package下面,放在类定义的前面,可以有多句且没有顺序要求。
import java.util.Arrays;
public class Import01 {
public static void main(String[] args) {
int[] arr = {-1, 20, 33, 43, 4334};
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
访问修饰符【modifier】
基本介绍
java提供四种访问控制修饰符号, 用于控制方法和属性(成员变量)的访问权限(范围)。
1、公开级别: public修饰,表示方法和属性对外公开。
2、受保护级别: protected修饰,表示对子类和同一个包中的类公开。
3、默认级别:没有修饰符,向同一个包中的类公开。
4、私有级别: 用private修饰,只有类本身可以访问,不对外公开。
使用的注意事项
1、修饰符可以用来修饰类中的属性,成员方法以及类。
2、只有默认和public可以修饰类,并且遵循上述访问权限的特点。
3、使用修饰符的属性和方法,在访问时的规则完全一致。
封装【encapsulation】
介绍
封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作。
典型的封装案例是电视机,我们不需要纠结于电视内部启动的原理,只需要知道启动方法即可。
封装的好处和理解
1、隐藏实现的细节,直接调用即可。
2、可以对数据进行验证,保证数据的安全性和合理性。
封装的实现步骤
-
将属性进行私有化 private【不能直接修改属性】
-
提供一个公共的set方法,用于对属性进行判断并赋值。
-
提供一个公共的get方法,用于获取属性的值。
封装练习
package com.encap;
public class Encapsulation01 {
public static void main(String[] args) {
Person person = new Person("ZhangSan",30, 10000);
System.out.println(person.getInfo());
System.out.println("年龄为:" + person.getAge());
System.out.println("薪水为: " + person.getSalary());
}
}
// 1、年龄在1-120之间,否则使用默认值,
// 2、工资不能直接查看
// 3、name 的长度在 2-6个字符之间。
class Person{
public String name;
private int age;
private double salary;
public Person() {
}
// 有三个属性的构造器
public Person(String name, int age, double salary) {
this.setName(name);
setAge(age);
setSalary(salary);
}
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 > 0 && age < 150){
this.age = age;
} else{
System.out.println("年龄输入的范围有问题,在1-150之间");
this.age = 18;
}
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getInfo(){
return "名字为:" + this.name + " 年龄为:" + this.age + " 薪水为: " + this.salary;
}
}
继承【extends】
基本介绍和示意图
继承的主要优点是解决代码复用,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
继承的基本语法
class 字类 extends 父类{
}
- 子类会自动拥有父类定义的属性和方法
- 父类又叫 超类、基类
- 子类又叫 派生类
继承的优点
1、代码的复用性提高了
2、代码的扩展性和维护性大大提高
继承的细节
1、子类继承了所有的属性和方法, 但是私有属性和方法不能在子类中直接访问,要通过父类提供的get等公共的方法去访问。
2、子类必须调用父类的构造器,完成父类的初始化。
默认在子类的构造器中使用 super();
3、当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类中没有提供无参构造器,则必须在子类的每个构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作。
super("zhang", 40);
4、如果希望指定去调用父类的某个构造器,则可以显式的调用一下super(参数列表);
5、super 在使用时,必须放在构造器的第一行且super只能在构造器中使用。
6、super() 和 this() 都只能放在构造器的第一行,因此这样两个方法不能共存在同一个构造器。
7、java所有类都是Object类的子类,或者说Object类是所有类的父类
8、父类构造器的调用不限于直接父类,将一直向上追溯,直到Object类(顶级父类)
构造器则是从最上级父类(Object)开始初始化,逐级初始化,直到最后所有子类的初始化结束。
9、子类最多只能继承一个父类(指直接继承), 即 java 中的单继承机制
思考: 如何让A类 继承 B类 和 C类 → A → B B→C
10、不能滥用继承,需遵循子类和父类之间必须满足 is-a 的逻辑关系,即包含。
继承的本质分析[重点]
继承的本质是抽象:类是对 对象 的抽象,继承是对某一批类的抽象。
内存图
package com.encap;
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.age); // 返回的是 39
System.out.println(son.hobby); // 旅游
}
}
class GrandPa {
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {
String name = "大头爸爸";
int age = 39;
}
class Son extends Father {
String name = "大头儿子";
}
练一练
1、请思考输出是什么?
package com.encap.extend_;
public class Exercise01 {
public static void main(String[] args) {
B b = new B();
}
}
class A{
A(){
System.out.println("a");
}
A(String name) {
System.out.println("a name");
}
}
class B extends A{
B(){
this("abc");
System.out.println("b");
}
B(String name){
System.out.println("b name");
}
}
super
基本介绍
super代表父类的引用,用于访问父类的属性、方法、构造器。
基本语法
1、访问父类的属性,但不能访问父类中的 private 属性
2、访问父类的方法,不能访问父类中的 private 方法
3、访问父类的构造器。 super(参数列表); 只能放在构造器的第一句,只能出现一句。
super的使用细节
1、调用父类的构造器的好处。「分工明确,父类属性由父类初始化,子类的属性由子类初始化」
2、当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super,如果子类和父类没有重名,则super、this、直接访问的效果都是一致的。
super 方法直接从父类开始查找方法或者属性,而this和直接访则是从本类开始查找。
3、super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员,如果多个父类中都有同名的成员,使用super访问遵循就近原则。 A → B → C
super和this的比较
重写/覆盖[OverWrite]
基本介绍
方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。
注意事项和使用细节
方法重写也叫方法覆盖,需要满足下面的条件。
1、子类的方法名称、参数,要和父类方法的参数、名称完全一致。
2、子类方法的返回类型和父类方法的返回类型一样,或者子类的返回类型为父类返回类型的子类。
比如: 父类返回类型为Object,子类的返回类型为String类型
父类为: public Object getInfo(){retuen null;};
子类为: public String getInfo(){retuen null;};
3、子类方法不能缩小父类方法的访问权限, 可以放大访问权限。
// public 的访问权限大于 默认的 访问权限,所以满足重写
void sayOk(){};
public void sayOk(){};
重载和重写的对比
多态
多态基本介绍
方法或对象具有多种形态。是面向对象的三大特征,多态是建立在封装和继承基础之上的。
多态的具体体现
1、方法的多态: 重写和重载就能体现多态。
2、对象的多态:【背下来,记住】
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就已经被确定,不能再改变
- 运行类型是可以变化的
- 编译类型看定义时 = 号的左边,运行类型看 = 号的右边
// 可以让父类的引用指向子类的类型。
Animal animal = new Dog(); //animal编译类型是Animal, 运行类型是Dog
animal = new Cat(); // animal的运行类型变成了Cat,编译类型仍然为Animal
多态的注意事项和细节讨论
多态的前提是:
1、两个对象(类)存在继承关系。
2、多态的向上转型
3、多态的向下转型
4、类的属性没有重写之说,当调用类的属性时,属性的值直接对应编译类型得到,如果编译类型中没有,则去父类中查找属性
package com.encap.poly;
public class PolyDetail {
public static void main(String[] args) {
Animal animal = new Dog();
// 判断运行结果
System.out.println(animal.count);
}
}
class Animal{
int count = 10;
}
class Dog extends Animal{
int count = 20;
}
5、instanceOf比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX类型的子类型
String str = "hello";
str isstanceOf Object; // true。 判断对象的运行类型【String】 是否为 XXX(Object)类型或 XX(Object)类型的子类型。
什么叫向上转型:
1、本质:父类的引用指向了子类的对象
2、语法:父类类型 引用名 = new 子类类型();
Animal animal = new Cat();
3、使用特点:
-
编译类型看左边,运行类型看右边。
-
可以调用父类中的所有成员(需遵循父类的访问权限)
-
不能调用子类中的特有成员
对上面两句的解释:在编译阶段,能调用哪些成员,是由编译类型来决定的。javac指令
- 最终运行效果看运行类型的具体实现。 即调用成员时,按照从子类(运行类型)开始查找成员,找到则调用,找到没权限则报错。 java指令
向下转型
1、语法: 子类类型 引用名 = (子类类型) 父类引用;
Cat cat = (Cat)animal;
2、只能强转父类的引用,不能强转父类的对象。
3、要求父类的引用必须指向的是当前目标类型的对象
4、当向下转型后,可以调用子类类型中的所有成员
Animal animal = new Cat(); // 向上转型,子类的对象,指向父类的引用名
Cat cat = (Cat)animal; // 向下转型, 将父类的引用进行强转,转成 当前目标类型的对象。
// animal此引用名指向堆中的Cat类,这是向上转型,此时编译类型为Animal,但运行类型为 Cat
// 向下转型则为,将堆中的Cat类重新创建一个引用,所以要求父类的引用必须指向的是当前目标类型的对象。
动态绑定机制
1、当调用对象方法的时候,该方法会对该对象的内存地址/运行类型进行绑定。即为方法从运行类型开始查找。
2、当调用对象属性时,则没有动态绑定机制,即为,属性哪个类调用,就用哪个类的属性
第二点是在方法中使用到属性,所以是对应着声明类。
「多态的前提」是,「类的属性没有重写之说,当调用类的属性时,属性的值直接对应编译类型得到,如果编译类型中没有,则去父类中查找属性」 。属性没有重写机制,则不需要从子类向父类查找属性,记住这两种情况即可。
测试题
package com.encap.test;
public class Test {
public static void main(String[] args) {
A a = new B();
System.out.println(a.getSum()); // 40
System.out.println(a.getSum1()); // 20
}
}
class A {
public int i = 10;
public int getI() {
return i;
}
public int getSum() {
return getI() + 10;
}
public int getSum1() {
return i + 10;
}
}
class B extends A{
public int i = 20;
public int getI() {
return i;
}
// public int getSum() {
// return getI() + 20;
// }
// public int getSum1() {
// return i + 10;
// }
}
多态数组
多态数组的定义类型为父类类型,里面保存的实际元素类型为子类类型。
package com.encap.extend_.Exercise03;
public class Test {
public static void main(String[] args) {
PC pc = new PC("inter", 16, 256, "IBM");
// 创建多态数组方法一:
// Computer[] c = new Computer[2];
// c[0] = pc;
// c[1] = new Computer("Mac", 256, 512);
// 创建多态数组方法二:
Computer[] c = {pc, new Computer("Mac", 256, 512)};
for (int i = 0; i < c.length; i++) {
if (c[i] instanceof PC){
// 向下转型方法一:
((PC)c[i]).printInfo();
// 向下转型方法二:
// PC p1 = (PC)c[i];
// p1.printInfo();
} else{
System.out.println(c[i].getDetail());
}
}
}
}
class PC extends Computer{
private String brand;
public PC(String CPU, int memory, int disk, String brand) {
super(CPU, memory, disk);
this.brand = brand;
}
public void printInfo(){
System.out.println("PC信息为:");
System.out.println(getDetail() + "品牌为: " + brand);
}
}
class Computer {
private String CPU;
private int memory;
private int disk;
public Computer(String CPU, int memory, int disk) {
this.CPU = CPU;
this.memory = memory;
this.disk = disk;
}
public String getDetail(){
return "电脑的详细信息:" + "CPU: " + CPU + " 内存为: " + memory + " 硬盘为:" + disk;
}
}
多态参数
方法定义的形参类型为父类类型,实参类型则允许传入子类类型。
Object类详解
equals方法
== 和 equals方法的对比:
1、== : 既可以判断基本类型,又可以判断引用类型
-
如果判断基本类型,判断的是值是否相等。比如:int i = 10; double d = 10.0; 返回为true
-
判断引用类型,则判断的是地址是否相等,即判断是不是同一个对象。
2、equals:是Object类中的方法,只能判断引用类型
3、默认判断的是地址是否相等,子类中往往重写Object中的该方法,用于判断内容是否相等。比如:Integer\String [可以看看Integer和String的源码]
public boolean equals(Object obj) {
return (this == obj); // ==判断引用类型,得地址
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
IDEA Debug 如何进入源码.docx
如何重写equals方法
题目:判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之返回false。
package Equals01;
import java.util.Objects;
public class Exercise01 {
public static void main(String[] args) {
Person person = new Person("zhangch", 18, '男');
Person person1 = new Person("zhangch", 18, '男');
System.out.println(person.equals(person1));
}
}
class Person{
private String name;
private int age;
private char gender;
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
Person person = (Person) o;
return age == person.age && gender == person.gender && Objects.equals(name, person.name);
}
}
hashCode方法
1、提高具有哈希结构容器的效率;
2、两个引用,如果指向的是同一个对象,则哈希值肯定是一样的;
3、两个引用,如果指向的是不同对象,则哈希值是不一样的;
4、哈希值主要根据地址号来定,不能完全将哈希值等价于地址;
5、后面在集合中,hashCode如果需要的话,也会进行重写。
toString方法
基本介绍
1、默认返回:全类名[包名 + 类名] + @ + 哈希值的十六进制[将哈希值转为十六进制]
【查看Object 的toString方法】:
getClass().getName(): 输出全类名
Integer.toHexString(hashCode()): 将对象hashCode值转为16进制字符串。
2、子类往往重写 toString 方法,用于返回对象的基本属性信息。 快捷键:command + N
3、当直接输出一个对象时,toString 方法会被默认的调用。如果重写则调用重写后的方法
finalize方法
1、当对象被回收时,系统自动调用该对象的 finalize 方法,子类可以重写该方法,做一些释放资源的操作。
2、什么时候回被回收,当某个对象没有任何引用时,则JVM就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁对象,在销毁对象之前,会先调用对象的 finalize 方法。
3、垃圾回收机制的调用,是由系统来决定[有专门的垃圾回收算法,即gc]的,也可以通过System.gc() 主动触发垃圾回收机制。
package com.object_;
public class Finalize_ {
public static void main(String[] args) {
Car bmw = new Car("BMW");
// 现在Car对象就是一个垃圾,则执行回收(销毁)对象。
// 在销毁对象前,会调用该对象的finalize方法
bmw = null;
// 主动调用垃圾回收器,不一定成功,也许垃圾回收器正在忙。
System.gc();
// 程序员就可以在 finalize 中,写自己的业务逻辑代码(比如释放资源:数据库连接、打开文件....)
System.out.println("程序退出了");
}
}
class Car{
private String name;
public Car(String name) {
this.name = name;
}
@Override
protected void finalize() throws Throwable {
// 重写 finalize 方法
System.out.println("我们销毁汽车" + name);
System.out.println("释放了资源 ......");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
断点调试
1、通过断点调试,一步步的查看源码执行的过程,从而发现错误所在。
2、在断点调试中,代码处于运行状态,此时,是以对象的运行类型来执行的。
debug 快捷键
F7 跳入:跳入到方法内 Step Into
F8 跳过:逐行执行代码 Step Over
shift + F8 跳出: 跳出方法 Step Out
F9 resume,执行到下一个断点
将光标放在某个变量上,可以看到该变量的最新数据。
项目-零钱通
化繁为简、先死后活
package com.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class SmallChange {
//化繁为简
//1. 先完成显示菜单,并可以选择菜单,给出对应提示
//2. 完成零钱通明细
//3. 完成收益入账
//4. 消费
//5. 退出
//6. 用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,否则循环输入指令,直到输入y 或者 n
//7. 在收益入账和消费时,判断金额是否合理,并给出相应的提示
//定义相关的变量
boolean loop = true; // 为false时,程序运行结束
Scanner scanner = new Scanner(System.in);
String key = null; // 用户选择的菜单信息
double money = 0; // 每笔消费或收入信息
double balance = 0; // 余额资产信息
String details = "-----------------零钱通明细------------------";
String note = ""; // 消费明细
Date date = null; // date 是 java.util.Date 类型,表示日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //可以用于日期格式化的
public void Menu(){
do {
switch (mainMenu()){
case "1":{
setDetails();
break;
}
case "2":{
income();
break;
}
case "3":{
pay();
break;
}
case "4":{
//当用户退出while ,进行判断
if (exit().equals("y")) {
loop = false;
}
break;
}
default:
System.out.println("请重新输入数字");
}
}while (loop);
System.out.println("-----退出了零钱通项目-----");
}
public String mainMenu(){
System.out.println("\n================零钱通菜单===============");
System.out.println("\t\t\t1 零钱通明细");
System.out.println("\t\t\t2 收益入账");
System.out.println("\t\t\t3 消费");
System.out.println("\t\t\t4 退 出");
System.out.print("请选择(1-4): ");
return scanner.next();
}
public void setDetails(){
System.out.println(details);
}
public void income(){
System.out.print("收益入账金额:");
money = scanner.nextDouble();
//money 的值范围应该校验 -》 一会在完善
//老师思路, 编程思想
//找出不正确的金额条件,然后给出提示, 就直接break
if(money <= 0) {
System.out.println("收益入账金额 需要 大于 0");
return;
}
//找出正确金额的条件
balance += money;
//拼接收益入账信息到 details
date = new Date(); //获取当前日期
details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance;
}
public void pay(){
System.out.print("消费金额:");
money = scanner.nextDouble();
//money 的值范围应该校验 -》 一会在完善
//找出金额不正确的情况
//过关斩将 校验方式.
if(money <= 0 || money > balance) {
System.out.println("你的消费金额 应该在 0-" + balance);
return;
}
System.out.print("消费说明:");
note = scanner.next();
balance -= money;
//拼接消费信息到 details
date = new Date(); //获取当前日期
details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance;
}
public String exit(){
//用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,
// 否则循环输入指令,直到输入y 或者 n
// 老韩思路分析
// (1) 定义一个变量 choice, 接收用户的输入
// (2) 使用 while + break, 来处理接收到的输入时 y 或者 n
// (3) 退出while后,再判断choice是y还是n ,就可以决定是否退出
// (4) 建议一段代码,完成一个小功能,尽量不要混在一起
String choice = "";
do { //要求用户必须输入y/n ,否则就一直循环
System.out.println("你确定要退出吗? y/n");
choice = scanner.next();
// 此处的while判断是重点。
} while (!"y".equals(choice) && !"n".equals(choice));
return choice;
}
}
package com.test;
public class SmallChangeSysOOP {
public static void main(String[] args) {
SmallChange smallChange = new SmallChange();
smallChange.Menu();
}
}
总结
java创建对象的流程,从默认值 → 显式赋值 → 构造器赋值 流程,中间注意super的使用。
1、在 常量区 加载类相关信息,比如属性和方法,属性取默认值。
2、调用对象的构造器,调用构造器中的super方法,再调用父类对应构造器super方法,逐级往上调用。
3、当运行完父类的super()方法时,此时进行父类类属性的显式赋值,然后构造器赋值。
4、然后继续走父类构造器下的其他代码。
5、当父类的super走完后,子类的属性才能进行显式赋值,然后构造器赋值。
作业
package Exercise.Exercise06;
public class BankAccount {
private double balance;
public BankAccount(double initialBalance){
this.balance = initialBalance;
}
public void deposit(double amount){
balance += amount;
}
public void withDraw(double amount){
balance -= amount;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
package Exercise.Exercise06;
public class CheckingAccount extends BankAccount{
public CheckingAccount(double initialBalance) {
super(initialBalance);
}
@Override
public void deposit(double amount) {
super.deposit(amount - 1);
}
@Override
public void withDraw(double amount) {
super.withDraw(amount + 1);
}
}
package Exercise.Exercise06;
public class SavingAccount extends BankAccount{
private int count = 3;
private double rate = 0.01;
public SavingAccount(double initialBalance) {
super(initialBalance);
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getRate() {
return rate;
}
public void setRate(double rate) {
this.rate = rate;
}
@Override
public void deposit(double amount) {
if (count > 0){
super.deposit(amount);
} else {
super.deposit(amount - 1);
}
count --;
}
@Override
public void withDraw(double amount) {
if (count > 0){
super.deposit(amount);
} else {
super.deposit(amount + 1);
}
count --;
}
public void earnMonthlyInterest(){
count = 3;
super.deposit(getBalance() * rate);
}
}
package Exercise.Exercise06;
public class Main {
public static void main(String[] args) {
CheckingAccount checkingAccount = new CheckingAccount(1000);
checkingAccount.deposit(100);
System.out.println(checkingAccount.getBalance());
checkingAccount.withDraw(100);
System.out.println(checkingAccount.getBalance());
SavingAccount savingAccount = new SavingAccount(1000);
savingAccount.deposit(100);
savingAccount.deposit(100);
System.out.println(savingAccount.getBalance());
savingAccount.deposit(100);
System.out.println(savingAccount.getBalance());
savingAccount.deposit(100);
System.out.println(savingAccount.getBalance());
savingAccount.earnMonthlyInterest();
System.out.println(savingAccount.getBalance());
}
}
说出 == 和equals的区别
什么是多态,多态的具体体现
多态:
方法或对象具有多种形态,是OOP的第三大特征,是建立在封装和继承基础之上
多态的具体体现:
1、方法多态:
1)重载体现多态;2)重写体现多态
2、对象多态:
1)对象的编译类型和运行类型可以不一致,编译类型在定义时,就已经确定,不能再进行变化
2)对象的运行类型是可以变化的,可以通过**getClass()来查看运行类型
**。
3)编译类型看 = 号的左边,运行类型看 = 号的右边。
java的动态绑定机制
1、当调用对象的方法时,该方法会从对象的内存地址/运行类型地址开始查找,
2、当调用对象的属性时,没有动态绑定机制,在哪里声明,哪里使用。