继承:指一个对象直接使用另一对象的属性和方法 继承的作用: 基本作用:子类继承父类,代码可以得到复用。 主要(重要)作用:因为有了继承关系,才有了后期的方法覆盖和多态机制。
① B类继承A类,则称A类为超类(superclass)、父类、基类,
B类则称为子类(subclass)、派生类、扩展类。
class A{}
class B extends A{}
我们平时聊天说的比较多的是:父类和子类。
superclass 父类
subclass 子类
② java 中的继承只支持单继承,不支持多继承,C++中支持多继承,
这也是 java 体现简单性的一点,换句话说,java 中不允许这样写代码:
class B extends A,C{ } 这是错误的。
③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,
例如:class C extends B,class B extends A,也就是说,C 直接继承 B,
其实 C 还间接继承 A。
④ java 中规定,子类继承父类,除构造方法不能继承之外,剩下都可以继承。
但是私有的属性无法在子类中直接访问。(父类中private修饰的不能在子类中
直接访问。可以通过间接的手段来访问。)
⑤ java 中的类没有显示的继承任何类,则默认继承 Object类,Object类是
java 语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有
Object类型中所有的特征。
⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它
们之间的耦合度非常高,Account 类发生改变之后会马上影响到 CreditAccount 类
什么时候可以使用继承? 能使用“is a”关系可描述清楚。
什么是方法覆盖? 当子类继承父类后,继承过来的方法无法满足子类的需求,子类将这个方法进行重写。 将继承过来的方法进行覆盖,执行覆盖后的方法。
方法覆盖满足的条件:
注意事项:
代码演示:
/**
* 父类:动物类
*/
class Animal{
private String name;
//无参构造方法
public Animal() {
}
//有参构造方法
public Animal(String name) {
this.name = name;
}
//动物具有吃东西的方法
public void eat(){
}
}
/**
* 猫继承动物类 猫是动物
*/
class Cat extends Animal{
//无参构造方法
public Cat(){
}
//猫类重写父类eat()方法!
public void eat(){
System.out.println("猫吃猫粮!");
}
}
/**
* 狗继承动物类 狗是动物
*/
class Dog extends Animal{
//无参构造方法
public Dog(){
}
//狗类重写父类的eat()方法!
public void eat(){
System.out.println("狗吃狗粮!!");
}
}
/**
1. 测试类
*/
public class Demo {
public static void main(String[] args) {
//创建猫对象
Cat cat=new Cat();
//猫吃东西
cat.eat();
//创建狗对象
Dog dog=new Dog();
//狗吃东西
dog.eat();
}
}
多种形态,多种状态,编译和运行有两个不同的状态。
编译期叫做静态绑定。
运行期叫做动态绑定。
Animal a = new Cat();
// 编译的时候编译器发现a的类型是Animal,所以编译器会去Animal类中找move()方法
// 找到了,绑定,编译通过。但是运行的时候和底层堆内存当中的实际对象有关
// 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。
a.move();
多态的典型代码:父类型的引用指向子类型的对象。
向上转型和向下转型的概念:
向上转型:子--->父 (upcasting)
又被称为自动类型转换:Animal a = new Cat();
向下转型:父--->子 (downcasting)
又被称为强制类型转换:Cat c = (Cat)a; 需要添加强制类型转换符。
什么时候需要向下转型?
需要调用或者执行子类对象中特有的方法。
必须进行向下转型,才可以调用。
向下转型有风险吗?
容易出现ClassCastException(类型转换异常)
怎么避免这个风险?
instanceof运算符,可以在程序运行阶段动态的判断某个引用指向的对象
是否为某一种类型。
养成好习惯,向下转型之前一定要使用instanceof运算符进行判断。
不管是向上转型还是向下转型,首先他们之间必须有继承关系,这样编译器就不会报错。
代码演示:
public class OverrideTest05{
public static void main(String[] args){
// 静态方法可以使用“引用.”来调用吗?可以
// 虽然使用“引用.”来调用,但是和对象无关。
Animal a = new Cat(); //多态
// 静态方法和对象无关。
// 虽然使用“引用.”来调用。但是实际运行的时候还是:Animal.doSome()
a.doSome();
}
}
class Animal{
// 父类的静态方法
public static void doSome(){
System.out.println("Animal的doSome方法执行!");
}
}
class Cat extends Animal{
// 尝试在子类当中对父类的静态方法进行重写
public static void doSome(){
System.out.println("Cat的doSome方法执行!");
}
}
类型向下转型时,必须使用instanceof进行判断。 强调:
引用 instanceof 类型
C instanceof Cat
为true,则C引用指向堆内存Java对象为一个Cat,如果为False 说明不是一个Cat代码演示:
/**
* 父类:动物类
*/
class Animal{
public Animal() {
}
//动物具有吃东西的方法
public void eat(){
}
}
/**
* 猫继承动物类 猫是动物
*/
class Cat extends Animal {
public Cat() {
}
//猫类重写父类eat()方法!
public void eat() {
System.out.println("猫吃猫粮!");
}
public void run(){
System.out.println("猫在走猫步");
}
}
/**
* 狗继承动物类 狗是动物
*/
class Dog extends Animal{
public Dog(){
}
//狗类重写父类的eat()方法!
public void eat(){
System.out.println("狗吃狗粮!!");
}
public void run(){
System.out.println("狗仔跳墙!1");
}
}
/**
* 测试类
*/
public class Demo {
public static void main(String[] args) {
//向下转型:父类调用子类特有的方法。
Animal animal=new Cat();
Animal animal1=new Dog();
//必须使用instanceof进行判断
if(animal instanceof Cat) {
Cat c=(Cat) animal;
c.run();//子类特有
}else if (animal1 instanceof Dog){
Dog d=(Dog) animal1;
d.run();//子类特有
}
}
}
什么时候super不能省略? 如果父与子类有相同的属性,想在子类中访问父类的特征。 代码演示:
//书
public class Book {
//书名
String name;
//构造方法
public Book(){
super();
}
public Book(String name){
super();
this.name = name;
}
}
//纸质书
public class PaperBook extends Book {
//构造方法
public PaperBook(){
super();
}
public PaperBook(String name){
super();
this.name = name;
}
//打印书名
public void printName(){
System.out.println("this.name->书名 : " + this.name);
System.out.println("super.name->书名 : " + super.name);
}
}
public class BookTest {
public static void main(String[] args) {
PaperBook book1 = new PaperBook("零基础学 Java 卷 I");
book1.printName();
}
}
通过以上内存结构图发现 this.name 和 super.name 实际上是同一块内存空间,所以它们输出结果是完全一样的。 如果在子类中加一个name属性呢?
//纸质书
public class PaperBook extends Book {
String name; //在子类中也定义了一个 name 属性
//构造方法
public PaperBook(){
super();
}
public PaperBook(String name){
super();
this.name = name;//这里的 this.name 代表子类的 name
}
//打印书名
public void printName(){
System.out.println("this.name->书名 : " + this.name);
System.out.println("super.name->书名 : " + super.name);
}
}
父类 Book 的构造方法在执行的时候给 super.name 赋值null,子类 PaperBook 的构造方法在执行的时候给 this.name 赋值“零基础学 Java 卷 I”,由于在子类 PaperBook 中定义了重名的变量 name 导致在当前对象中有两个 name,一个是从父类中继承过来的,一个是自己的,如果此时想访问父类中继承过来的 name 则必须使用 super.name,当直接访问 name 或者 this.name 都表示访问当前对象自己的 name。