java类和对象:继承、多态、接口、抽象类-2

简介: java类和对象:继承、多态、接口、抽象类

java类和对象:继承、多态、接口、抽象类-1

https://developer.aliyun.com/article/1515765


二、多态

          对于几个不同的类,可以根据他们共同特性,将其抽取出来形成一个共同的父类,这个父类中包含了其他类所具有的共同属性,例如这里有一个狗类,一个猫类,和一个鸟类,他们都有眼睛,都有脚,还可以拥有自己的名字等等静态属性,动态属性,就比如都会吃,喝跑等。


       但是对于不同的动物来说,比如狗和鸟,他们的跑这个行为是不一样的,对于狗来说是用四条腿来跑,而对于鸟来说,只能用两个脚跳,或者用两个翅膀飞,这个行为和狗对比起来是完全不一样的,那么对于其继承的父类来说,不可能只用父类的方法,来描述两个不同的行为,这些行为都是他们的独自的特性。


       这个时候就只需要对其父类的这个方法于子类中进行重写,而不用在每一个子类都实现一个方法,于是就避免了大量重复的代码的编写。同时只需要实例化一个继承这个父类的子类对象,即可调佣相应的方法。

class Animal{
    public void action(){
        System.out.println("正在跑");
    }
}
class Dog extends Animal{
    public void action(){
        System.out.println("正在用四条腿跑");
    }
}
class Bird extends Animal{
    public void fly(){
        System.out.println("正在飞");
    }
}


例如这里有一个Animal父类,其中一个Dog类和Bird类继承这个Animal类。父类中有action这个方法,但是对于鸟和狗来说,他们的行为是不一样的,比如狗是用四条腿跑,而鸟是用翅膀飞。

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Bird bird = new Bird();
        dog.action();
        bird.action();
    }
}


结果如下:

三、抽象类


       有时候我们在实例化对象的时候,难免会将一个父类不小心给实例化了,但是有的情况是不允许父类被实例化的。例如一个父类Animal动物类,他被他的子类Dog继承。我们可以将Dog实例化成一个具体的dog,但是你并不能将一个动物给具体抽象出来,一个动物直接抽象出来会是什么?怎么归类?但是我们又只需要实例化子类对象,而不是父类对象。这就是一大麻烦,为了避免这个问题,我们需要将这个父类设置为抽象类,来避免父类被实例化。


       在实际解决问题的时候,通常将父类设置为抽象类,然后对这个父类进行继承和多态处理,继承关系中,越是在上方的类越抽象,例如狗类继承哺乳类,哺乳类继承动物类等。


       抽象类的语法如下:


public abstract class Test类名{        


       abstract void function( );


}


       abstract为定义抽象类关键字,使用abstract关键字定义的类为抽象类,而使用这个关键字定义的方法被称为抽象方法,这个方法不能有方法体,方法本身没有任何意义,它的作用只存在于被子类重写后。一个类如果有抽象方法,那么他必须被定义为抽象类(如果声明一个抽象方法,就必须将含有这个抽象方法的类定义为抽象类),实际上抽象类除了被继承之外没有任何意义,抽象类同时也保证了类在被继承的时候的安全性。


       对于继承这个抽象类的子类来说,子类需要重写这个抽象类中的所有的抽象方法。


四、接口类

       举一个很简单的例子,一个父类中存在属性:名字,年龄行为:跑,游泳(两个都是抽象方法);


然后我们定一个狗类(假设不会游泳),和一个鱼类都继承这个父类,那么对于狗类和鱼类来说都需要实现跑和游泳这两抽象方法,那么问题来了,狗如何去实现游泳这个方法?那么鱼又如何去实现跑这个方法?鱼不可能会跑,狗不能游泳,或者说狗类不用重写和实现这个方法,那么这个抽象方法是不可能被实现的,但是需要继承这个父类的名字和年龄等属性,为了应对这种问题,接口的概念就出现了。


       接口就是为了应对这种父类不能完全将子类中的共同特性抽取出来的情况。


语法如下:


关键字:interface


interface Test(接口名){


       void  function();  // 接口内的方法,省略abstract关键字。


}

使用implements 来让类实现该接口



在接口中,方法必须被定义为public或abstract的形式其他修饰限定符不被java编译器认可,即使该方法没有被public修饰,也是默认public权限,并且接口中被定义的任何字段都是自动被static和final修饰的。


实现某个接口的类,这个类就必须实现重写这个接口中的方法。

案例如下:

interface Fly{
    void fly();
}
interface Run{
    void run();
}
class Dog implements Run{
    @Override
    public void run() {
        System.out.println("dog is running");
    }
}
class Bird implements Fly{
    public void fly(){
        System.out.println( "bird is flying");
    }
}
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Bird bird = new Bird();
        dog.run();
        bird.fly();
    }
}


       结果如图

接口类型也可是实现向上转型

 

interface Run{
    void run();
}
class Dog implements Run{
    @Override
    public void run() {
        System.out.println("dog is running");
    }
}
public class Main {
    public static void main(String[] args) {
        Run run = new Dog();
        run.run();
    }
}


结果如下:

五、final关键字

重写和继承的功能很强大,但是必然也存在着不允许被重写或者继承的情况,这个时候就可以使用final修饰类或者方法,来防止某些不允许被重写和继承的情况。


1、final防止重写

       为了方法方法被重写,需要在方法声明的开始处将final指定为修饰符,被final修饰的方法不能被重修。

class A{
    final void method(){
        System.out.println("hello");
    }
}
class B extends A{
    void method(){
        System.out.println("hello java");
    }
}


报错如下:

2、使用final放置继承

在声明类的时候可以在开始的位置加上final关键字,以防止其被其他类继承:

final class A{
    // 方法体
}
class B extends A{
    // 方法体
}


执行后显示

85cf1c028f0e372308f360e7e6daa885_b8b699899e9748118352cf29ddfd3450.png

       如果一个类被abstract和final同时修饰,是非法的。如果这个类被abstract修饰,那么其中必定包含abstract方法,abstract方法必须被重写,但是被final修饰的类,其中的方法都是隐式的被final修饰,也就是说其中的所有方法都不能被重写,因此同时被final和abstract修饰是没有意义的,是不合法的。


3、final修饰的变量

final不仅可以修饰方法和类,还可以用来修饰成员变量,如果一个变量被final修饰,那么它的值在其生命周期内就不能改变。但是可以给他初始化。final修饰的变量初始化可以直接赋值,也可以使用代码块和构造方法来对其进行初始化,不管怎么样,必须对其选取这几种方法中的一个来初始化

初始化:

1、可以使用代码块

class A{
    final int a;
    {
        a = 10;
    }
}

如果这个变量同时被static修饰,那么可以使用static静态代码块来对其进行初始化:

1. class A{
2. final static int a;
3. static {
4.         a = 10;
5.     }
6. }

2、构造器初始化

class A{
    final  int a;
    public A(int a) {
        this.a = a;
    }
}


目录
打赏
0
0
0
0
5
分享
相关文章
|
1天前
|
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
25 11
课时11:综合实战:简单Java类
本次分享的主题是综合实战:简单 Java 类。主要分为两个部分: 1.简单 Java 类的含义 2.简单 Java 类的开发
课时37:综合实战:数据表与简单Java类映射转换
今天我分享的是数据表与简单 Java 类映射转换,主要分为以下四部分。 1. 映射关系基础 2. 映射步骤方法 3. 项目对象配置 4. 数据获取与调试
|
15天前
|
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
138 60
【Java并发】【线程池】带你从0-1入门线程池
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
53 23
|
11天前
|
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
77 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
102 14
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
57 13
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
2月前
|
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
125 17

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等