JAVA学习---面向对象之继承·多态

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/qq_37757008/article/details/81408567 https://blog.csdn.net/qq_37757008/article/details/83061077

这周六我们学习了面向对象的一些知识,包含继承和多态的。
以下是我学过后的心得总结:

封装:

即将构造方法,成员变量,成员方法封装在一起,形成一个类class文件,实现调用。


继承:

  • 继承概述
    继承即多个类中存在相同的属性和行为时,我们可以将这些内容抽取到单独的一个类中,这个类即父类,剩余的类则无需再定义这些属性和行为,只需继承那个类即可,这些类就是父类的子类。

  • 继承语法

    class 子类名 extends 父类名{}

  • 继承特点
    1.JAVA类只支持单继承,但支持多层继承。
    2.子类只能继承父类所有非私有成员(成员方法和成员变量)。
    3.子类不能继承父类的构造方法,但是我们可以通过super关键字去访问父类的构造方法。
    4.子类在创建对象时,一定会先初始化父类的数据(执行父类的空参构造)。
    5.Object类是所有类的顶层父类,所有类都是直接或间接继承与它。

  • 继承的利弊
    1.优点:提高了代码的复用性和维护性,同时让类鱼类之间产生了关系,这是多态的前提。
    2.弊端:类的耦合性增强了。而我们开发的原则是高内聚,低耦合。

  • this和super的区别和应用
    this 代表的是本类对象的引用;
    super 代表的父类存储空间的标识,是父类的引用,可以操作父类的成员。

现在我们来看一个代码,它结合了继承的运用,同时体现了super和this的区别。

public class Fu {
    int num = 100;
    int num2=50;
    public void fu(){
        System.out.println("我是父类");
    }
}
public class Zi extends Fu {
    int num = 10;
    int c = 666;
    public void show(int num) {
        num = 123;
        System.out.println(num);
        System.out.println(this.num);
        //当子类的成员变量和父类重名的时候,可以用一个关键super来区分
        //this 代表本类的引用。
        //super 代表父类空间的一个表示,你可以通过super可以访问父类的成员变量 成员方法,构造方法
        System.out.println(super.num);
        System.out.println(c);
        System.out.println(num2);
    }

    public void hehe() {
        //调用父类的方法
        this.fu();
        //super访问父类的成员方法
        super.fu();
    }
}
public class Test {
    public static void main(String[] args) {
        //变量的寻找 遵循就近访问原则。先在局部范围找,找到就使用,如果没找到就去本类成员范围找,如果还没找到,就去父类的成员找//
        Zi zi = new Zi();
        zi.show(1);
        zi.hehe();
    } 
}

在这里插入图片描述
从上面的结果看出来子类 Zi 继承了父类 Fu ,test方法最后new了一个子类对象zi用它调用了其自身的show方法和hehe方法,在子类中hehe方法通过this和super方法调用访问fu方法,this是在自己类中找不到了,所以去父类中去找fu方法,super则是直接去父类中寻找fu方法

  • 方法重写
    即子类中出现了和父类一模一样的声明方法(方法名,参数列表,返回值类型),也被称为方法覆盖,方法重写。
    当子类需要父类的功能,而功能主体子类有自己特有的内容时,就用到了方法重写。用这种特性即沿袭了父类的功能,又定义了子类特有的内容。

    扫描二维码关注公众号,回复: 4672050 查看本文章
  • 方法重写的注意事项:
    1.父类中私有方法不能被重写,应为它根本就不能被继承,所以谈不上重写。
    2.子类重写父类方法时,访问权限不能更低,最好与父类一致。
    3.父类的静态方法,子类也必须通过静态方法进行重写。
    重写父类的快捷键 CTRL+O

  • final关键字
    由于继承中有一个方法重写的现象,而有时候我们不想让子类去重写父类的方法,所以我们就用final关键字定义父类,这样子类就没法继承了。

    final修饰特点:
    修饰类: 被修饰类不能被继承
    修饰方法: 被修饰的方法不能被重写
    修饰变量: 被修饰的变量不能被重新赋值

  • 代码块
    在Java中,使用{}括起来的代码被称为代码块。
    根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块等等。
    a:局部代码块
    在方法中出现;限定变量生命周期,及早释放,提高内存利用率
    b:构造代码块
    在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
    c:静态代码块
    在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。

class Fu {
    static {
        System.out.println("静态代码块Fu"); 
    }

    {
        System.out.println("构造代码块Fu");
    }

    public Fu() {
        System.out.println("构造方法Fu");
    }
}

class Zi extends Fu {
    static {
        System.out.println("静态代码块Zi"); //2
    }

    {
        System.out.println("构造代码块Zi");
    }

    public Zi() {
        System.out.println("构造方法Zi");
    }
}

public class Test8 {

    static {
        System.out.println("测试类的静态代码块");
    }

    static {
        System.out.println("测试类的静态代码块2");
    }

    public static void main(String[] args) {
        Zi z = new Zi();
    }
}

实验结果:
在这里插入图片描述

由上面的实验结果我们可以看出,相同等级下,构造代码块优先于构造方法执行,每创建一次对象,都要执行,而静态代码块,随着类的加载而加载,只执行一次。


多态

  • 概念
    某一个事物,在不同时刻表现出来的不同状态。

Cat c=new Cat(); //猫可以是猫的类型。
Animal a=new Cat(); //猫也是动物的一种

  • 多态前提
    1.要有继承关系,否则谈不上多态。
    2.要有方法重写,没有也可以,但是如果没有就没有多态的意义。
    3.要有父类引用指向子类对象。

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

  • 多态的利弊
    首先多态提高了代码的维护性,这由继承的特性保证。其次提高了代码的拓展性,这是由多态保证。
    但是多态不能使用子类的特有功能,我们必须通过向下转型来解决此问题。

而向下转型也是有风险的,时常不注意时就会犯类型转换异常的错误,下面我们为您用一个例子来看看空指针异常的错误原理。

//父类定义Fu
public class Fu {

    public void show(){
        System.out.println("fu show");
    }
}
//子类定义Zi,同时定义了子类独有的方法ziMethod()
public class Zi extends Fu {							//继承了父类Fu

    @Override
    public void show() {
        System.out.println("zi show");
    }

    //提供一个子类独有的方法
    public void ziMethod(){
        System.out.println("我是子类一个特有的一个方法");
    }
}
//子类定义Son,同时定义了子类独有的方法sonMethod()
public class Son extends Fu{  					//继承了父类Fu

    @Override
    public void show() {
        System.out.println("son  show");
    }

    **public void sonMethod(){
        System.out.println("我是Son 里面的一个特有的方法");
    }**
}

按照多态的特性,父类引用指向子类的方法,父类不能使用子类的特有方法,我们需要向下转型。

public class Test5 {
    public static void main(String[] args) {
        Fu fu = new Zi();
        //fu.ziMethod();                                 这里就会报错
        //向下转型
        Zi zi = (Zi) fu;
        zi.ziMethod();
        fu = new Son();
        fu.show();
        Son son = (Son) fu;
        son.sonMethod();
        System.out.println("---------------------------");
        Fu fu1 = new Zi();
        Zi zi1 = (Zi) fu;						//ClassCastException 类型转换异常
        zi1.ziMethod();
        Son son1 = (Son) fu1;
        son1.sonMethod();
    }
}

在这里插入图片描述
从以上结果我们可以看出,这个测试类就犯了类型转换异常,而原理就是
fu = new Son();
fu.show();
Son son = (Son) fu;

在这里我们先把fu对象向下转型为了Son类型的对象,而在后面我们又
Zi zi1 = (Zi) fu;
zi1.ziMethod();

要把fu对象向下转型为Zi类对象,而它在上面已经被转型为Son的对象,Son和Zi都属于子类,不存在直接的继承关系,所以无法转型,而我们新定义的
Fu fu1 = new Zi();
fu1就可以向下转型为son,从而调用son特有的方法sonMethon();


猜你喜欢

转载自blog.csdn.net/qq_37757008/article/details/83061077