初识Java - 概念与准备

news2024/9/22 1:55:20

本笔记参考自: 《On Java 中文版》


目录

写在第一行

Java的迭代与发展

Java的迭代

Java的参考文档

对象的概念

抽象

接口

访问权限

复用实现

继承

基类和子类

A是B和A像B

多态

单根层次结构

集合

参数化类型

对象的创建和生命周期


写在第一行

         作为一门派生语言,Java的诞生离不开C++。也正因如此,Java继承了来自于C++“面向对象”(Small-Talk)的概念。而后来,这种面向对象的概念被证明是有些激进的。而正如每一门语言都有的一样,Java也存在着自身的局限,但知晓一门语言的不足也同样重要。

(例如Java中那些设计存在缺陷的库及语言。)

    很显然,将一切都封装成对象过于激进,但完全抛弃它也不免浪费。因此在Java一些面向初学者的书中,对于对象这一概念的态度是折中的(笔者:合理地利用)。本笔记参考的《On Java 中文版》既是如此。

Java的迭代与发展

Java的迭代

        发展至今,Java已经迭代了很久。除去早期版本的版本号,现在的Java一般每6个月发布一个新版本,并且使用整数作为其版本号。值得注意的是,Java在新发布的版本中往往会包含一些试用功能,但难以保证这些功能长期存在的,所有写代码时最好别依赖它。

        Java提供了两种不同的支持:短期支持(STS)与长期支持(LTS,常见的Java 8就是该版本)。但同样地,它们都会提供不同的功能试用。

    在每一版的Java中,都会包含不同的功能试用,可以分为三类:实验(Experimental)、预览(Preview)、孵化中(Incubating)。

Java的参考文档

        Java的开发工具集(即JDK)带有电子在线文档,该文档对于每个类的描述都很详细。在进行Java开发的时候可以参考该文档。

对象的概念

抽象

        如果说计算机是一种表达的媒介,编程语言是一种思维模式(就好比不同的语言最终影响了我们的衣食住行一样),那么面向对象编程,就是对使用计算机这一媒介的一次尝试

        要解释上面这句话,就要提到抽象任何编程语言都是一种抽象,有的是对于计算机结构的抽象,有的是对特定问题的抽象。这些不同的语言会在不同的问题上展现自己的优势,但同样的,它们往往都存在无能为力的地方。因此,面向对象编程应运而生。

        在面向对象编程中,对象可以是某种生物,某个建筑或者某种服务,而我们进行抽象的对象不再是计算机,而是实际的问题。通过这种方式,我们将程序转变为一段用来描述问题的文字。(注:对象与计算机之间的联系可以通过“状态”进行体现,因为每一个对象都有自己的行为和特征)

        Alan Kay曾经总结过SmallTalk(一种面向对象语言)的基本特征,其同样适用于其他面向对象的编程:

  1. 万物皆对象。
  2. 一段程序实际上就是多个对象通过发送消息来通知彼此要干什么。
  3. 从内存角度而言,每一个对象都是由其他更为基础的对象组成的。
  4. 每一个对象都有类型。
  5. 同一类型的对象可以接收相同的信息。

接口

        在拥有了对象这一概念后,我们将对象进行了分类,因此就诞生了类型。我们把状态不同而结构相同的对象分为“同一类对象”,而反过来,每一个对象所归属的类就决定了对象具有的行为特征。

    在很多面向对象的编程语言中,存在着class(即:类)这一关键字。可以说,这一关键字就代表着type(即:类型)。而事实上,由于类描述了对象的相同特征行为,这和数据类型很相似,所以也有这样的说法:类就是数据类型。

        但此时依旧存在着一个麻烦的问题,那就是对象能够接受什么请求。这就是由“接口”决定的,对象归属的类定义了这些接口。在面向对象的操作中,我们会向对象发出特定的请求,而如何处理请求是由对象来决定的。例如,下方图片展示了一个名为Light的类型:

Light A = new Light();    //A是一个引用,使用new关键字新建一个对象
A.on();                   //调用这一对象的接口

||| “实现”的概念: 用于响应请求的代码,以及与之相关的数据,它们的总和被称为“实现”。

    在开发面向对象的程序时,我们应该将对象想象为一个“服务的提供者”,对象应该能够,且只能够做好一件事(每个对象都只提供一种服务)。

访问权限

        一般,可以将程序员分为两类,分别是“类的创建者”和“客户程序员”,一方负责创建数据类型,而另一方则使用各种类。这意味着,“类的创建者”只为“客户程序员”提供必要的类的接口。这种做法当然是有意义的:

    一方面,这种做法可以提高安全性,因为这可以使得“客户程序员”无法解除那些本不允许他们接触的内容;而另一方面,当创建者想要修改类的内容时,由于修改的内容处于内部,因此不会影响使用该类的“客户程序员”。

        Java为了实现这种对访问权限的控制,设置了3个显式关键字,分别是publicprivateprotected,不同的修饰有不同的权限:

关键字访问权限
public可以被所有人访问
private只能被类的创建者通过该类自身的方法访问(其余人不可访问)
protected类似于private,但被protected修饰的类,其子类可以访问protected的成员
若不使用上述任意一种访问修饰符,Java也有默认的访问权限,即“包访问”,这一权限运行一个类访问其同一个包内的其他类,但不影响外部访问。

复用实现

        在理想的情况下,我们希望我们创建的对象能够有效,且应该是可以复用的。但现实情况是,这种可复用的对象设计更为少见。

        复用一个类有不同的方式,如果是利用已有的类组合成一个新的类,这种方式被称为“组合”(若组合是动态的,则被称为“聚合”)。组合代表的通常是一种“有”的关系,例如:“汽车有发动机”。

    组合是一种很灵活的复用方式,这是因为通过组合形成的新类,其内部的对象通常具有private属性,因此它即安全,又方便创建者修改这些内部对象。也因此,在创建新类时可以优先考虑组合。

继承

基类和子类

        在实际面对问题时,我们有时会发现:可能需要两个功能及其相似的类。如果因此大费周章,就太麻烦了。而继承(复制现有的类,在复制类上进行增补)就可以对此进行处理。通常,我们把被复制的类称为“基类(“超类”或“父类”),而把被修改的“复制”类称为“子类(“派生类”或“继承类”)

    继承的缺点是:若基类发生变化,则子类也会跟着变化。

        继承的这种思路使得我们可以有基类来阐述核心的思想,而众多的子类则是这一核心思想的不同实现方式。例如:如果现在需要绘制一个图形,把“形状”(Shape)作为基类,每个具体的形状都有具体的信息(大小、颜色)和行为(绘制、上色),那么圆形(Circle)、矩形(Square)、三角形(Triangle)等就是被派生出的子类。

        由继承产生的新类不仅会继承基类的所有成员(private成员除外),还会继承基类的接口。也就是说,基类对象能够接收的消息,子类也一样可以接收。从这一点上看,子类和基类拥有相同的类型。

        子类和基类会因为两种不同的方式产生区别:第一种方式是为子类添加新的方法。

        而另一种方式则是修改基类的已有方法,即“重写”。想要重写一个方法,只需在子类中对该方法进行重新定义即可。

A是B和A像B

        若子类和基类的接口一模一样,这也就意味着子类和基类的类型是完全相同的。在这种情况下,我们说基类和子类之间存在的关系是“A是B”,就比如“圆是一个形状”。此时,可以直接用子类的对象替代基类的对象

        但还有另一类“A像B”的情况,在这种情况下,子类除了拥有基类接口外,还有一些独立的接口。这时无法通过基类的接口获取子类的新方法。这时之前提到的那种替换通用性就会有所下降,显得并不这么合适。此时如果需要迎合子类,比较好的方法是从设计层面进行更改(增添功能)。

多态

        在涉及类型层次(即子类和基类结构)时,通常会将对象视为其基类的一个实例。通过派生子类的方式,可以轻松扩展程序设计。在这种方式中,我们并不需要关心具体执行的代码,因为对象能够根据类型执行对应正确的代码。

    这里存在着这样的一个问题:既然我们并不知道对象的具体类型,那么应该怎么为这一对象匹配正确的处理呢(毕竟它仅仅调用了接口)?

    答案来自于继承机制的一种重要技巧:编译器不是通过传统方式来调用方法。这种机制被称为“后期绑定”,这种机制要求程序直到运行时才确定代码的地址。而在Java中,方法都默认具有后期绑定特性,这使得我们不需要使用额外代码来实现多态。

    与“后期绑定”对应的就是“前期绑定”,对于非面向对象编译器而言,其生成的函数调用会触发“前期绑定”,此时编译器会生成一个具体方法名的调用,再通过该方法决定被执行代码的绝对地址。

        除此之外,这里还会涉及一个“向上转型”的概念,即将子类视为基类。如果我们为基类编写一个方法do(),那么这个方法也将适用于该基类的任意的一个子类,而do()发送给基类的信息也可以发送给子类。例如,还是以Shape为例:

单根层次结构

        在Java中,面向对象中的所有类都默认继承自一个终极基类Object。这种“单根层次结构”的使得所有对象都具有了共同的接口,这就提高了Java的兼容性。单根层次结构的另一个好处就是垃圾收集器,因为所有对象都有类型信息(Object),所以在对这些信息处理时,不需要费尽心思去考虑处理对象的类型。

集合

        有时,在面对一些问题时,我们会遇到对象个数不明,数量不明,存在时间不明的情况。在程序开始执行前,我们无法得知上述情报。很显然,这对开辟空间是一个巨大的阻力。

        在面向对象设计中,为了解决上述情况,通常都会用到集合(其实也可以使用数组)。集合是一种对象,这种对象通过保存其他对象的引用来解决问题,并且会根据放入的内容来调整空间。Java提供了一些集合,例如List类、Map类、Set类等,还有一些队列、栈和树。

    当然,无论集合的类型多么丰富,我们需要的都是能够解决问题的集合。比如List有两种基础的集合:ArrayListLinkedList。二者会因为结构的不同而在执行效率上有所区别。(不过由于两者都是基于List接口的子类,因此可以通过改动代码进行切换)

参数化类型

        在Java 5之前的版本中,集合只支持通用类型Object。这意味着,如果我们将对象添加到集合中,那么我们使用的对象将向上转型Object,从而失去自身的特征。这无疑加大了从集合中提取对象的难度。

     与“向上转型”相反,存在着“向下转型”的概念。当然,这种转型其实不太安全,因为一个基类可以有多个子类,若不声明确切的对象类型,那么在选择子类上就会可能出现安全问题。

        “参数化类型”的概念,为创建的集合明确其中包含的对象类型,成为了上述问题的解决方案。一个被参数化的类型是一个特殊的类,可以让编译器自动为其适配类型。例如:一个被定义为存放Shape类型的集合,也只能从中取出Shape类型。

        Java 5新增了一个特性用于支持参数化类型,或者说“泛型”。如果需要创建一个Shape对象的ArrayList,只需要在下方尖括号内加上类名,就可以定义泛型:

ArrayList<Shape> shapes = new ArrayList<>();

对象的创建和生命周期

        每个对象的创建都要消耗内存资源,当不需要使用该对象时,回收其占据的资源无疑是必要的行为。但随着问题复杂度的上升,当系统的某一部分不再需要一个对象时,该系统的其他部分可能还在使用该对象。这就使得一些使用显式删除对象的编程语言(例如C++)的程序员要耗费精力去解决这一问题。

        C++将对生命周期的处理交给了程序员,通过对栈区和堆区的选择比较效率和灵活性。而Java只运行动态分配内存,通过new操作符来创建一个对象的动态实例(不过也有特例,就是基本类型)。当然,Java也不需要手动释放内存,因为通过垃圾收集器机制,Java能够自动销毁无用对象。

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

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

相关文章

Charles抓包工具使用(一)(macOS)

Fiddler抓包 | 竟然有这些骚操作&#xff0c;太神奇了&#xff1f; Fiddler响应拦截数据篡改&#xff0c;实现特殊场景深度测试&#xff08;一&#xff09; 利用Fiddler抓包调试工具&#xff0c;实现mock数据特殊场景深度测试&#xff08;二&#xff09; 利用Fiddler抓包调试工…

pytorch-gpu 极简安装

1、进入pytoch官网&#xff1a;PyTorch 找到pytorch-gpu版本&#xff0c;看到CUDA11.8、11.7、CPU&#xff0c;这里我选择安装CUDA11.8 2、下载CUDA Toolkit&#xff1a;CUDA Toolkit 11.8 Downloads | NVIDIA Developer 3、下载CUDANN&#xff1a;cuDNN Download | NVIDIA D…

TCP拥塞控制详解 | 1. 概述

网络传输问题本质上是对网络资源的共享和复用问题&#xff0c;因此拥塞控制是网络工程领域的核心问题之一&#xff0c;并且随着互联网和数据中心流量的爆炸式增长&#xff0c;相关算法和机制出现了很多创新&#xff0c;本系列是免费电子书《TCP Congestion Control: A Systems …

基于Spring Boot的鲜花销售网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的鲜花销售网站设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java springboot…

运算放大器(三):差分放大

一、定义 差分放大电路又称为差动放大电路&#xff0c;当该电路的两个输入端的电压有差别时&#xff0c;输出电压才有变动&#xff0c;因此称为差动。 二、电路结构 常用的差分放大电路如下 图1 所示&#xff0c; 图1 根据虚短和虚断可得&#xff1a;

C# Blazor 学习笔记(0):初识Blazor

文章目录 Blazor是什么适合人群 开始学习BlazorBlazor资源如何创建BlazorBlazor 基础知识介绍文件分布Razor和cshtml的区别Razor介绍 Blazor是什么 Blazor是微软推出的前端框架&#xff0c;有两种形式&#xff0c;以下以Blazor Server为主。具有一下特点 前端是用C#而不是JS前…

Linux编辑器 - vim使用

1.vim的基本概念 Vim是一个广泛使用的文本编辑器&#xff0c;它是在Unix和Linux系统中常用的命令行文本编辑器之一。 vim的主要三种模式 ( 其实有好多模式&#xff0c;目前掌握这 3 种即可 ), 分别是 命令模式 &#xff08; command mode &#xff09;、 插入模式 &#xff0…

仿第八区分发封装打包系统源码教程-轻松打包app

这个是最新的修改优化&#xff0c;优化了一些小bug不能用的问题&#xff0c;具体什么就不讲了&#xff0c;用过的应该有知道的。 大致功能&#xff1a; 支持一键安卓打包&#xff0c;IOS免签、绿标&#xff01;&#xff08;几乎媲美原生&#xff09; 拥有此款神器&#xff0…

AppCompatActivity.setContentView(与activity.setContentView区别)方法解读

AppCompatActivity.setContentView()与Activity.setContentView()主要的区别&#xff0c;Activity.setContentView直接将视图添加到Window上&#xff0c;AppCompatActivity.setContentView()借助AppCompatActivity的Delegate代理类&#xff0c;将要显示的视图加入到代理层视图&…

【网络原理】 (3) (网络层 IP协议 地址管理 路由选择 数据链路层 以太网 MTU 补充:DNS)

文章目录 网络层IP协议地址管理路由选择 数据链路层以太网MTU补充:DNS 网络层 IP协议 网络层的代表,IP协议. 4位版本号&#xff08;version&#xff09;&#xff1a;指定IP协议的版本&#xff0c;对于IPv4来说&#xff0c;就是4。4位头部长度&#xff08;header length&…

98. Python基础教程:try...except...finally语句

【目录】 文章目录 1. try...except...finally语法介绍2. try...except...finally执行顺序3. 捕获特定类型的异常4. 捕获所有类型的异常5. 实操练习-打开txt文件并输出文件内容 【正文】 在今天的课程中&#xff0c;我们将学习Python中的异常处理语句try...except...finally。 …

excel英语翻译让你的数据更容易被理解

从前有一个名叫小明的办公室职员&#xff0c;他每天都要处理大量的数据和报表。然而&#xff0c;由于工作需要&#xff0c;他经常收到来自不同国家的Excel表格&#xff0c;这些表格上的内容都是用各种各样的语言编写的&#xff0c;让他很难理解其中的意思。这时&#xff0c;小明…

Qt Creator 11 开放源码集成开发环境新增集成终端和 GitHub Copilot 支持

导读Qt 项目今天发布了 Qt Creator 11&#xff0c;这是一款开源、免费、跨平台 IDE&#xff08;集成开发环境&#xff09;软件的最新稳定版本&#xff0c;适用于 GNU/Linux、macOS 和 Windows 平台。 Qt Creator 11 的亮点包括支持标签、多外壳、颜色和字体的集成终端模拟器&am…

建模教程:如何利用3ds Max 和 After Effects 实现多通道渲染和后期合成

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建基本场景 步骤 1 打开 3ds Max。在 透视视口。 打开 3ds Max 步骤 2 做一个茶壶&#xff0c;放在飞机上。 制作茶壶 步骤 3 我在场景中应用了几个灯光。我选择了光线追踪阴影作为阴影。 光线追…

走进人工智能| 智能物联网 AIoT的魅力交织

前言&#xff1a; AIIoT是指人工智能&#xff08;AI&#xff09;与物联网&#xff08;IoT&#xff09;的结合。智能物联网是一种技术体系&#xff0c;通过连接和集成物理设备、传感器和互联网&#xff0c;实现设备之间的智能交互和数据共享&#xff0c;为人们提供智能化、自动化…

赛车游戏——【极品飞车】(内含源码inscode在线运行)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

IEEE 802.11——无线局域网的重要里程碑

概要 无线局域网&#xff08;Wireless Local Area Network&#xff0c;WLAN&#xff09;已经成为现代生活中不可或缺的一部分&#xff0c;它为我们提供了便捷的无线网络连接&#xff0c;让我们能够在家中、办公室、公共场所等地轻松上网。在无线局域网技术的发展过程中&#x…

【C++】模板进阶(模板的特化,非类型模板参数,模板的分离编译)

文章目录 一、模板使用时一定要加typename的情况二、 非类型模板参数三、模板的特化1.函数模板特化2.类模板特化1.全特化&#xff1a;2. 偏特化&#xff1a;1. 部分特化2.参数更一步限制 四、模板的分离编译1.Stack.h2.Stack.cpp(定义)3.test.cpp 一、模板使用时一定要加typena…

【taro react】---- 获取元素的位置和宽高等信息

1. 需求分析 添加节点的布局位置的查询请求。相对于显示区域&#xff0c;以像素为单位。其功能类似于 DOM 的 getBoundingClientRect。返回 NodesRef 对应的 SelectorQuery。区分小程序和H5的环境&#xff0c;调用 getBoundingClientRect 获取对应的信息。 2. H5 实现 判断传…

根据前序和中序遍历序列构造二叉树 (递归+迭代两种方法实现)

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]源代码如下…