Java 面向对象进阶:解锁多态、内部类与包管理

news2025/5/18 8:43:53

Java 面向对象进阶:解锁多态、内部类与包管理 🔑

在 Java 的面向对象编程中,多态赋予了对象“多种形态”的能力,内部类提供了更精细的代码组织方式,而包则帮助我们管理和组织大量的类。今天,我们将深入探讨这些概念,理解它们在实际开发中的应用。

🎭 多态:对象的多种身份

多态性是面向对象编程的三大特性之一(封装、继承、多态)。它允许我们使用一个父类引用来指向子类的对象,从而在运行时根据对象的实际类型执行不同的操作。

  • 向上造型 / 自动类型转换 (Upcasting)

    • 概念:超类型的引用指向派生类的对象。这是自动发生的,不需要强制转换。
    • 规则:能“点”出来什么,看引用的类型。虽然对象实际是子类,但通过父类引用只能访问父类中定义的成员(包括继承自父类的)。子类特有的成员无法直接通过父类引用访问。这是一个重要的规定,请记住它。
    • 可以向上造型成为的类型:一个对象可以向上转型成为它所继承的类,以及它所实现的接口
    Animal o2 = new Dog("小黑",2,"黑"); // 狗是动物 - 向上造型
    // 通过 o2 只能访问 Animal 类中定义的成员,例如 o2.name, o2.eat() 等
    // 无法直接访问 Dog 类特有的 lookHome() 方法
    Swim o3 = new Dog("小黑",2,"黑");   // 狗会游泳 - 向上造型
    // 通过 o3 只能访问 Swim 接口中定义的方法,例如 o3.swim()
    
  • 向下转型 / 强制类型转换 (Downcasting)

    • 概念:将一个超类型的引用强制转换为派生类的引用。
    • 成功的条件:强制类型转换成功的条件只有两种:
      • 引用实际指向的对象就是该目标类型
      • 引用实际指向的对象实现了该目标接口或继承了该目标类
    • 类型转换异常 (ClassCastException):如果强制类型转换不符合上述条件,就会在运行时发生 ClassCastException 异常。
    • 建议:在进行向下转型之前,先使用 instanceof 关键字来判断引用所指向的对象是否是目标类型。
    • instanceof:返回一个布尔值,表示引用所指向的对象是否是某个类型(类或接口)的实例。instanceof 返回 true 的条件,就是强制类型转换成功的条件。
    Animal o = new Dog("小黑",2,"黑"); // 向上造型
    Dog g = (Dog)o;   // 引用 o 所指向的对象就是 Dog 类型,强制转换成功
    Swim s = (Swim)o; // 引用 o 所指向的对象实现了 Swim 接口,强制转换成功
    // Fish f = (Fish)o; // 运行时会发生 ClassCastException,因为 o 实际指向的是 Dog 对象,而不是 Fish 对象
    
    System.out.println(o instanceof Dog);  // true
    System.out.println(o instanceof Swim); // true
    System.out.println(o instanceof Fish); // false
    
    if(o instanceof Fish){ // 先判断,避免异常
        Fish f = (Fish)o;
        // 可以安全地使用 f 引用访问 Fish 特有的成员
    }
    
    • 何时需要强转:当你需要访问对象中在超类中没有定义的,而只在派生类或实现的接口中特有的属性或行为时,就需要进行强制类型转换。
  • 多态的实际应用场景

    • 统一处理不同子类对象:将不同子类对象统一封装到超类数组中进行遍历和操作,实现代码复用。例如,将不同类型的动物放入一个 Animal 类型的数组中,然后循环调用它们的 eat()drink() 方法,即使具体的实现不同(重写),代码结构依然简洁。
    • 方法的参数或返回值类型:将超类型(类或接口)作为方法的参数类型或返回值类型,可以使方法接收或返回各种不同的子类对象,扩大方法的应用范围,提高代码的灵活性和复用性。例如,Master 类中的 feed(Animal animal) 方法,可以喂养任何 Animal 的子类对象。
    // 演示向上造型(多态)的应用:
    Animal[] animals = new Animal[5];
    animals[0] = new Dog("小黑",2,"黑"); // 向上造型
    animals[1] = new Dog("小白",1,"白");
    animals[2] = new Fish("小金",1,"金");
    animals[3] = new Fish("小花",2,"花");
    animals[4] = new Chick("小灰",3,"灰");
    
    for(int i=0;i<animals.length;i++){ // 遍历所有动物
        System.out.println(animals[i].name);
        animals[i].drink();
        animals[i].eat(); // 多态:根据实际对象调用对应的 eat() 方法
        if(animals[i] instanceof Dog){ // 判断是否为 Dog 对象,进行向下转型以访问特有方法
            Dog dog = (Dog)animals[i];
            dog.lookHome();
        }
        if(animals[i] instanceof Chick){ // 判断是否为 Chick 对象
            Chick chick = (Chick)animals[i];
            chick.layEggs();
        }
        if(animals[i] instanceof Swim){ // 判断是否实现了 Swim 接口
            Swim s = (Swim)animals[i];
            s.swim(); // 多态:调用实际对象实现的 swim() 方法
        }
    }
    

🚪 成员内部类:服务于外部类

成员内部类是定义在另一个类内部的非静态类。它通常只服务于其外部类,对外不可见。

  • 类中套类:外面的类称为外部类,里面的类称为内部类
  • 可见性:内部类通常只服务于外部类,默认情况下对外不具备可见性
  • 创建对象:内部类对象通常在外部类中创建
  • 访问外部类成员:内部类可以直接访问外部类的所有成员(包括私有的)。在内部类中,有一个隐式的引用指向创建它的外部类对象。
    • 这个隐式的引用可以通过 外部类名.this 来访问。
    • 例如:System.out.println(Mama.this.name);
  • 何时使用:当一个类 (A 类,例如 Baby) 只应该被另一个类 (B 类,例如 Mama) 使用,并且 A 类还需要访问 B 类的成员时,可以考虑设计成员内部类。
// 成员内部类示例
public class InnerClassDemo {
    public static void main(String[] args) {
        Mama m = new Mama();
        // Baby b = new Baby(); // 编译错误,内部类对外不具备可见性
    }
}

class Mama{ // 外部类
    String name = "我是妈妈";
    void create(){
        Baby b = new Baby(); // 正确,内部类对象通常在外部类中创建
        b.show();
    }
    class Baby{ // 成员内部类
        void show(){
            System.out.println(name); // 简写,内部类直接访问外部类成员
            System.out.println(Mama.this.name); // 完整写法,通过 Mama.this 指代外部类对象
            // System.out.println(this.name); // 编译错误,this 在这里指代当前的 Baby 对象,Baby 类没有 name 成员
        }
    }
}

🤫 匿名内部类:简化一次性使用

匿名内部类是一种特殊的内部类,它没有名字。主要用于创建一个派生类的对象,并且该对象只创建一次。使用匿名内部类可以大大简化代码。

  • 何时使用:当你需要创建一个接口的实现类或一个类的子类的对象,并且只需要创建一次这个对象时,可以使用匿名内部类。
  • 语法
    接口名/类名 对象名 = new 接口名/类名() {
        // 匿名内部类的类体
        // 实现接口中的抽象方法 或 重写父类方法
        // 可以有自己的成员,但通常不常见
    };
    
  • 注意:匿名内部类中不能修改外部局部变量的值。这是因为编译器会默认将匿名内部类中访问到的外部局部变量变为 final 的。
  • 小面试题:内部类有独立的 .class 文件吗?
    • :有。编译器会为匿名内部类生成一个带有特殊命名规则的 .class 文件。
// 匿名内部类示例
public class AnonInnerClassDemo {
    public static void main(String[] args) {
        // 使用匿名内部类实现 InterInter 接口
        InterInter o3 = new InterInter(){
            public void show(){ // 实现 InterInter 接口中的抽象方法 show()
                System.out.println("showshow");
                // num = 6; // 编译错误,不能修改外部局部变量 num
            }
        };
        o3.show(); // 调用匿名内部类中实现的 show() 方法

        int num = 5;
        // num = 6; // 这里修改 num 是合法的
    }
}

interface InterInter{
    void show();
}

📦 package 与 import:组织和引用代码

随着项目规模的增大,类会越来越多。packageimport 关键字帮助我们组织和管理这些类,避免命名冲突。

  • package:声明包

    • 作用:将相关的类组织在一起,形成一个“包”,从而避免类的命名冲突
    • 规定:同一个包中的类不能同名,但不同包中的类可以同名。
    • 类的全称:一个类的完整名称包括包名和类名,格式为 包名.类名。包名常常具有层次结构,用点 (.) 分隔。
    • 建议:包名所有字母都小写
    • package 语句必须是 Java 源文件的第一条非注释语句
  • import:导入类

    • 当一个类需要使用不同包中的其他类时,不能直接访问,需要先导入。
    • 方式 1 (建议):使用 import 关键字导入需要使用的类。
      import java.util.Scanner; // 导入 java.util 包下的 Scanner 类
      // 现在可以直接使用 Scanner 类名
      Scanner scan = new Scanner(System.in);
      
    • 方式 2 (不建议):使用类的全称来访问。这种方式太繁琐,不建议在代码中大量使用。
      java.util.Scanner scan = new java.util.Scanner(System.in); // 使用类的全称
      
    • 导入同一个包下的多个类:可以使用通配符 * 来导入包下的所有类,例如 import java.util.*;。但这通常不如明确导入所需的类那样清晰。
    • import 语句必须放在 package 语句之后,所有类定义之前。

补充:

  • 隐式的引用总结
    • this:指代当前对象。
    • super:指代当前对象的超类对象。
    • 外部类名.this:指代当前内部类对象所依赖的外部类对象。
  • 关键字顺序:在一个 Java 源文件中,关键字的顺序通常是:package,再 import,最后 class 定义

多态、内部类和包管理是 Java 中非常实用的特性。理解并熟练运用它们,能够帮助我们编写出更加灵活、可维护和结构清晰的代码。继续练习,你会越来越得心应手!

总结

  • 多态:多种形态
    1. 向上造型:超类型的引用指向派生类的对象
    2. 向下转型,成功的条件:
      2.1) 引用所指向的对象,就是该类型
      2.2) 引用所指向的对象,实现了该接口或继承了该类
  • 匿名内部类:
    1. 若想创建一个派生类的对象,并且对象只创建一次,可以设计为匿名内部类
      可以大大简化代码
  • package 用于声明包,import 用于导入类

提示

  • 什么是多态
  • 多态的应用场景有哪些
  • 匿名内部类的应用场景有哪些
  • package 和 import 的作用
  • 不同包中的类如何访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法:分治法

实验内容 在一个2kⅹ2k个方格组成的棋盘中&#xff0c;若恰有一个方格与其他方格不同&#xff0c;则称该方格为特殊方格&#xff0c;且称该棋盘为一特殊棋盘。 显然&#xff0c;特殊方格出现的位置有4k 种情况&#xff0c;即k>0,有4k 种不同的特殊棋盘 棋盘覆盖&#xff1a…

MySQL初阶:sql事务和索引

索引&#xff08;index&#xff09; 可以类似理解为一本书的目录&#xff0c;一个表可以有多个索引。 索引的意义和代价 在MySQL中使用select进行查询时会经过&#xff1a; 1.先遍历表 2.将条件带入每行记录中进行判断&#xff0c;看是否符合 3.不符合就跳过 但当表中的…

docker部署第一个Go项目

1.前期准备 目录结构 main.go package mainimport ("fmt""github.com/gin-gonic/gin""net/http" )func main() {fmt.Println("\n .::::.\n .::::::::.\n :::::::::::\n …

Visual Studio2022跨平台Avalonia开发搭建

由于我已经下载并安装了 VS2022版本&#xff0c;这里就跳过不做阐述。 1.安装 Visual Studio 2022 安装时工作负荷Tab页勾选 ‌“.NET 桌面开发”‌ 和“Visual Studio扩展开发”‌ &#xff0c;这里由于不是用的微软的MAUI&#xff0c;所以不用选择其他的来支持跨平台开发&a…

css iconfont图标样式修改,js 点击后更改样式

背景&#xff1a; 在vue项目中&#xff0c;通过点击/鼠标覆盖&#xff0c;更改选中元素的样式&#xff0c;可以通过js逻辑&#xff0c;也可以根据css样式修改。包括以下内容&#xff1a;iconfont图标的引入以及使用&#xff0c;iconfont图标样式修改【导入文件是纯白&#xff0…

开源项目实战学习之YOLO11:12.4 ultralytics-models-sam-memory_attention.py源码分析

👉 点击关注不迷路 👉 点击关注不迷路 👉 另外,前些天发现了一个巨牛的AI人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。感兴趣的可以点击相关跳转链接。 点击跳转到网站。 ultralytics-models-sam 1.sam-modules-memory_attention.pyblocks.py: 定义模…

【沉浸式求职学习day42】【算法题:滑动窗口】

沉浸式求职学习 长度最小的子数组水果成篮 关于算法题&#xff1a;滑动窗口的几个题目 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 s &#xff0c;找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组&#xff0c;并返回其长度。如果不存在符合条件的子数组…

LIIGO ❤️ RUST 12 YEARS

LIIGO &#x1f496; RUST 12 YEARS 今天是RUST语言1.0发布十周年纪念日。十年前的今天&#xff0c;2015年的今天&#xff0c;Rust 1.0 正式发行。这是值得全球Rust支持者隆重纪念的日子。我借此机会衷心感谢Rust语言创始人Graydon Hoare&#xff0c;Mozilla公司&#xff0c;以…

Linux基础开发工具二(gcc/g++,自动化构建makefile)

3. 编译器gcc/g 3.1 背景知识 1. 预处理&#xff08;进行宏替换/去注释/条件编译/头文件展开等) 2. 编译&#xff08;生成汇编) 3. 汇编&#xff08;生成机器可识别代码&#xff09; 4. 连接&#xff08;生成可执行文件或库文件) 3.2 gcc编译选项 格式 &#xff1a; gcc …

全局异常处理:如何优雅地统一管理业务异常

在软件开发中&#xff0c;异常处理是保证系统健壮性的重要环节。一个良好的异常处理机制不仅能提高代码的可维护性&#xff0c;还能为使用者提供清晰的错误反馈。本文将介绍如何通过全局异常处理和业务异常统一处理来编写更加优雅的代码。 一、传统异常处理的痛点 1.1 典型问…

动态规划-LCR 166.珠宝的最大价值-力扣(LeetCode)

一、题目解析 frame二维矩阵中每个值代表珠宝的价值&#xff0c;现在从左上角开始拿珠宝&#xff0c;只能向右或向下拿珠宝&#xff0c;到达右下角时停止拿珠宝&#xff0c;要求拿的珠宝价值最大。 二、算法解析 1.状态表示 我们想要知道的是到达[i,j]为位置时的最大价值&am…

JDBC实现模糊、动态与分页查询的详解

文章目录 一. 模糊查询1. Mysql的写法2. JDBC的实现 二. 动态条件查询1. 创建生成动态条件查询sql的方法2. 完整的动态条件查询类以及测试类 三. 分页查询1. 什么是分页查询&#xff1f;2. 分页查询的分类3. MySQL的实现4. JDBC实现4.1. 创建page页4.2. 分页的实现 本章来讲一下…

域环境信息收集技术详解:从基础命令到实战应用

引言 在企业网络环境中&#xff0c;Active Directory (AD)域服务是微软提供的集中式目录服务&#xff0c;用于管理网络中的用户、计算机和其他资源。对于信息安全专业人员来说&#xff0c;熟练掌握域环境信息收集技术至关重要&#xff0c;无论是进行渗透测试、安全评估还是日常…

【C++ Qt】布局管理器

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” &#x1f914;绪论​&#xff1a; 在Qt开发中&#xff0c;界面布局的合理设计是提升用户体验的关键。早期&#xff0c;开发者常采用绝对定位的方式摆放控件&#xff0c;即通…

vscode用python开发maya联动调试设置

如何在VScode里编写Maya Python脚本_哔哩哔哩_bilibili1 包括1&#xff0c;maya的python全面在vscode支持&#xff0c;2&#xff0c;通过mayacode发送到maya&#xff0c;3同步调试 import maya.cmds as cmds 1、让 maya.cmds编译通过 下载Autodesk_Maya_2018_6_Update_DEVK…

SLAM定位常用地图对比示例

序号 地图类型 概述 1 格栅地图 将现实环境栅格化,每一个栅格用 0 和 1 分别表示空闲和占据状态,初始化为未知状态 0.5 2 特征地图 以点、线、面等几何特征来描绘周围环境,将采集的信息进行筛选和提取得到关键几何特征 3 拓扑地图 将重要部分抽象为地图,使用简单的图形表示…

python的漫画网站管理系统

目录 技术栈介绍具体实现截图![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0ed2084038144499a162b3fb731a5f37.png)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a76a091066f74a80bf7ac1be489ae8a8.png)系统设计研究方法&#xff1a;设计步骤设计流程核…

源码安装gperftools工具

源码安装gperftools工具 下载gperftools源码 https://github.com/gperftools/gperftools/releases/download/gperftools-2.16/gperftools-2.16.tar.gz 注&#xff1a;需要下载github上release版本&#xff0c;如果直接下载master分支上源码&#xff0c;将可能出现各种编译报错…

前端脚手架开发指南:提高开发效率的核心操作

前端脚手架通过自动化的方式可以提高开发效率并减少重复工作&#xff0c;而最强大的脚手架并不是现成的那些工具而是属于你自己团队量身定制的脚手架&#xff01;本篇文章将带你了解脚手架开发的基本技巧&#xff0c;帮助你掌握如何构建适合自己需求的工具&#xff0c;并带着你…

搜索引擎工作原理|倒排索引|query改写|CTR点击率预估|爬虫

写在前面 使用搜索引擎是我们经常做的事情&#xff0c;搜索引擎的实现原理。 什么是搜索引擎 搜索引擎是一种在线搜索工具&#xff0c;当用户在搜索框输入关键词时&#xff0c;搜索引擎就会将与该关键词相关的内容展示给用户。比较大型的搜索引擎有谷歌&#xff0c;百度&…