Java笔记6 多态,抽象类,接口和Final

文章详细阐述了Java中的多态特性,包括父类引用可以指向子类对象,但不能反向赋值。讨论了抽象类的概念,指出抽象类不能实例化,但可以有构造方法,用于子类继承。同时提到了final关键字的使用,如修饰类、方法和变量,以及接口的作用和特性。文章强调了面向抽象编程的重要性和多态在降低耦合度、提高扩展性方面的价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 多态:父类型引用指向子类型对象
  • 多态注意事项
  1. 子类对象可以直接赋给父类引用,但父类对象在任何情况下都不可以直接赋给子类引用,因为子类是父类的一种,但父类不是子类的一种,或者说 子类可以当做父类看待,但父类不可以当做子类看待 , 打个比喻,狗可以当做动物看待,但动物不可以当做狗来看待;
  2. 通过父类引用只能访问子类对象从父类继承过来的成员,不能访问子类对象所特有的成员
  3. 上面说父类引用永远不可能直接赋给子类引用,有一个特殊情况,只有在父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化为子类引用,其他情况下不允许把父类引用强制转化为子类引用,否则运行时会出错
  4. 代码演示:
public class Test
{
	public static void main(String[] args){
		A aa=new A();
		B bb=new B();
        //bb=aa;//error
		bb=(B)aa;//编译没有错误,但运行时出错

		A aa2=new B();
		bb=aa2;//error 永远不可以把父类引用直接赋给子类引用
		bb=(B)aa2;  //OK 因为aa2本身指向的就是一个B类对象(子类对象)
	}
}
class A
{
}
class B extends A
{
}

错误原因:
在这里插入图片描述

  • 多态在实际开发中的作用:降低程序的耦合度,提高程序的扩展力
  • 抽象类与抽象方法
    在这里插入图片描述
public class Poly {
    public static void main(String[] args) {

    }
}
//有抽象方法的类一定是抽象类
abstract class B
{
    public abstract void f();//没有方法体
}
//抽象类不一定有抽象方法
abstract class C
{
    public void g()
    {
    }
}
  1. 抽象类的由来:利用抽象类是为了更好的对类加以分类,就像人类不但给各种具体植物取了名字,还发明了“植物”这个抽象的词对所有具体植物进行归类一样
  2. Java用来模拟现实世界,所以也存在抽象类,抽象类通常用来作为一个类族的最顶层的父类,用最底层的类表示现实中的具体事物,用最顶层的类表示该类族所有事物的共性,就好像生物分为动物和植物,动物又分为高级动物和低级动物等等,通常最上面的若干层类都是抽象的。
package com.ittanya.demo1;

public class AbsPoly{
    public static void main(String[] args) {
        //C cc=new C();//错误
        B bb = new B();
        bb.f();
        C cc;//可以定义一个抽象类的引用,但是不可以定义一个抽象类的对象
        cc = bb;
        bb.f();
    }
  }

abstract class C
{
    abstract public void f();
    //public abstract void g();//报错
}
class B extends C
{
    public void f(){
        System.out.println("BBBB");
    }
}

几种错误**:**
在这里插入图片描述
在这里插入图片描述

  • Final关键字的使用:
  1. 修饰整个类:
    在这里插入图片描述
  2. Final修饰类中的若干属性:
    在这里插入图片描述
package com.ittanya.demo1;

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

    }
}
class B
{
    final public int i;//常变量=const
    //但不能同时有两个赋值语句
    public B()//在构造方法中赋值,不报错
    {
        i=99;
    }
    /*public void f()  报错
    {
        i=22;
    }*/
}

注意:默认值不算真正的赋值
3. Final修饰类中的若干个方法:
![在这里插入图片描述](https://img-blog.csdnimg.cn/7d50dc74d16b465cbab3522eac82c319.png

  • 接口
    在这里插入图片描述
    在这里插入图片描述
  • 接口的作用:
    在这里插入图片描述
package com.ittanya.demo1;

interface It{
    //接口中定义的属性的值在实现类中不能被更改
    //接口的属性是public static final 类型
    public static final int i=20;//冗余
    public abstract void f();//冗余
}

//接口中是不可以定义构造函数的
interface It1{
    int i=20; //不能改为 int i;
    void f();
}

//接口可以多重继承,即一个接口可以有多个父接口,但是一个类只能有一个父类
interface It2 extends It,It1{
}

//implements不能改为extends 因为类可以继承类,但类不能继承接口,逻辑意义不通,但类可以实现接口
class T implements It1{
    public T(int j){
        //this.i=j;//无法将值赋给 final 变量 'i'
        //接口It中的属性i是public static final 类型
        j=20;
        System.out.println(j);
        System.out.println("父类");
    }
    public void f(){
        System.out.println(i);
    }
}

//一个类可以在继承一个父类的同时实现一个或多个接口,但extends关键字必须在前
class T1 extends T implements It,It1{

    public T1(int j) {
        super(10);
        System.out.println("子类");
    }
}
class 接口 {
    public static void main(String[] args) {
        T tt=new T(30);
        tt.f();
    }
}

运行结果:
在这里插入图片描述

package com.ittanya.demo1;

interface It{
    void f();
}

abstract class T implements It{
    public void f(){
        System.out.println("AAAA");
    }
}

class 接口 {
    public static void main(String[] args) {
        int i;
        It it;
        It it1=new It() {
            @Override
            public void f() {
                System.out.println("TTTT");
            }
        };
        it1.f();
    }
}

运行结果:
在这里插入图片描述
- 接口与抽象类区别:

  1. 接口中的方法不允许有方法体,但抽象类却允许
  2. Java类不允许多承,接口却允许多继承
    (接口可以实现多继承,即一个接口可以有多个父类
    但Java类只允许单继承,即一个类只能有一个父类)

- 杂七杂八:
3. Animala5=new Cat(); //底层对象是一只猫
// 分析这个程序能否编译和运行呢?
分析程序一定要分析编译阶段的静态绑定和运行阶段的动态绑定,
只有编译通过的代码才能运行。没有编译,根本轮不到运行。

// 错误:找不到符号
// why???
因为编译器只知道a5的类型是Animal,去Animal,class文件中找catchMouse()方法
//结果没有找到,所以静态绑定失败,编译报错。无法运行。(语法不合法)

a5.catchMouse :
假设代码写到了这里,非要调用catchMouse()方法怎么办?
//这个时候就必须使用”向下转型”了。(强制类型转换)

//以下这行代码头啥没报错????
//因为a5是Animal类型,转成Cat,Animal和Cat之间存在继承关系。所以没报错
Cat x=(Cat)a5.x.catchMouse();
//猫正在抓老鼠!! ! !
  1. 类到对象是实例化。对象到类是抽象。

  2. 抽象类:

    1、什么是抽象类?
    类和类之间具有其同特征形成的就是抽象类,
    将这些共同特征提取出来,形成的类就是抽象类,类本身是不在在的,所以抽象类无法创建对象(无法实例化)。

    2、抽象类属于什么类型?
    抽象类也属于引用教据类型。

    3、抽象类怎么定义?
    语法: [修饰符列表] abstract class 类{

          类体:
    

    }
    4、抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。

    5、final和abstract不能联合使用,这两个关键字是对立的。

    6、抽象类的子类可以是抽象类。也可以是非抽象类。

    7、抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。

    8、抽象类关联到一个概念:抽象方法
    什么是抽象方法呢?
    抽象方法表示没有实现的方法,没有方法体的方法。例如:
    public abstract void dosome();

    抽象方法特点是:
    特点1:没有方法体,以分号结尾。
    特点2:前面修饰符列表中有abstract关键字。

    9、抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中

    10、重要结论(五颗星):

    一个非抽象的类继承抽象类,必须将抽象类中的抽象方法实现了,这是java语法上强行规定的,必须的,不然编译器就报错了
    这里的覆盖或者说重写,也可以叫做实现。(对抽象的实现)

  3. 面试题(判断题): java语言中凡是没有方法体的方法都是抽象方法

    错误。
    object类中就有很多方法都没有方法体,都是以”;"结尾的,但他们都不是抽象方法,例如:
    public native int hashCode() ;
    这个方法底层调用了c++写的动态链接库程序。前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。

  4. 代码演示1:

public class AbstractTest02{
     public static void main(string[] args){
// 能不能使用多态
// 父类型引用指向子类型对象
    Animal a=new Bird(); 
    //向上转型。(自动类型转换)

// 这就是面向抽象编程。
//以后你都是调用的a.xxxx
// a的类型是Animal,Animal是抽象的
// 面向抽象编程,不要面向具体编程,降低程序的耦合度,提高程序的扩展力。这种编程思想符合OCP原则。
//分析以下:
    //编译的时候这个move()方法是谁的?
   //运行的时候这个move()方法又是谁的?
    a.move();
   }
}
  1. 代码演示2:
package com.ittanya.demo1;

abstract class Animal1{
    public abstract void move();
}
//子类(非抽象的)
// 错误: Bird不是抽象的,并且未覆盖Anima1中的抽象方法move()
/*
class Bird extends Animal1{
}
*/
class Bird extends Animal1{
    public void move(){
        System.out.println("鸟儿在飞翔!");
    }
}
class Cat1 extends Animal1{
    public void move(){
        System.out.println("猫在走猫步!");
    }
}
// 如果Bird是抽象类的话,那么这个Animal中继承过来的抽象方法也可以不去重写/覆盖/实现
abstract class Bird1 extends Animal1{
}
  1. final关键字:

1.1、final修饰的类无法继承。

1.2、fina1修饰的方法无法覆益。

1.3、final修饰的变量只能赋一次值。

1.4、final修饰的引用一指向某个对象,则不能再重新指向其它对象,但该引用指向的对象内部的数据是可以修改的。

1.5final修饰的实变量必须手动初始化,不能采用系统默认值。

1.6、fina1修饰的实例变量一般和static联合使用,称为常量,如:
public static final double PI =3.1415926;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值