今日重点:
目录
一、Java面向对象的特点之一:继承
类与类之间的关系:
* 1.属性关系
* 2.参数关系
* 3.继承关系
1.继承的实现
(1)概念:
继承是面向对象三大特性之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义以及追加属性和方法,继承通过extends实现。在Java中,继承是单继承,一个子类只能有一个直接父类,但是可以有多个间接父类,extends后面只能写一个类。
父类(超类superclass)
子类(基类 subclass)
(2)实现格式:
- 格式:class 子类 extends 父类 { }
- 举例:class Cat extends Animal { }
(3)继承的注意事项
1.子类不是无限继承父类中的内容,它只能继承父类中非私有(非private修饰)的代码,也不能继承构造方法,也不能继承不同包中,默认修饰的内容。
2.只能继承父类中非私有(非private修饰)的代码:private修饰的内容是私有的,只能在本类中使用。(话糙理不糙:你爸爸的闺女 不是你的闺女 你是无法继承这关系)3.不能继承构造方法:构造方法是用来初始化对象(对象创建),它是给父类创建对象用的。(话糙理不糙:生你爸爸的人 不能生你)
访问权限修饰符:
* 1.public
* 2.protected 受保护的,不同包的子类可以访问
* 3.default 默认的
* 4.private(4)继承能干什么
* 1.子类可以继承父类的属性
* 2.子类·可以继承了父类的方法
* 3.创建子类对象时(创建对象的过程就是实例化的过程),执行了父类的构造器,父类先被实例化,再去实例化子类。
* 4.当一个类被实例化时,一定会先实例化它的间接父类,再直接父类,再实例化它自己(先有爷爷再有爸爸再有自己)
*注意:子类的构造器可以有多个,但是必须和父类的构造器形式上统一。
2、继承中成员访问的特点
(1)构造方法访问特点
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法,如果父类中只有带参构造方法,我们又需要使用无参构造方法时,一般自己给出无参构造方法(2)变量和成员方法的访问特点
1.变量
①子类局部范围找
②子类成员范围找
③父类成员范围找
④如果都没有就报错(不考虑父亲的父亲…)2.成员方法
①子类成员范围找
②父类成员范围找
③如果都没有就报错(不考虑父亲的父亲…)
(3)super和this关键字的区别
1.定义:
this:代表本类对象的引用,代表当前对象的引用,谁来调用我,我就代表谁
super:代表父类存储空间的标识,代表当前对象父类的引用
2.使用区别:
①调用成员变量
this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
super.成员变量 调用父类的成员变量
②调用构造方法
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法
③调用成员方法
this.成员方法 调用本类的成员方法,也可以调用父类的方法
super.成员方法 调用父类的成员方法
面试题:this和super的区别?
* 在子类中当使用super调用父类的构造器时,super(age)必须是第一句话
* 在当前类中使用this调用本类的构造器时,this(name)必须是第一句话
* 在构造器中,如果需要使用super或this调用其他(子类或者父类)构造器,只能二选一,而且还必须是第一句话
* super指向的父类,不代表任何对象。
* this指向的本类,代表当前类的对象,方法的调用者。
3、方法重写
(1)定义:
子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
①子类可以重写父类的方法
②方法的重写,我们可以利用到父类中方法已经运算过的结果,在结果的基础上进行扩展
③方法的重写,体现的就是继承的核心,就是为了扩展父类的功能。
④开发中,如果要重写,基本就是一模一样,我们只变方法体⑤重写的方法的返回值可以是被重写方法的返回值的子类。
(2) 方法的重写的规则---前提,继承与被继承的关系(父类与子类):
①.访问权限:重写的方法的权限不能低于被重写的方法。开发中一般都是等于。
②返回值类型:重写的方法的返回值可以和被重写的方法不同,但是必须是被重写方法的返回值的子类。开发中,一般就是一样。
③.方法名:必须相同
④.参数列表:参数类型,参数个数必须相同。
⑤抛出异常:重写的方法不能抛出比被重写的方法更大的异常
(3)应用场景
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
(4)方法重写和方法重载的区别:(面试题)
方法的重写(Override)和重载(Overload)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
①方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overload)。
②方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Override)。
③方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
(5)方法重写的注意事项
私有方法不能被重写(父类私有成员子类是不能继承的)。
子类方法访问权限不能更低(public > 默认 > 私有)。以上参考的文章博客链接为:
二、课上实例
我们创建四个类,Biology类,Animal类,Person类,Cat类
Biology类的代码
//Biology类的代码: package com.jr.morning; public class Biology { protected String name; Integer age;//Integer:包装器类型 public Biology() { } public Biology(Integer age) { this.age = age; System.out.println("生物类的构造器..."); } public void breath(){ } }
Animal类的代码
//Animal类的代码: package com.jr.morning; public class Animal extends Biology{ public Animal() {//无参构造 } public Animal(Integer age) { super(age);//super:代表调用父类的结构(属性、方法、构造器) System.out.println("动物类的构造器..."); } public Animal(Integer age,String name) { super(age);//在子类中当使用super调用父类的构造器时,super(age)必须是第一句话 //this(age);//在构造器中,如果需要使用super或this调用其他(子类或者父类)构造器,只能二选一,而且还必须是在第一句话 this.name = name; //this(name); } public void eat(){ // 调用父类的属性 age = 20;//super.age=20; // 调用父类的方法 breath();//super.breath(); // 调用当前类的属性 name = "z";//this.name="z"; //this和super都可以省略掉,代表先在本类找,没找到就是去父类找 } public void drank(String water) { System.out.println("动物在喝" + water); } public String show() { return "我们很优秀"; } public Biology info(Biology biology) { return null; } }
Person类的代码
//Person类的代码: package com.jr.morning; public class Person extends Animal { public Person() { } public Person(Integer age) { super(age); System.out.println("人类的构造器..."); } public void drank(String water){ System.out.println("人在喝" + water); System.out.println("喝完了" + water + "再来一杯!"); } public String show(){ // 返回的是我们很优秀,我们很直溜 return super.show() + "我们很直溜"; } public Animal info(Biology animal){ return null; } }
Cat类的代码
//Cat类代码: package com.jr.morning; public class Cat extends Animal{ public Cat(Integer age) { super(age); } }
主类的代码
package com.jr.morning; public class Ch01 { public static void main(String[] args) { //生物类的对象 Biology biology = new Biology(); biology.age = 20;//调属性 biology.breath();//调方法 //动物类的对象 Animal animal = new Animal(30); animal.age = 30;//当Animal类中什么都没有写的时候,这里也可以写age,breath animal.breath();//因为这是从Biology父类继承过来的属性和方法 //人类的对象 Person person = new Person(); person.age = 35;//继承间接分类的age属性 person.name = "张三";//继承直接父类的name属性 person.eat();//继承直接分类的eat方法 person.breath();//继承间接父类的breath方法 } }
调用方法重写的代码
package com.jr.morning; public class Ch02 { public static void main(String[] args) { Person person = new Person();//得到类的对象 person.drank("江小白");//调用本类Person类的drank方法,不能调用Animal类的方法 } }
三、实际案例
----需求 :
1.有一个银行卡类,有账号和密码,余额,有存款和取款的方法。
2.创建一个借记卡类,继承于银行卡,转账额度。存款和取款的方法,取款的时候,如果超过了20000,则提示需要去柜台拿身份真办理! ! !
4.创建一个信用卡类,继承于银行卡,信用额度。
5.有存款和取款的方法。
取款:如果余额大于0,则从余额中扣,如果余额小于等于0, 则会走信用额度
余额: 100, 信用额度: 50000, 1000我们创建四个类:主类Demo,银行卡类Card,借记卡类DebitCard,信用卡类CreditCard
这里有两个版本,这个案例是上课针对本节课知识点做的针对性练习,易理解所以就存在一些bug,进阶版更简洁一些,用到了链式编程(链式处理)。
链式;
1.编程性强;
2.可读性强;
3.代码更简洁;
4.对程序员的业务能力要求高;
5.不太利于代码调试;
链式编程可以使得代码可读性高,链式编程的原理就是返回一个this对象,就是返回本身,达到链式效果。看到this关键字,我们首先应该想到1.它代表当前类对象2.代表当前方法的调用者。在链式编程中,this关键字起到的作用就是当前方法的调用者。
主类Demo
package com.jr.morning.Test1; public class Demo { public static void main(String[] args) { /* //测试借记卡DebitCard DebitCard debitCard=new DebitCard("123456","123456",Double.valueOf(100),Double.valueOf(20000));//得到DebitCard类对象 Double in=debitCard.in(10000000.0);//存款 in =debitCard.out(300000.0);//取款 if (in >=0){ System.out.println("余额为:"+in); }else if(in==-1){ System.out.println("取款失败,余额不足!"); }else if (in==-2){ System.out.println("取款失败,今日取款额度不足!"); } */ //测试信用卡CreditCard CreditCard creditCard=new CreditCard("123456","123456",1000.0,50000.0); System.out.println("剩余额度为:"+creditCard.out(2000.0));//取款。结果返回剩余额度 System.out.println("余额为:"+creditCard.in (3000.0));//存款。结果返回余额 } }
进阶版:
public class Demo { public static void main(String[] args) { DebitCard debitCard = new DebitCard("123456", "123456", 100.0, 2000.0); Card card = debitCard.in(2000.0);//存钱,赋值给card System.out.println("存款成功:" + card.getCardId() + "的余额为:" + card.getBalance()); DebitCard d = debitCard.out(1500.0);//存钱,赋值给card if (d.getBalance() >= 0) { System.out.println("取款成功:" + d.getCardId() + "的余额为:" + d.getBalance()); } else if (d.getBalance() == -1) { System.out.println("余额不足!" ); } else if (d.getBalance() == -2) { System.out.println("取款额度不足!"); } } }
银行卡类Card
package com.jr.morning.Test1; import java.util.Date; //银行卡 public class Card {//父类 private String cardId; private String password; private double balance;//余额 //构造函数 public Card(String cardId, String password, double balance) { this.cardId = cardId; this.password = password; this.balance = balance; } public Card() {//养成一个习惯,构造函数之后,每个类还应该构造一个无参构造器 } public Double in(Double money) {//存款 balance += money;//给balance赋值 return balance;//返回余额 } public Double out(Double money) {//取款 balance -= money; return balance; } //构造setter,getter方法 public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } }
进阶版:
package com.jr.morning.Test; import java.util.Date; //银行卡 public class Card {//父类 private String cardId; private String password; private double balance;//余额 //构造函数 public Card(String cardId, String password, double balance) { this.cardId = cardId; this.password = password; this.balance = balance; } public Card() {//养成一个习惯,构造函数之后,每个类还应该构造一个无参构造器 } public Card in(Double money){//存款 balance += money;//给balance赋值 this.setBalance(balance); return this;//返回余额 } public Card out(Double money){//取款 balance-=money; Card card=new Card(cardId,password,balance);//获取Card类的属性 return card;//返回给Card } //构造setter,getter方法 public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } }
借记卡类DebitCard
package com.jr.morning.Test1; import java.awt.datatransfer.Transferable; import java.util.Date; //借记卡 public class DebitCard extends Card {//DebitCard子类继承Card父类 private Double TransferAmount;//加入一个转账额度的属性 public DebitCard() { } public DebitCard(String cardId, String password, double balance, Double TransferAmount) { super(cardId, password, balance);//调用父类的构造函数(属性) this.TransferAmount = TransferAmount;//传进来的TransferAmount赋值给调用本类的TransferAmount } public Double out(Double money) {//方法重写---DebitCard中的取款,写取款是因为借记卡里得判断一下余额 //借记卡的取款,除了要考虑余额是否足够。转账额度问题,超过20000 if (getBalance() >= money && TransferAmount >= money) {// 不用直接用super直接调用父类Card的属性了,因为private double balance;中有private代表属性私有化了,不能调用 //但是可以用get方法调用余额Balance---getBalance //getBalance()>=money&&TransferAmount>=money代表余额要足够,额度要足够,可以直接调用父类方法 return super.out(money); } else if (getBalance() < money) { return Double.valueOf(-1);//自己定义的规则,如果方法的返回值等于-1,说明余额不足 } else if (TransferAmount < money) { return Double.valueOf(-2);//自己定义的规则,如果方法的返回值等于-2,说明额度不够 } return Double.valueOf(-3);//自己定义的规则,如果方法的返回值等于-3,说明是其他情况 } }
进阶版:
package com.jr.morning.Test; import java.awt.datatransfer.Transferable; import java.util.Date; //借记卡 public class DebitCard extends Card {//DebitCard子类继承Card父类 private Double TransferAmount;//加入一个转账额度的属性 public DebitCard() { } public DebitCard(String cardId, String password, double balance, Double TransferAmount) { super(cardId, password, balance);//调用父类的构造函数(属性) this.TransferAmount = TransferAmount;//传进来的TransferAmount赋值给调用本类的TransferAmount } public DebitCard out(Double money) {//方法重写---DebitCard中的取款,写取款是因为借记卡里得判断一下余额 //借记卡的取款,除了要考虑余额是否足够。转账额度问题 //我们需要DebitCard类的对象,那我们就去得到DebitCard类 DebitCard debitCard=new DebitCard(); if (getBalance() >= money && TransferAmount >= money) {// 不用直接用super直接调用父类Card的属性了,因为private double balance;中有private代表属性私有化了,不能调用 //但是可以用get方法调用余额Balance---getBalance //getBalance()>=money&&TransferAmount>=money代表余额要足够,额度要足够,可以直接调用父类方法 Card card= super.out(money); //把父类的属性设置给子类 debitCard.setCardId(card.getCardId()); debitCard.setPassword(card.getPassword()); debitCard.setBalance(card.getBalance()); //括号里边get方法是获取属性,是父类对象拿它自己的属性给子类 //括号外边是用子类对象去设置属性(set方法) return debitCard; } else if (getBalance() < money) {//取款失败 debitCard.setBalance(Double.valueOf(-1));//Double.valueOf是把-1强制转换成double类型的数据 return debitCard;//自己定义的规则,如果方法的返回值等于-1,说明余额不足 } else if (TransferAmount < money) { debitCard.setBalance(Double.valueOf(-2)); return debitCard;//自己定义的规则,如果方法的返回值等于-2,说明额度不够 } return null;//返回空值,说明是其他情况 } }
信用卡类CreditCard
package com.jr.morning.Test1; public class CreditCard extends Card {//CreditCard子类继承Card父类 private Double credits;//CreditCard的信用额度属性 private Double temp=0.0;//定义一个临时属性 public CreditCard() {//CreditCard类的无参构造器 } public CreditCard(String cardId, String password, double balance, Double credits) { super(cardId, password, balance); this.credits = credits; } public Double in(Double money){//方法重写---CreditCard的存款 //信用卡的存款,首先要还额度,其次此时存款 if (temp==0.0){//判断临时的temp里的额度是不是0 return super.in(money);//如果是0,说明额度是够的,不用先还额度,直接存款就可以 } if (temp>=money){//如果额度欠的钱比存的money还多或正好相等,要先还额度,剩下的钱才是余额 credits += money;//看额度还差多少 temp -= money;//欠的额度还剩多少 return credits; } if (temp <money){//如果额度欠的钱比存的money还少, credits += temp;//额度满级 setBalance(money-temp);//获取还额度之后的余额 temp =0.0;//不欠额度了 return getBalance();//返回信用卡的余额 } return null; } public Double out(Double money){//方法重写---CreditCard的取款 //取款先走余额,再走信用额度 if(getBalance() >= money){ return super.out(money); } else if (getBalance() < money && credits < money) {//取款的时候,余额不够,额度也不够 return Double.valueOf(-1);//就返回-1 } else if (getBalance() < money && credits > money) {//余额不够,额度够 double d = money - getBalance(); credits = credits -d ;//剩余的信用额度 temp = d;//让temp把剩余额度存起来 return credits;//返回信用额度 } return null; } }
进阶版:
package com.jr.morning.Test; //信用卡 public class CreditCard extends Card {//CreditCard子类继承Card父类 private Double credits;//CreditCard的信用额度属性 private Double temp=0.0;//定义一个临时属性 public CreditCard() {//CreditCard类的无参构造器 } public CreditCard(String cardId, String password, double balance, Double credits) { super(cardId, password, balance); this.credits = credits; } public CreditCard in(Double money){//方法重写---CreditCard的存款 //信用卡的存款,首先要还额度,其次此时存款 if (temp==0.0){//判断临时的temp里的额度是不是0 return null;//如果是0,说明额度是够的,不用先还额度,直接存款就可以 } if (temp>=money){//如果额度欠的钱比存的money还多或正好相等,要先还额度,剩下的钱才是余额 credits += money;//看额度还差多少 temp -= money;//欠的额度还剩多少 return null; } if (temp <money){//如果额度欠的钱比存的money还少, credits += temp;//额度满级 setBalance(money-temp);//获取还额度之后的余额 temp =0.0;//不欠额度了 return null; } return null; } public CreditCard out(Double money){//方法重写---CreditCard的取款 //取款先走余额,再走信用额度 if(getBalance() >= money){ return null; } else if (getBalance() < money && credits < money) {//取款的时候,余额不够,额度也不够 return null; } else if (getBalance() < money && credits > money) {//余额不够,额度够 double d = money - getBalance(); credits = credits -d ;//剩余的信用额度 temp = d;//让temp把剩余额度存起来 return null; } return null; } }
今日总结:
这是学习Java面向对象的第三天,知识点是继承,掌握程度算三颗星吧。写银行卡案例的时候自己还是没能写出来,甚至思路也很少,说明自己对知识点的总体掌握情况不是很理想,我自我反思觉得原因应该是前两天的知识没学好,后面就有点跟不上了。人生如同过韶关,关关难过关关过,继续加油吧。