Java基础(9)继承、final关键字、多态、抽象类

1.面向对象三大特性(2)继承

1. 继承的概述:多个类中存在相同的属性和行为时,将这些内容抽取到单独的父类中,那么这个类无需再定义这些属性和行为,只需要继承这个类即可
2. 继承的格式:class 子类名 extends 父类名{ }
3. 继承的代码示例

public class TestDemo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.age = 5;
        dog.name = "旺财";
        System.out.println(dog.age);
        System.out.println(dog.name);
        dog.eat();
        dog.sleep();
        dog.lookDoor();

        System.out.println("===============");

        Cat cat = new Cat();
        cat.age = 4;
        cat.name = "啦啦";
        System.out.println(cat.age);
        System.out.println(cat.name);
        cat.eat();
        cat.sleep();
        cat.catchMouse();
    }
}


class Animal{
    int age;
    String name;

    public void eat(){
        System.out.println("吃饭");
    }

    public void sleep(){
        System.out.println("睡觉");
    }
}

class Dog extends Animal{

    public void lookDoor(){
        System.out.println("狗看门");
    }
}

class Cat extends Animal{

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

		 //输出结果
		 /*
		 5
		旺财
		吃饭
		睡觉
		狗看门
		===============
		4
		啦啦
		吃饭
		睡觉
		猫抓老鼠
		 */
 

4. 继承的好处:提高了代码的复用性、维护性、让类与类之间产生了关系
5. 继承的弊端:类的耦合性增强了
PS:开发的原则:高内聚,底耦合
6. 继承的特点:
(1)Java只支持单继承,不支持多继承:一个类只有一个父类。但是一个父类可以有多个子类
(2)Java支持多层继承:子类- -父类- -父类

//Son -- Father -- Grandfather
public class TestDemo2 {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.g);  //ggg
        System.out.println(son.f);  //fff
        System.out.println(son.s);  //sss
        son.show();   //爷爷类中的show方法
        son.fuShow();  //父类中的show方法
        son.sonShow();  //Son类中的show方法

    }
}

class Grandfather{
    String g = "ggg";
    public void show(){
        System.out.println("爷爷类中的show方法");
    }
}

class Father extends Grandfather{
    String f = "fff";
    public void fuShow(){
        System.out.println("父类中的show方法");
    }
}

class Son extends Father{
    String s = "sss";
    public void sonShow(){
        System.out.println("Son类中的show方法");
    }

}

7. 继承的注意事项
(1)子类只能继承父类所有非私有的成员(成员方法和成员变量)
(2)构造方法不参与继承

public class TestDemo3 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println(zi.age);  //50
//        zi.name;  //报错 无法访问
//        zi.show();  //报错,无法访问
        zi.show2();  //公共的show方法
    }
}

class Fu{
    private String name = "fu";
    int age = 50;
    private int num = 3000;

    private void show(){
        System.out.println("私有show方法");
    }

    public void show2(){
        System.out.println("公共的show方法");
    }

}

class Zi extends Fu{

}

8. 继承中访问变量的规则
(1)子类的成员变量和父类的成员变量不一样,按照名称访问
(2)子类的成员变量与父类的成员变量一样:就近原则

9. this和super的应用
(1)this代表本类对象的引用,super代表父类存储空间的标识
(2)this和super的使用:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量

public class TestDemo01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.show(20);
    }
}

class Fu{
    int num = 200;
}

class Zi extends Fu{
    int num = 600;

    public void show(int num){
        System.out.println(num);
        System.out.println(this.num);
        System.out.println(super.num);
    }
}

	//输出结果
	/*
	20
	600
	200
	*/

(3)this和super的使用:调用构造方法
有了继承关系后,我们在初始化子类的时候先要初始化父类的数据,即:我们在创建子类对象的时候,要先调用父类的构造方法,来完成父类数据的初始化,然后在初始化自己的数据。在每个类的构造方法中的第一行有一行默认的代码super(),在行代码就去调用父类的空参构造
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法

public class TestDemo02 {
    public static void main(String[] args) {
        Son son = new Son();
        /*
        父类构造方法执行了
		子类构造方法执行了
        */
    }
}


class Father{
    public Father(){
        System.out.println("父类构造方法执行了");
    }

}

class Son extends Father{
    public Son(){
        System.out.println("子类构造方法执行了");
    }
}

(4)this和super的使用:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法

public class TestDemo01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.test();
    }
}

class Fu{
    int fuNum = 200;
    int f = 600;

    public void fuShow(){
        System.out.println("父类的show方法");
    }
}

class Zi extends Fu{
    int num = 20;
    int f = 9000;

    public void ziShow(){
        System.out.println("子类的show方法");
    }

    public void test(){
        System.out.println(super.fuNum);  //200
        System.out.println(super.f);  //600
        System.out.println(this.f);   //9000
        System.out.println(this.num);   //20

        System.out.println("=================");

        ziShow();   //子类的show方法
        super.fuShow();   //父类的show方法
        this.fuShow();    //父类的show方法
    }
}

10. 方法重写
(1)方法重写的概述:子类如果对父类的方法不满意,那么子类可以重写父类中的方法,所以子类中出现了和父类一模一样的方法声明(方法名,参数列表,返回值类型),所以也称为方法覆盖
(2)方法重写的注意事项
①父类中私有的方法不能重写,因为父类中私有的方法根本就不能继承
②子类重写父类方法时,访问权限不能低于父类方法,最好是一样的
③如果还要保留父类的功能,并在此基础上进行扩展,使用super.方法名
④父类的static方法,不能被重写,可以被继承
(3)ctrl+o:在idea中调用方法重写 @Override

public class TestDemo02 {
    public static void main(String[] args) {
        IPhone ip = new IPhone();
        ip.call();  //打视频电话
        ip.sendMsg();   //发短信    发彩信
    }
}

class Phone {
    public void call() {
        System.out.println("打电话");
    }

    public void sendMsg(){
        System.out.println("发短信");
    }

    private void playGame(){
        System.out.println("玩游戏");
    }
}

class IPhone extends Phone{
    @Override
    public void call() {
        System.out.println("打视频电话");
    }

    @Override
    public void sendMsg() {
        super.sendMsg();   //如果还要保留父类的功能,并在此基础上进行扩展,使用super.方法名
        System.out.println("发彩信");
    }

    /*@Override
    public void playGame(){

    }*/   //父类私有方法子类不可以继承
}

2.final关键字

1. final关键字的起源:由于继承中有一个方法重写的现象,但是有时候不想让子类重写父类的方法,所以就引入一个关键字final
2. final关键字概述:final表示最终的,可以修饰类,变量,成员方法
3. final修饰的特点
(1)final修饰类:被修饰的类不能被继承
(2)final修饰成员方法:被修饰的成员方法不能被重写
(3)final修饰变量:被修饰的变量不能被重新赋值,此变量变成一个常量
(4)final修饰局部变量:如果局部变量是基本类型,其值不能改变。如果局部变量是引用类型,其地址值不能改变
4. final关键字的代码示例

public class TestDemo01 {
    public static void main(String[] args) {
        final int NUM = 100;
//        NUM = 200;  //报错,final修饰的变量不能被重新赋值

        Son son = new Son();
        son.show();   //重写了Father类中的show方法
        son.finalShow();    //Father类中被final修饰的方法,子类可以继承,但是不能被重写

        System.out.println("================");

        final Son son1 = new Son();
//        son1 = new Son();  //final 修饰引用类型,指的是 地址值不能再次改变
    }
}


//final 修饰类,此类不能被继承。
final class Fu{
    public void show(){
        System.out.println("Fu类因为被final修饰,所以不能被继承");
    }
}

class Father{
    public void show(){
        System.out.println("Father类的show方法");
    }

    public final void finalShow(){
        System.out.println("Father类中被final修饰的方法,子类可以继承,但是不能被重写");
    }
}

class Son extends Father{
    @Override
    public void show() {
        System.out.println("重写了Father类中的show方法");
    }
}

3.面向对象三大特性(3)多态

1. 多态的概述:某一个事物,在不同时刻表现出来的不同状态
2. 多态的前提
(1)要有继承关系
(2)要有方法重写
(3)要有父类引用指向子类对象:Fu f = new Zi();

public class TestDemo01 {
    public static void main(String[] args) {
    	//多态:父类引用 指向子类对象
        Animal an = new Cat();
        an.eat();   //猫吃鱼
    }
}

class Animal{
    public void eat(){
        System.out.println("吃饭");
    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

3. 多态中的成员访问特点
(1)成员变量:编译看左边,运行看左边
(2)构造方法:创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化
(3)成员方法:编译看左边,运行看右边
(4)静态方法:编译看左边,运行看左边(静态和类相关,算不上重写,所以访问还是看左边的)

public class TestDemo02 {
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num);  //20(Fu类的)
//        System.out.println(f.aaa);  //错误,不能访问子类的成员变量

        f.show();  //子类重写了父类的show方法
        f.fuStatic();   //父类的静态方法
        Fu.fuStatic();  //父类的静态方法
    }
}

class Fu{
    int num = 20;

    public Fu(){
        System.out.println("父类构造方法执行了");
    }

    public void show(){
        System.out.println("父类show方法执行了");
    }

    public static void fuStatic(){
        System.out.println("父类的静态方法");
    }
}

class Zi extends Fu{
    int num = 200;
    int aaa = 10;

    public Zi(){
        System.out.println("子类构造方法执行了");
    }

    @Override
    public void show() {
        System.out.println("子类重写了父类的show方法");
    }
}

		/*
		父类构造方法执行了
		子类构造方法执行了
		20
		子类重写了父类的show方法
		父类的静态方法
		父类的静态方法
		*/

4. 多态的好处
(1)提高代码的维护性(继承)
(2)提高代码的扩展性(多态)

public class TestDemo1 {
    public static void main(String[] args) {
        Animal an1 = new Cat();
        MyUtils.testEat(an1);   //猫吃鱼

        Animal an2 = new Dog();
        MyUtils.testEat(an2);  //狗吃骨头

        Animal an3 = new Rabbit();
        MyUtils.testEat(an3);   //兔子吃萝卜

        Animal an4 = new Panda();
        MyUtils.testEat(an4);   //熊猫吃竹子

    }
}


class Animal{
    public void eat(){
        System.out.println("吃饭");
    }
}


class MyUtils{  //设计一个工具类,调用动物们的eat方法
    private MyUtils(){
        //私有构造不能被实例化
    }

    public static void testEat(Animal an){
        an.eat();
    }

}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}


class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}


class Rabbit extends Animal{
    @Override
    public void eat() {
        System.out.println("兔子吃萝卜");
    }
}


class Panda extends Animal{
    @Override
    public void eat() {
        System.out.println("熊猫吃竹子");
    }
}

5. 多态的向下转型
(1)多态的弊端:不能使用子类特有的功能,所以提出了向下转型,把父类的引用强制转换为子类的引用
(2)向下转型的格式:Zi z = (Zi) f;
(3)向下转型的代码示例

public class TestDemo2 {
    public static void main(String[] args) {
        Fu f = new Zi();
        f.show();    //子类重写了父类的show方法执行了

//        f.showZi();   //多态形式不能直接调用子类特有的方法
//        System.out.println(f.num);   //多态形式也不能直接调用子类的变量

        //向下转型
        Zi z = (Zi) f;
        System.out.println(z.num);  //200
        z.show();     //子类重写了父类的show方法执行了
        z.showZi();   //子类特有的showZi方法执行了
    }
}


class Fu{
    public void show(){
        System.out.println("父类的show方法执行了");
    }
}

class Zi extends Fu{
    int num = 200;

    @Override
    public void show() {
        System.out.println("子类重写了父类的show方法执行了");
    }

    public void showZi(){
        System.out.println("子类特有的showZi方法执行了");
    }
}

(4)猫狗案例

public class TestDemo1 {
    public static void main(String[] args) {
        Animal an = new Cat();
        an.eat();    //猫吃鱼
        Cat c = (Cat) an;  
        c.catchMouse();   //猫抓老鼠

        System.out.println("=================");

        //重新转换对象
        an = new Dog();   
        an.eat();   //狗吃骨头

        Dog d = (Dog) an;
        d.lookDoor();    //狗看门
    }
}

class Animal{
    public void eat(){
        System.out.println("吃饭");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookDoor(){
        System.out.println("狗看门");
    }
}


class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

4.抽象类(上)

1. 抽象类的概述:在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,那么这个类必须是抽象类
2. 使用抽象类的原因:父类把子类共性内容的内容向上抽取出来,但是父类不知道子类对共性内容的具体实现,所以父类只需要给出功能的声明,不需要给出具体的实现,具体的实现交给子类来完成
3. 抽象类的特点
(1)抽象类和抽象方法的定义格式
①抽象类:abstract class 类名{}
②抽象方法:public abstract void 方法名(参数列表){}
(2)抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
(3)抽象类不能直接创建对象
(4)子类必须重写父类的抽象方法

public class TestDemo1 {
    public static void main(String[] args) {
//        Animal an = new Animal()     //抽象类不能直接创建对象

        Animal an = new Cat();
        an.eat();   //猫吃鱼
        an.sleep();   //猫爱白天睡觉

        System.out.println("============");

        an = new Dog();
        an.eat();   //狗吃骨头
        an.sleep();   //狗爱夜里睡觉

    }
}

abstract class Animal{
    public abstract void eat();
    public abstract void sleep();
}

class Cat extends Animal{
    //父类中的抽象方法,是强制子类必须重写
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫爱白天睡觉");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void sleep() {
        System.out.println("狗爱夜里睡觉");
    }
}

(5)抽象类的中的构造方法:在子类访问父类的时候进行初始化
(6)抽象类的实例化:通过多态的方式,由具体的子类进行实例化

public class TestDemo2 {
    public static void main(String[] args) {
        AA a = new BB();
        System.out.println(a.num);  //100
        BB b = (BB) a;
        System.out.println(b.num);  //100
    }
}

abstract class AA{
    int num = 100;
    public AA(){
        System.out.println("AA的构造方法");
    }

    public abstract void aa();
}

class BB extends AA{
    public BB() {
        super();
        System.out.println("BB的构造方法");
    }

    @Override
    public void aa() {
        System.out.println("重写了父类的aa方法");
    }
}

			/*
			AA的构造方法
			BB的构造方法
			100
			100
			*/

(7)抽象类的子类,要么是抽象类,要么重写抽象类中所有的抽象方法

public class TestDemo1 {
    public static void main(String[] args) {
        
    }
}

abstract class BB{
    public abstract void eat();
    public abstract void sleep();
}

abstract class CC extends BB{
    public abstract void haha();
}

class DD extends CC{
    @Override
    public void eat() {
        
    }

    @Override
    public void sleep() {

    }

    @Override
    public void haha() {

    }
}

4. 抽象类的成员特点
(1)成员变量:既可以是变量,也可以是常量
(2)构造方法:有,用于子类访问父类数据的初始化
(3)成员方法:即可以是抽象的,也可以是非抽象的

5. 一个类如果没有抽象方法,也可以定义成抽象类,其目的就是为了不能创建该类的对象

6. abstract不能和几个关键字共存
(1)private(私有的):abstract定义的方法必须强制子类重写,而private修饰的方法是私有的,不能被子类继承,更不能被重写
(2)final(最终的):final修饰的方法,子类不能重写。而abstract必须强制子类重写
(3)static(静态的):static方法属于类,不参与重写。而abstract必须强制子类重写

public class TestDemo01 {
    public static void main(String[] args) {
//        Fu fu = new Fu();    //被abstract修饰的类不能创建对象
    }
}

abstract class Fu{
//    private abstract void method01();  //private不能和abstract共存

//    static abstract void method02();     //static不能喝abstract共存

//    public abstract final void method03();   //final不能和abstract共存
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值