java对象强制类型转换,看完直接跪服

本文详细介绍了TCP/IP协议族,包括网络层、运输层和应用层的主要协议。特别关注TCP的三次握手和四次挥手过程,解析了为何需要三次握手和四次挥手的原因,以及TCP连接中可能出现的问题和解决方案。此外,还探讨了TCP连接的维护和异常处理机制,适合面试和学习网络基础知识。

计算机网络体系结构

在计算机网络的基本概念中,分层次的体系结构是最基本的。计算机网络体系结构的抽象概念较多,在学习时要多思考。这些概念对后面的学习很有帮助。

网络协议是什么?

在计算机网络要做到有条不紊地交换数据,就必须遵守一些事先约定好的规则,比如交换数据的格式、是否需要发送一个应答信息。这些规则被称为网络协议。

为什么要对网络协议分层?

  • 简化问题难度和复杂度。由于各层之间独立,我们可以分割大问题为小问题。
  • 灵活性好。当其中一层的技术变化时,只要层间接口关系保持不变,其他层不受影响。
  • 易于实现和维护。
  • 促进标准化工作。分开后,每层功能可以相对简单地被描述。

网络协议分层的缺点: 功能可能出现在多个层里,产生了额外开销。

为了使不同体系结构的计算机网络都能互联,国际标准化组织 ISO 于1977年提出了一个试图使各种计算机在世界范围内互联成网的标准框架,即著名的开放系统互联基本参考模型 OSI/RM,简称为OSI。

OSI 第七层协议体系结构的概念清楚,理论也较完整,但它既复杂又不实用,TCP/IP 体系结构则不同,但它现在却得到了非常广泛的应用。TCP/IP 是一个四层体系结构,它包含应用层,运输层,网际层和网络接口层(用网际层这个名字是强调这一层是为了解决不同网络的互连问题),不过从实质上讲,TCP/IP 只有最上面的三层,因为最下面的网络接口层并没有什么具体内容,因此在学习计算机网络的原理时往往采用这种的办法,即综合 OSI 和 TCP/IP 的优点,采用一种只有五层协议的体系结构,这样既简洁又能将概念阐述清楚,有时为了方便,也可把最底下两层称为网络接口层。

四层协议,五层协议和七层协议的关系如下:

  • TCP/IP是一个四层的体系结构,主要包括:应用层、运输层、网际层和网络接口层。
  • 五层协议的体系结构主要包括:应用层、运输层、网络层,数据链路层和物理层。
  • OSI七层协议模型主要包括是:应用层(Application)、表示层(Presentation)、会话层(Session)、运输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。

注:五层协议的体系结构只是为了介绍网络原理而设计的,实际应用还是 TCP/IP 四层体系结构。

TCP/IP 协议族

应用层

应用层( application-layer )的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程(进程:主机中正在运行的程序)间的通信和交互的规则。

对于不同的网络应用需要不同的应用层协议。在互联网中应用层协议很多,如域名系统 DNS,支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议等等。

运输层

运输层(transport layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务。应用进程利用该服务传送应用层报文。

运输层主要使用以下两种协议

  1. 传输控制协议-TCP:提供面向连接的,可靠的数据传输服务。
  2. 用户数据协议-UDP:提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)。

每一个应用层(TCP/IP参考模型的最高层)协议一般都会使用到两个传输层协议之一:

运行在TCP协议上的协议:

  • HTTP(Hypertext Transfer Protocol,超文本传输协议),主要用于普通浏览。
  • HTTPS(HTTP over SSL,安全超文本传输协议),HTTP协议的安全版本。
  • FTP(File Transfer Protocol,文件传输协议),用于文件传输。
  • POP3(Post Office Protocol, version 3,邮局协议),收邮件用。
  • SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),用来发送电子邮件。
  • TELNET(Teletype over the Network,网络电传),通过一个终端(terminal)登陆到网络。
  • SSH(Secure Shell,用于替代安全性差的TELNET),用于加密安全登陆用。

运行在UDP协议上的协议:

  • BOOTP(Boot Protocol,启动协议),应用于无盘设备。
  • NTP(Network Time Protocol,网络时间协议),用于网络同步。
  • DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),动态配置IP地址。

运行在TCP和UDP协议上:

  • DNS(Domain Name Service,域名服务),用于完成地址查找,邮件转发等工作。

网络层

网络层的任务就是选择合适的网间路由和交换结点,确保计算机通信的数据及时传送。在发送数据时,网络层把运输层产生的报文段或用户数据报封装成分组和包进行传送。在 TCP/IP 体系结构中,由于网络层使用 IP 协议,因此分组也叫 IP 数据报 ,简称数据报。

互联网是由大量的异构(heterogeneous)网络通过路由器(router)相互连接起来的。互联网使用的网络层协议是无连接的网际协议(Intert Prococol)和许多路由选择协议,因此互联网的网络层也叫做网际层或 IP 层。

数据链路层

数据链路层(data link layer)通常简称为链路层。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要使用专门的链路层的协议。

在两个相邻节点之间传送数据时,数据链路层将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息(如同步信息,地址信息,差错控制等)。

在接收数据时,控制信息使接收端能够知道一个帧从哪个比特开始和到哪个比特结束。

一般的web应用的通信传输流是这样的:

发送端在层与层之间传输数据时,每经过一层时会被打上一个该层所属的首部信息。反之,接收端在层与层之间传输数据时,每经过一层时会把对应的首部信息去除。

物理层

在物理层上所传送的数据单位是比特。 物理层(physical layer)的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。使其上面的数据链路层不必考虑网络的具体传输介质是什么。“透明传送比特流”表示经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的。

TCP/IP 协议族

在互联网使用的各种协议中最重要和最著名的就是 TCP/IP 两个协议。现在人们经常提到的 TCP/IP 并不一定是单指 TCP 和 IP 这两个具体的协议,而往往是表示互联网所使用的整个 TCP/IP 协议族。

互联网协议套件(英语:Internet Protocol Suite,缩写IPS)是一个网络通讯模型,以及一整个网络传输协议家族,为网际网络的基础通讯架构。它常被通称为TCP/IP协议族(英语:TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP。因为该协定家族的两个核心协定:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准。

划重点:

TCP(传输控制协议)和IP(网际协议) 是最先定义的两个核心协议,所以才统称为TCP/IP协议族

TCP的三次握手四次挥手

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如ip地址、端口号等。

TCP可以看成是一种字节流,它会处理IP层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在TCP头部。

一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:连接、数据传输、退出(关闭)。通过三次握手建立一个链接,通过四次挥手来关闭一个连接。

当一个连接被建立或被终止时,交换的报文段只包含TCP头部,而没有数据。

TCP报文的头部结构

在了解TCP连接之前先来了解一下TCP报文的头部结构。

上图中有几个字段需要重点介绍下:

(1)序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

(2)确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。

(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

  • ACK:确认序号有效。
  • FIN:释放一个连接。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:发起一个新连接。
  • URG:紧急指针(urgent pointer)有效。

需要注意的是:

  • 不要将确认序号ack与标志位中的ACK搞混了。
  • 确认方ack=发起方seq+1,两端配对。

三次握手

三次握手的本质是确认通信双方收发数据的能力

首先,我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。

于是他给我回信,我若收到了,我便知我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。

然而此时他还不知道他的发件能力和我的收件能力到底可不可以,于是我最后回馈一次**,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。**

这,就是三次握手,这样说,你理解了吗?

  • 第一次握手:客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。
  • 第二次握手:服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
  • 第三次握手:客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。

四次挥手

四次挥手的目的是关闭一个连接

比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。

  • 第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
  • 第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
  • 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
  • 第四次挥手:客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。

常见面试题

为什么TCP连接的时候是3次?2次不可以吗?

因为需要考虑连接时丢包的问题,如果只握手2次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数(可以理解服务端已经连接成功)据,而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端发过来的数据。

如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。

为什么TCP连接的时候是3次,关闭的时候却是4次?

因为只有在客户端和服务端都没有数据要发送的时候才能断开TCP。而客户端发出FIN报文时只能保证客户端没有数据发了,服务端还有没有数据发客户端是不知道的。而服务端收到客户端的FIN报文后只能先回复客户端一个确认报文来告诉客户端我服务端已经收到你的FIN报文了,但我服务端还有一些数据没发完,等这些数据发完了服务端才能给客户端发FIN报文(所以不能一次性将确认报文和FIN报文发给客户端,就是这里多出来了一次)。

为什么客户端发出第四次挥手的确认报文后要等2MSL的时间才能释放TCP连接?

这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

完结

Redis基于内存,常用作于缓存的一种技术,并且Redis存储的方式是以key-value的形式。Redis是如今互联网技术架构中,使用最广泛的缓存,在工作中常常会使用到。Redis也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一,因此作为Java开发者,Redis是我们必须要掌握的。

Redis 是 NoSQL 数据库领域的佼佼者,如果你需要了解 Redis 是如何实现高并发、海量数据存储的,那么这份腾讯专家手敲《Redis源码日志笔记》将会是你的最佳选择。

会使用到。Redis也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一,因此作为Java开发者,Redis是我们必须要掌握的。

Redis 是 NoSQL 数据库领域的佼佼者,如果你需要了解 Redis 是如何实现高并发、海量数据存储的,那么这份腾讯专家手敲《Redis源码日志笔记》将会是你的最佳选择。

[外链图片转存中…(img-SDMIW6Pi-1626022927679)]

感兴趣的朋友可以通过点赞+戳这里的方式免费获取腾讯专家手写Redis源码日志笔记pdf版本!

<think>首先,用户的问题是:“我想将Java对象进行强制类型转换的方法和注意事项 请问Java对象强制类型转换 如何进行Java对象的强转”。这涉及到Java对象强制类型转换。 我需要参考提供的引用。引用[1]、[2]、[3]、[4]都提到了Java类型转换,但引用[4]似乎有点偏离主题,因为它谈到了Redis,而不是直接关于对象强制类型转换。引用[4]说:“java对象强制类型转换看完直接。Redis基于内存,常用作于缓存的一种技术...”,这看起来像是标题或误导,但内容是关于Redis的。所以,我应该只使用相关部分。 关键引用: - 引用[1]:解释了基本类型和引用类型的强制转换。 - 引用[2]:讨论了基本类型的强制转换规则。 - 引用[3]:强调了Java是强类型语言,赋值时需类型检查。 - 引用[4]:标题提到对象强制类型转换,但内容是关于Redis的,所以我应该忽略不相关部分。 用户的问题是针对Java对象(引用类型)的强制类型转换。所以,我要聚焦在引用类型的强制转换上。 系统级指令: - 所有行内数学表达式用$...$格式。但在这个上下文中,可能没有数学表达式,所以不需要。 - 独立公式用$$...$$并单独成段。同样,可能不适用。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,保证真实可靠。 用户可见层:回答结构清晰,逐步解决问题。 所以,我的回答应该包括: 1. 介绍Java对象强制类型转换的概念。 2. 方法:如何执行强制类型转换。 3. 注意事项:常见错误、类型检查等。 4. 添加引用标识。 5. 生成相关问题。 结构: - 开头简要介绍。 - 然后详细解释方法和注意事项。 - 结束时生成相关问题。 引用添加:当引用时,在段落末尾添加[^n]。 现在,基于引用: - 从引用[1]:Java中的类型强制转换分为基本类型和引用类型。引用类型的强制转换涉及类层次结构。 - 引用[3]:Java是强类型语言,赋值需类型兼容。 - 引用[4]虽然标题是对象强制类型转换,但内容不相关,所以我应该基于常识和标准知识。 标准Java知识: - 对象强制类型转换:当你有父类引用指向子类对象时,可以向下转型(downcasting)。 - 使用语法:`(TargetType) object`。 - 注意事项:必须确保对象实际上是目标类型的实例,否则会抛出ClassCastException。 - 使用instanceof检查类型。 方法: 1. 语法:`Subclass obj = (Subclass) superclassRef;` 2. 使用instanceof操作符进行安全转换。 注意事项: - 确保对象是目标类型或其子类。 - 避免不必要的转换。 - 理解继承关系。 在回答中,自然地融入引用: - 例如,引用[1]提到引用类型的强制转换在底层原理不同,我可以提到。 - 引用[3]强调类型检查。 最后,生成相关问题: - 例如,关于性能、优化、应用场景等。 完整回答结构: 1. 介绍Java对象强制类型转换。 2. 解释方法。 3. 讨论注意事项。 4. 添加引用。 5. 生成相关问题。 使用中文。</think>### Java对象强制类型转换的方法和注意事项 在Java中,对象强制类型转换(也称向下转型或downcasting)是一种将父类引用转换为子类引用的操作。这通常在多态场景中使用,当您知道一个对象实际上是某个子类的实例时,可以通过强制转换来访问子类特有的方法或属性。Java是强类型语言,因此在赋值或方法调用时,编译器会进行严格的类型检查[^3]。下面我将逐步解释强制类型转换的方法、关键注意事项,以及如何安全地进行操作。本文基于Java标准规范,并结合了相关引用内容。 #### 1. **强制类型转换的基本方法** Java对象强制类型转换的语法很简单:使用圆括号将目标类型包裹在对象引用前。格式为:`(TargetType) objectReference`。其中,`TargetType`必须是对象实际类型的子类或实现类(如果涉及接口)。以下是具体步骤和示例: - **步骤**: 1. 确认对象引用是父类类型(如`SuperClass`),但实际指向子类对象(如`SubClass`)。 2. 使用强制转换语法将引用转换为目标子类类型。 3. 访问子类特有的成员。 - **示例代码**: 假设有一个父类`Animal`和一个子类`Dog`: ```java class Animal { public void eat() { System.out.println("Animal is eating"); } } class Dog extends Animal { public void bark() { System.out.println("Dog is barking"); } } public class Main { public static void main(String[] args) { Animal animal = new Dog(); // 父类引用指向子类对象(向上转型) // 强制类型转换:将Animal引用转换为Dog类型 Dog dog = (Dog) animal; // 正确转换,因为animal实际是Dog实例 dog.bark(); // 输出: Dog is barking } } ``` 在这个例子中,`animal`引用在运行时是`Dog`对象,因此强制转换成功。如果转换失败(例如,对象不是目标类型),会抛出`ClassCastException`[^1]。 #### 2. **注意事项** 强制类型转换虽然强大,但容易引发错误。以下是关键注意事项,帮助您避免常见问题: - **确保类型兼容性**:在转换前,必须验证对象是否确实是目标类型的实例。否则,运行时会抛出`ClassCastException`。这可以通过`instanceof`操作符进行安全检查: ```java if (animal instanceof Dog) { Dog dog = (Dog) animal; // 安全转换 dog.bark(); } else { System.out.println("Cannot cast to Dog"); } ``` 引用[3]强调,Java的强类型特性要求赋值时类型兼容,否则编译或运行时会失败[^3]。 - **避免不必要的转换**:如果父类引用已经能访问所需方法(通过多态),就不需要强制转换。过度使用转换会增加代码复杂性和错误风险。例如,在`Animal`类中添加`bark()`方法(如果适用),可以避免向下转型。 - **理解继承和接口关系**:强制转换只适用于类层次结构。如果试图将无关类(如`String`转`Integer`)进行转换,会导致`ClassCastException`。引用[1]指出,引用类型的强制转换在底层依赖于对象的实际类型信息(存储在JVM的类型元数据中),如果类型不匹配,JVM会拒绝转换[^1]。 - **性能影响**:强制类型转换本身开销很小,但`instanceof`检查可能引入轻微性能损耗(通常在纳秒级)。在性能敏感场景中,应优先使用多态而非频繁转换。 - **泛型与强制转换**:在泛型代码中,强制转换可能表示设计问题。例如,使用`List<Object>`存储不同类型对象强制转换,容易出错。推荐使用泛型边界(如`<T extends SuperClass>`)来确保类型安全。 - **常见错误场景**: - 转换未初始化的对象(`null`引用转换不会抛出异常,但后续操作失败)。 - 在集合类中错误转换元素(例如,从`List`中取出元素后强制转换,需先用`instanceof`检查)。 #### 3. **安全最佳实践** - **始终使用instanceof**:在转换前进行类型检查,这是防止`ClassCastException`的标准做法。 - **单元测试**:编写测试用例覆盖转换逻辑,确保在边界条件下(如错误类型输入)行为正确。 - **利用多态**:重构代码以减少转换需求,例如通过方法重写或接口实现。 - **日志和异常处理**:在catch块中处理`ClassCastException`,提供有意义的错误信息: ```java try { Dog dog = (Dog) animal; dog.bark(); } catch (ClassCastException e) { System.err.println("Type cast failed: " + e.getMessage()); } ``` Java对象强制类型转换是处理继承多态的核心技术,但需谨慎使用以确保代码健壮性。引用[2]提到,强制转换本质上是“手动执行类型窄化”,而自动转换(向上转型)由Java处理[^2]。在实际开发中,遵循上述方法可有效避免运行时错误。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值