学习大数据的第11天——Java面向对象知识(重写、关键字final、abstract以及多态)

从面向对象开始,就开始需要理解一些难理解的知识点了,不过不要放弃!!!!

重写(补充一些遗漏的知识点)

方法重写的注意事项:
1、父类中私有的方法不能被重写
2、子类重写父类的方法时候,访问权限不能更低,要么子类重写的方法访问权限比父类的访问权限要高或者一样,建议:以后子类重写父类的方法的时候,权限修饰符写一样就不会发生这样的问题。
3、父类中静态的方法不能被重写,也就是说不能被Override修饰,因为静态的是属于类本身的东西。

根据例题进行理解:新手机时旧手机的子类

class OldPhone1{
    private String name;

    public void call(String name) {
        System.out.println("打电话给" + name);
    }
    public static void play(){
        System.out.println("玩俄罗斯方块");
    }
}

class NewPhone1 extends OldPhone1{
    @Override
    public void call(String name){
        //在子类重写的方法,想要调用父类中的方法,运用关键字super.成员
        super.call(name);
        System.out.println("看抖音");
    }

    //说明被static关键字修饰的方法不能重写
//    @Override
    public static void  play(){
        System.out.println("玩王者荣耀");
    }
}
public class ExtendsDome1 {

    public static void main(String[] args) {
        NewPhone1 n1 = new NewPhone1();
        n1.call("XXX");
        //这不算重写,这算是在子类的独有方法
        //可以根据原先static的知识,用类名直接访问方法
        NewPhone1.play();
    }
}

再看看下面的运行结果是什么(也就是常说的看程序写结果)

class A1{
    //将父类中的静态成员看作一个全局共享的,被所有的子类共享
    public static int a = 10;

    public static void fun(){
        System.out.println("hello");
    }
}

class B1 extends A1{
    public void fun2(){
        a = 200;
        System.out.println(a);
    }

    public static void fun(){
        System.out.println("world");
    }
}


public class ExtendsDemo2 {
    public static void main(String[] args) {
        B1 b = new B1();
        System.out.println(b.a);//10
        b.fun();//world
        b.fun2();//200
        System.out.println(b.a);//200
        System.out.println(A1.a);//200

    }
}

final关键字

final的特点:
final:最终的的意思。它可以修饰类,成员变量,成员方法

​ 特点:
​ 1、修饰类,类不能被继承
​ 2、修饰成员变量,变量变常量,并且只能赋值一次,在构造方法完毕之前赋值即可。
​ 常量:
​ 字面值常量
​ 自定义常量:被final修饰变量变成自定义常量
​ 3、final修饰成员方法:方法不能被重写

面试题:
final修饰局部变量
1、在方法内部,修饰基本数据类型的变量,变量值只能赋值一次,不能发生改变
2、final修饰引用数据类型的变量呢?
引用的地址值不可以发生改变你,但是该对象的堆内存中的值是可以发生改变的。

class Fu3 {
    int num = 10;

    public void show1(){
        num = 100;
    }
}

class Zi3 extends Fu3 {
    public void show() {
        System.out.println(num);
    }
}

public class FinalDemo2 {
    public static void main(String[] args) {
        final Fu3 f = new Fu3();
        //因为f为final类型的对象,不能在将其他的地址值赋值给f了
        //但是里面的成员变量(不是final类型的)还是可以进行改变
//        f = new Fu3();

        f.show1();
        System.out.println(f.num);
        //z.show();输出为10,说明在子类创建的时候,得先将父类的成员变量初始化以及构造方法运行一遍
        Zi3 z = new Zi3();
        z.show();


    }
}

引入多态的概念:

多态:某一事物,在不同时刻表现出来的不同状态

    举例:
        水:
            固态、液态、气态
            固态的水是水、液态的水也是水、气态的水也是水
        水果:
            波罗蜜、香蕉、榴莲
            波罗蜜是水果、香蕉是水果、榴莲是水果
            水果是波罗蜜。// 反过来说是有问题的
        动物:
            狗、虎、猫、大象
            狗是动物,这么说是没问题的
            动物是狗,这么说是不可以。

   说了这么多,总结出一个思想,这个思想叫做:多态
   通过观察例子发现,要想有多态,就必须要继承,继承是多态的前提。

   多态的前提:
        1、要有继承关系
        2、要有方法的重写。
            其实没有重写也是可以的,但是不重写就没有意义
            动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性
        3、要有父类的引用指向子类对象
            父类名 f = new 子类名(...);

   多态访问成员的特点:
        1、成员变量
            编译看左,运行看左
        2、构造方法
            创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化
        3、成员方法
            编译看左,运行看右。
            因为成员方法存在重写,所以访问看右边
        4、静态成员方法
            编译看左,运行也看左。
            由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的。


    自己的总结:
        多态访问成员变量的特点:
            父类的引用指向子类对象
            父类名称 对象名称 = new 子类名称();
                  左边            右边
            1、成员变量:想要输出f.成员变量时,只会去父类中去找成员变量如果找到就输出,如果没找到,则输出错误
            2、构造方法:在创建的时候,先创建父类的构造方法,再构造子类的方法
            3、成员方法:f.方法名  运行时,编译看左边,运行看右边,意思是:运行方法之前先会去父类的方法中去寻找
                show方法,如果没找到直接报出错误,如果找到的话,则是运行子类的show方法,也想要运行父类的时,加上super.show();
            4、静态的成员方法:static不支持重写,只是单纯的调用父类的静态方法,因为static时类特有的属性,随着类的加载而加载

根据代码进行理解

class Fu4 {
    int num = 100;

    Fu4() {
        System.out.println("这是父类的构造方法");
    }
    //当父类没有这个方法的时候,会报错
//    java: 找不到符号
//    符号:   方法 show()
//    位置: 类型为com.shujia.yl.day11.Fu4的变量 f

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

    public static void fun(){
        System.out.println("这是父类的fun方法");
    }
}

class Zi4 extends Fu4 {
    int num = 1000;

    Zi4() {
        System.out.println("这是子类的构造方法");
    }

    @Override
    public void show() {
        super.show();
        System.out.println("这是子类的show方法");
    }

    public static void fun(){
        System.out.println("这是子类的fun方法");
    }


    //想要直接 f.show2()的方法获取方法是不可以的,因为程序再运行之前回去父类中查到是否有一样的方法,这是多态的弊端
    //但是可以解决:向下类型转换即可
    public void show2() {
        System.out.println("这是子类的特有的方法");
    }

}

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

        Fu4 f = new Zi4();
        //输出父类的成员变量
        System.out.println(f.num);
        f.show();
        //这里static不支持重写,所以这里只是单纯的调用父类的静态方法::::前面说过可以用Fu4.fun();代替
        f.fun();
//        f.show2();
        //向下类型转换
        Zi4 z = (Zi4) f;
        z.show2();
    }
}

尤其记住多态访问成员的特点(很重要很重要很重要)你不记住的话,后面会很晕很晕

多态的前提:(三个缺一不可)
1、要有继承的关系
2、子类要重写父类中的方法
3、父类的引用指向子类对象

多态的弊端:
多态无法使用子类特有的方法
1、我就想使用父类中的方法,能不能用,能。不使用多态
2、如果我想使用子类中的特有方法,还必须使用多态,咋办?
1)就不使用多态,创建子类对象然后调用方法,但是在我上一个例子上,再次创建对象,还会在堆内存中开辟空间,很有可能会造成资源浪费

​ 2)以我们目前的知识,我们还不会,但是我们想一想之前的数据类型。将子类看成一个小的类型,将父类看成一个大的类型,现在想要用小的类型中的方法我们应该要将大的类型转成小的类型。在我们之前的做法是用强制类型转换。 如果在继承关系,也有类似的这样的做法就好了。 java替我们考虑到这样的问题,提供了一个技术给我们使用:
向下转型,将父类的引用强制转换成子类的引用
​ 子类类名 变量名 = (子类类名)父类的引用;

对象之间转型的问题:
1、向上转型:Fu f = new Son();

​ 2、向下转型:Son s = (Son)f;
有点像数据类型的转换,int a = 10;,byte b = (byte)a;

向下转型需要注意的一个问题:
要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。

/*
        向下转型猫狗案例
 */
class Animal2{
    public void eat(){
        System.out.println("吃");
    }
}

class Dog2 extends Animal2{
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

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

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

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

关键字abstract(抽象)

怎么理解abstract呢?
抽象的表述:
我们之前所说的猫,狗,猪,熊猫,老虎等等都是动物具体的例子,而动物本身是一个抽象的概念
但是回想一下我们之前都是将动物写成了一个具体的,而类又可以创建对象,但是实际上抽象的东西本身应该不能被实例化
并且动物中吃的方法应该也不是一个具体的实现,以及所有动物共同拥有的方法在动物中应该都是抽象的表现
我们今天之后,我们把一个不具体的功能,叫做抽象方法,而如果一个类中有抽象方法,我们就把这个类称之为抽象类。

抽象类的特点:
1、抽象类和抽象方法都要用一个关键字修饰:abstract
修饰一个类 放在class的前面
举例: abstract class Animal3{}
修饰一个方法 一般是放在权限修饰符后面
定义一个抽象的show方法
举例:public abstract void show();
2、有抽象方法的类一定要是抽象类,抽象类不一定要有抽象方法,具体的类中不能有抽象方法,抽象类中既可以存在抽象方法
也可以存在有方法体的方法。
3、抽象类不能被实例化
既然不能被实例化,那写在抽象类中的方法如何被调用呢?
抽象类如何创建呢?
通过多态的形式,使用具体的子类去实例化调用方法,专业术语称之为:抽象多态
4、如果继承抽象类的是一个具体的子类,需要重写该抽象类中所有的抽象方法
如果继承抽象的也是一个抽象类,可以不去重写父类中的抽象方法,也可以选择性的去重写。

抽象类的成员的特点:
成员变量:
既可以是变量,也可以是常量
构造方法:
可以存在构造方法,我们上一个程序中,才总结出抽象类不能被实例化,这里构造方法意义是什么?
我们之前在继承中还说过要想初始化子类,必须先初始化父类,所以这里构造方法是提供初始化父类的作用
成员方法:
可以是抽象方法,但是具体的子类必须要重写该方法
也可以不是抽象方法,提高代码的复用性。

abstract关键字不能和哪些关键字共存?
private
static
final

学习总结(至此面向对象的三大特征介绍完了,后面还会学习接口的知识,所以我们先来个面向对象的总结1.0—):

面向对象的三大特征:
封装、继承、多态、

一、封装:隐藏类中的属性,提供公共的方法给外界
1、private 私有,它可以修饰成员变量,构造方法,成员方法
一个标准类1.0:
成员变量:被private
成员方法:getXxx()和setXxx()
show(): 遍历所有成员变量值

2、this关键字
一个标准类2.0:
给变量名起名讲究见名之意,为了可以去调用当前对象中的成员变量,我们引出了this
this代表的是调用方法的当前对象

3、构造方法
为了创建对象
1、可以发生重载
2、可以给成员变量进行初始化值
一个标准类的3.0
成员变量:使用private关键字修饰
构造方法:一个无参构造方法/一个带所有参数的构造方法
成员方法:getXxx()/setXxx() …
show(): 遍历所有的成员变量值

4、static
可以被所有类的对象共享的成员,使用static修饰
特点:可以直接通过类名.静态成员的方式调用
随着类的加载而记载的,也称之为类成员

二、继承:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
1、定义语句格式
class A{}
class B extends A{}
B称之为子类,或者派生类
A称之为父类,超类或者基类

2、java中类只支持单个继承,不支持一次继承多个类,但是可以多层继承
3、super关键字,在子类要想访问父类的成员,就是用super关键字
super可以访问父类非私有成员变量,构造方法,成员方法
this也可以访问本类非私有成员变量,构造方法,成员方法
面试题:this与super的区别?
4、要想初始化子类必须先初始化父类。
5、重写:是发生在继承的关系中
子类重写/覆盖父类中的方法,声明与父类中的一模一样,只是实现不一样而已
面试题:重写与重载的区别/overload和override的区别
6、final关键字:它可以修饰成员变量,成员方法,类
修饰类:类不能被继承
修饰成员变量:变量变自定义常量
修饰成员方法:方法不能被重写
7、final修饰变量的初始化时机
在对象构造完毕前即可
8、多态:
多态的前提:
要有继承关系
要有方法的重写
要有父类的引用指向子类的对象

多态访问成员的特点:****
成员变量:编译看左,运行看左
​ 成员方法:编译看左,运行看右
​ 静态成员方法:编译看左,运行也看左
**

​ 多态的弊端:不能访问子类特有的方法

解决方案:向下转型

​ 关键字abstract,它可以修饰类,方法
​ 1、抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类
​ 2、抽象类不能被实例化
​ 3、要想实例化抽象类,必须用一个具体的子类继承它
​ 注意:具体的子类继承抽象类,必须重写该抽象类中的所有的抽象方法
​ 4、最终以抽象多态的形式进行实例化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值