注意:
生活上:财产的继承、颜值的继承
代码层面:
有了继承性以后:
默认的父类:
Java 中声明的类,如果没有显式的声明其父类时,则默认继承于 java.lang.Object
补充说明:
is-a
的关系,为多态的使用提供了前提。
is-a
的关系。可见,父类更通用、更一般,子类更具体。
class A{
//属性、方法
}
class B extends A{
}
继承中的基本概念:
必须
和父类被重写的方法具有相同的方法名称
、参数列表
。不能大于
父类被重写的方法的返回值类型。(例如:Student < Person)。注意:如果返回值类型是基本数据类型和 void,那么必须是相同
不能小于
父类被重写的方法的访问权限。(public > protected > 缺省 > private)注意:① 父类私有方法不能重写 ② 跨包的父类缺省的方法也不能重写
此外,子类与父类中同名同参数的方法必须同时声明为非 static 的(即为重写),或者同时声明为 static 的(不是重写)。因为 static 方法是属于类的,子类无法覆盖父类的方法。
子类在继承父类以后,就获取了父类中声明的所有的方法。但是,父类中的方法可能不太适用于子类,换句话说,子类 需要对父类中继承过来的方法进行覆盖、覆写的操作。
举例(银行账户):
class Account{//账户
double balance;//余额
//取钱
public void withdraw(double amt){
//判断balance余额是否够amt取钱的额度
}
}
class CheckAccount extends Account{ //信用卡
double protectedBy;//透支额度
public void withdraw(double amt){
//判断balance余额是否够amt取钱的额度
//如果不够,还可以考虑从protectedBy额度里取
}
}
class AccountTest{
public static void main(String[] args){
CheckAccount acct = new CheckAccount();
acct.withdraw(); //执行的是子类重写父类的方法
}
}
重载:“两同一不同”
重写:继承以后,子类覆盖父类中同名同参数的方法
super 的理解:父类的
在 Java 类中使用 super 来调用父类中的指定操作:
注意:
使用 super 关键字即可。
① 子类继承父类时,不会继承父类的构造器。只能通过“super(形参列表)”的方式调用父类指定的构造器。
② 规定:“super(形参列表)”,必须声明在构造器的首行。
③ 我们前面讲过,在构造器的首行可以使用"this(形参列表)",调用本类中重载的构造器, 结合 ②,结论:在构造器的首行,"this(形参列表)" 和 "super(形参列表)"只能二选一。
④ 如果在子类构造器的首行既没有显示调用"this(形参列表)",也没有显式调用"super(形参列表)", 则子类此构造器默认调用"super()",即调用父类中空参的构造器。
⑤ 由 ③ 和 ④ 得到结论:子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器。 只能是这两种情况之一。
⑥ 由 ⑤ 得到:一个类中声明有 n 个构造器,最多有 n-1 个构造器中使用了"this(形参列表)", 则剩下的那个一定使用"super(形参列表)"。
我们在通过子类的构造器创建对象时,一定在调用子类构造器的过程中,直接或间接的调用到父类的构造器。 也正因为调用过父类的构造器,我们才会将父类中声明的属性或方法加载到内存中,供子类对象使用。
子类继承父类以后,我们就可以在子类的方法或构造器中,调用父类中声明的属性或方法。(满足封装性的前提下)
如何调用呢?需要使用"super."的结构,表示调用父类的属性或方法。
一般情况下,我们可以考虑省略"super."的结构。但是,如果出现子类重写了父类的方法或子父类中出现了同名的属性时, 则必须使用"super."的声明,显式的调用父类被重写的方法或父类中声明的同名的属性。
this:当前对象
super:引用父类声明的成员
2、this 和 super 的使用格式
如何理解多态 :
生活举例:
女朋友:我想养一个宠物。 孩子:我想要一个玩具。 老板:张秘书,安排一个技术科的同事,跟我一起下周出差。
多态性,是面向对象中最重要的概念,在 Java 中的体现:**对象的多态性:父类的引用指向子类的对象**
格式:(父类类型:指子类继承的父类类型,或者实现的接口类型)
父类类型 变量名 = 子类对象;
举例:
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
对象的多态:在 Java 中,子类的对象可以替代父类的对象使用。所以,一个引用类型变量可能指向(引用)多种不同类型的对象
Java 引用变量有两个类型:编译时类型
和运行时类型
。编译时类型由声明
该变量时使用的类型决定,运行时类型由实际赋给该变量的对象
决定。简称:编译时,看左边;运行时,看右边。
多态的使用前提:① 类的继承关系 ② 方法的重写
弊端:
好处:
举例:
class Account{
public void withdraw(){} //取钱
}
class CheckAccount extends Account{ //信用卡
//存在方法的重写
public void withdraw(){} //取钱
}
class SavingAccount extends Account{ //储蓄卡
//存在方法的重写
}
class Customer{
Account account;
public void setAccount(Account account){
this.account = account;
}
public Account getAccount(){
return accout;
}
}
class CustomerTest{
main(){
Customer cust = new Customer();
cust.setAccount(new CheckAccount());
cust.getAccount().withdraw();
}
}
首先,一个对象在 new 的时候创建是哪个类型的对象,它从头至尾都不会变。即这个对象的运行时类型,本质的类型用于不会变。但是,把这个对象赋值给不同类型的变量时,这些变量的编译时类型却不同。
为什么要类型转换:
因为多态,就一定会有把子类对象赋值给父类变量的时候,这个时候,在编译期间
,就会出现类型转换的现象。
但是,使用父类变量接收了子类对象之后,我们就不能调用
子类拥有,而父类没有的方法了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做类型转换,使得编译通过
。
向上转型:自动完成
向下转型:(子类类型)父类变量
package com.atguigu.polymorphism.grammar;
public class ClassCastTest {
public static void main(String[] args) {
//没有类型转换
Dog dog = new Dog();//dog的编译时类型和运行时类型都是Dog
//向上转型
Pet pet = new Dog();//pet的编译时类型是Pet,运行时类型是Dog
pet.setNickname("小白");
pet.eat();//可以调用父类Pet有声明的方法eat,但执行的是子类重写的eat方法体
// pet.watchHouse();//不能调用父类没有的方法watchHouse
// 向下转型
Dog d = (Dog) pet;
System.out.println("d.nickname = " + d.getNickname());
d.eat();//可以调用eat方法
d.watchHouse();//可以调用子类扩展的方法watchHouse
Cat c = (Cat) pet;//编译通过,因为从语法检查来说,pet的编译时类型是Pet,Cat是Pet的子类,所以向下转型语法正确
//这句代码运行报错ClassCastException,因为pet变量的运行时类型是Dog,Dog和Cat之间是没有继承关系的
}
}
instanceof 的使用:
为了避免 ClassCastException 的发生,Java 提供了instanceof
关键字,给引用变量做类型的校验。如下代码格式:
//检验对象a是否是数据类型A的对象,返回值为boolean型
对象a instanceof 数据类型A
代码:
package com.atguigu.polymorphism.grammar;
public class TestInstanceof {
public static void main(String[] args) {
Pet[] pets = new Pet[2];
pets[0] = new Dog();//多态引用
pets[0].setNickname("小白");
pets[1] = new Cat();//多态引用
pets[1].setNickname("雪球");
for (int i = 0; i < pets.length; i++) {
pets[i].eat();
if(pets[i] instanceof Dog){
Dog dog = (Dog) pets[i];
dog.watchHouse();
}else if(pets[i] instanceof Cat){
Cat cat = (Cat) pets[i];
cat.catchMouse();
}
}
}
}
类java.lang.Object
是类层次结构的根类,即所有其它类的父类。每个类都使用 Object
作为超类。
==和 equals 的区别: