admin管理员组

文章数量:1547200

😉😉 学习交流群:

✅✅1:这是孙哥suns给大家的福利!

✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料

🥭🥭3:QQ群:583783824   📚📚  工作微信:BigTreeJava 拉你进微信群,免费领取!

🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞

💞💞5:以上内容,进群免费领取呦~ 💞💞💞💞

文章目录

一:方法的调用

1:概述

2:静态链接

3:动态链接

二:方法的绑定

1:绑定概念

2:早期绑定

3:晚期绑定

三:晚期绑定示例

1:编写代码

2:jclasslib查看内容

四:早期绑定示例 

1:编写代码

2:jclasslib查看内容

五:总结说明


一:方法的调用

        我们每天都在写方法的调用,但是我们能搞明白其中的原理和JVM当中的操作步骤么?这就是本文的意义。

1:概述

        官方说法:

        在JVM中,将符号引用转换为调用方法的直接引用这个操作是跟JVM当中方法的绑定机制息息相关的。

        说人话:

        上边这段话是什么意思?我这里给大家解释一下,我们javap整理完毕字节码文件之后,我们会可以在任意一个方法中查看code下的字节码指令,很多字节码指令的后边都会跟#数字这么一个概念,这个就是符号引用,这个引用指向常量池。

        所谓将符号引用转换为方法的直接引用,就是将这个字节码指令后边的符号引用,转变为真实的方法。

        下列中的#3就是符号引用。

  public void methodB();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #6                  // String methodB().....
         5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: aload_0
         9: invokevirtual #7                  // Method methodA:()V
        12: aload_0
        13: dup
        14: getfield      #2                  // Field num:I
        17: iconst_1
        18: iadd
        19: putfield      #2                  // Field num:I
        22: return

        从上述找一个例子的话,就是将偏移地址为9的字节码指令后边的#7这个符号引用用真实的方法字面量代替

2:静态链接

        官方说法:

        当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接。

        说人话:

        静态链接:这种方式在编译阶段就已经把符号引用直接转换为了直接引用。

3:动态链接

        官方说法:

        如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接。

        说人话:

        动态链接:这种方式在运行阶段才能把符号引用直接转换为直接引用。

二:方法的绑定

1:绑定概念

        绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。这个不论是编译器确定还是运行期确定都只会发生一次,不会修改。

        对应的方法的绑定机制为:早期绑定 (Early Bindng)和晚期绑定(Late Binding)。

2:早期绑定

        官方说法:

        早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也就可以使用静态链接的方式将符号引用转换为直接引用。

        说人话:

        早期绑定是和我们的静态绑定相对应的。

3:晚期绑定

        官方说法:

        如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也就被称之为晚期绑定

        说人话:

        晚期绑定是和我们的动态绑定相对应的。

三:晚期绑定示例

1:编写代码

class Animal {
    public void eat(){
        System.out.println("动物进食");
    }
}

interface Huntable{
    void hunt();
}

class Dog extends Animal implements Huntable{
    @Override
    public void eat(){
        System.out.println("狗吃骨头");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,多管闲事");
    }
}

class Cat extends Animal implements Huntable{
    @Override
    public void eat(){
        System.out.println("猫吃鱼");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,天经地义");
    }
}

public class AnimalTest{
    public void showAnimal(Animal animal){
        animal.eat();//晚期绑定
    }

    public void showHunt(Huntable h){
        h.hunt();//晚期绑定
    }

}

2:jclasslib查看内容

四:早期绑定示例 

1:编写代码

class Animal {
    public void eat(){
        System.out.println("动物进食");
    }
}

interface Huntable{
    void hunt();
}

class Dog extends Animal implements Huntable{
    @Override
    public void eat(){
        super.eat();//早期绑定
        System.out.println("狗吃骨头");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,多管闲事");
    }
}

class Cat extends Animal implements Huntable{
    public Cat(){
        super();//早期绑定
    }
    public Cat(String name){
        this();//早期绑定
    }
    
    @Override
    public void eat(){
        System.out.println("猫吃鱼");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,天经地义");
    }
}

public class AnimalTest{
    public void showAnimal(Animal animal){
        animal.eat();//晚期绑定
    }

    public void showHunt(Huntable h){
        h.hunt();//晚期绑定
    }

}

2:jclasslib查看内容

        光标放到cat这个类上查看他的jclasslib

         invokeSpecial是早期绑定字节码指令,invokevirtual是晚期绑定的字节码指令。

五:总结说明

        随着高级语言的横空出世,类似于Java一样的基于面向对象的编程语言如今越来越多,尽管这类编程语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持封装、继承和多态等面向对象特性

        既然这一类的编程语言具备多态特性,那么自然也就具备早期绑定和晚期绑定两种绑定方式。

        Java中任何一个普通的方法其实都具备虚函数的特征,也就是运行期才能确定下来,它们相当于c++语言中的虚函数 (c++中则需要使用关键字virtual来显式定义)。

        如果在Java程序中不希望某个方法拥有虚函数的特征时,则可以使用关键字final来标记这个方法。也就是一个方法不想被晚期绑定,直接把他给final修饰即可。

文章目录

一:OSI通信模型间数据传输展示

二:应用层到会话层解析

1:应用层

2:表现层

3:会话层

三:传输层到物理层解析

1:传输层

2:网络层

3:数据链路层、与物理层

一:OSI通信模型间数据传输展示

        分析方法可以借鉴下图模型。发送方第7第6层到第1上至下传输数据,而接则从第1层第2到第7层由下至上向每个上一级分层传输数据。每个分层上,在处理由上一层传过来的数据时可以附上当前分层的协议所必须的“首部”信息。然后接收端对收到的数据进行数据“首部”与“内容”的分离,再转发给上一分层,并终将发送端的数据恢复为原状。

二:应用层到会话层解析

        假定用户A要给用户B 发送一封内容为“早上好”邮件。众多的位列与各层中的协议,发挥着各自的作用,从而实现邮件的发送和接收

1:应用层

        用户A在主机A上新建一电子件指定收人为 B并发送内容"叔叔好

        用户 A输入“叔叔好”的这一部分就属于与通信无关的功能,而将“早上好”的内容发送给收件人 B 则是其与通相关的功能。因此,此处的“输入电子邮件内容后发送给目标地址”也就相当于应用层。从用户输人完所要发送的内容并点击“发送”按的那一开始,就进人了应用层协议的处理。该协议会在所要传送数据的前端附加一个首部标签信息。该首部标明了邮件内容收件人为“B”。

         这一附有首部信息的数据传送给主机 B 以后由该机上的收发邮件软件通过“收信”功能获取内容主机B上的应用收到由主机A 发送过来的数据后,如果主机 B上收件人的邮箱空间已满无法接收新的邮件,则会返回一个错误给发送方。对这类异常的处理也正属于应用层需要解决的问题。

2:表现层

        表示层更关注据的具体表现形式。所使用的应用软件本身的不同也会导致数据的表现形式截然不同。比如有的字体处理软件创建的文件只能由该字处器厂商所提供的特定版本的软件才来打开读取。

        解决这类问题有以下几种方法。首先是利用表示层,将数据从“某个计算机特定的数据格式”转换为“网络通用的标准数据格式”后再发送出去。接收端主机收到数据以后将这些网络标准格式的数据恢复为“该计算机特定的数据格式”然后再进行相应处理。

        在前面这个例子中,由于数据被转换为通用标准的格式后再进行处理,使得异构的机型之间也能保持数据的一致性。这也正是表示层的作用所在。即表示层是进行“统一的网络数据格式”与“某一台计算机或某一软件特有的数据格式”之间相互转换的分层。

        此例中的“叔叔好”这文字根据其编码格式被转换成为了“统一的网络数据格式”。即便是一段简单的文字流,也可以有众多复杂的编码格式。如果未能按照特定格式编码,那么在接收端就是收到邮件也可能会是乱码表示层与表示层之间为了识别编码格式也会附加首部信息,从而将实际传输的数据转交给下一层去处理。

3:会话层

        下面,我们来分析在两端主机的会话层之间是如何高效地进行数据交互、采用何种方法传输数据的。

        假定用户 A 新建了5电子件准备发给用户B这5件的发可以有很多种。例如,可以每发一封邮件时建立一次连接”,随后断开连接。还可以一经建立好连接后将5 邮件连续发送给对方。甚至可以同时建立好5个连接,将5 封邮件同时发送给对方。决定采用何种连接方法是会话层的主要责任。会话层也像应用层或表示层那样,在其收到的数据前端附加首部或标签信息后再转发给下一层。而这些首部或标签中记录着数据传送顺序的信息。

三:传输层到物理层解析

1:传输层

        到此为止,我们通过例子说明了在应用层写人的数据会经由表示层格式化编码、再由会话层标记发送顺序后才被发送出去的大致过程。然而,会话层只对何时建立连接、何时发送数据等问题进行管理,并不具有实际传输数据的功能。真正负责在网络上传输具体数据的是会话层以下的“无名英雄”

        传输层主机A确保与主机 B之间的通信并准备发送数据。这一过程叫做“建立连接”。有了这个通信连接就可以使主机 A 发送的电子邮件到达主机 B 中,主机 B 的邮件处理程序获取最终数据。此外,当通信传输结束后,有必要将连接断开。

        如上,进行建立连接或断开连接的处理,在两个主机之间创建逻辑上的通信连接即是传输层的主要作用。此外,传输层为确保所传输的数据到达目标地址会在通信两端的计算机之间进行确认,如果数据没有到达,它会负责进行重发。

        例如,主机 A 将“早上好”这一数据发送给机 B。期间可能会为某原因导致数据被破坏,或由于发生某种网络异常致使只有一部分数据到达目标地址。假设主机 B 只收到了“早上”这一部分数据,那么它会在收到数据后将自已没有收到“早上”之后那部分数据的事实告知主机 A。主机A得知这个情后就会将后面的“好”重发给主机 B,并再次确认对端是否收到。

        这就好比人们日常会话中的确认语句:“对了,你刚才说什么来着?”计算机通信协议其实并没有想象中那么晦涩难懂,其基本原理是与我们的日常生活紧密相连、大同小异的。

        由此可见,保证数据传输的可靠性是传输层的一个重要作用。为了确保可靠性,在这一层也会为所要传输的数据附加首部以识别这一分层的数据。然而,实际上将数据传输给对端的处理是由网络层来完成的。

        传输层作用就是:确立链接、断开链接、保证传输准确性和完整性。

2:网络层

        网络层的作用是在网络与网络相互连接的环境中,将数据从发送端主机发送到接收端主机。如图127 所示,两端机之间然有众多数据链路,能够将数据从主机A送到主机 B也都是网络层的劳。

        网络层的作用就是:主机A到主机B的数据通信处理

        在实际发送数据时,目的地址"至关重要。这个地址是进行通信的网络中唯一指定的序号。也可以把它想象为我们日常生活中使用的电话号码。只要这个目标地址确定了,就可以在众多计算机中选出该目标地址所对应的计算机发送数据。基于这个地址,就可以在网络层进行数据包的发送处理。而有了地址和网络层的包发送处理,就可以将数据发送到世界上任何一台互连设备。网络层中也会将其从上层收到的数据和地址信息等一起发送给下面的数据链路层,进行后面的处理。

        传输层与网络层的关系

        在不同的网络体系结构下,网络层有时也不能保证数据的可达性。例如在相当于TCP/IP 网络层的 IP 协议中,就不能保证数据一定会发送到对端地址。因此,数据传送过程中出现数据丢失、顺序混乱等问题可能性会大大增加。像这样没有可靠性传输要求的网络层中,可以由传输层负责提供“正确传输数据的处理”。TCP/IP 中,网络层与传输层相互协作以确保数据包能够传送到世界各地,实现可靠传输。

        每个分层的作用与功能越清晰,规范协议的具体内容就越简单,实现”这些具体协议的工作也将会更加轻松。

3:数据链路层、与物理层

        通信传输实际上是通过物理的传输介质实现的。数据链路层的作用就是在这些通过传输介质互连的设备之间进行数据处理。

         物理层中,将数据的0转换为电压和脉冲光传输给物理的传输介,而相互直连的设备之间使用地址实现传输。这种地址称为 MAC地址,也可称为物理地址或硬件地址。采用 MAC 地址,目的是为了识别连接到同一个传输介质上的设备。因此,在这一分层中将包含 MAC 地信息的部附加到从网路层转发过来的数据上,将其发送到网络。

        网络层与数据链路层都是基于目标地址将数据发送给接收端的,但是网络层负责将整个数据发送给最终目标地址,而数据链路层则只负责发送一个分段内的数据。

        主机B端的处理接收端主机 B 上的处理流正好与主机A,它从理层开始将接收到的数据逐层发给上一分层进行处理,从而使用户 B在 B用客户端软件接收用户 A发送过来的邮件,并可以读取相应内容为“早上好”如上所述,读者可以将通信网络的功能分层来思考。每个分层上的协议规定了该分层中数据首部的格式以及首部与处理数据的顺序。

文章参考自:图解TCP/IP协议图书

本文标签: 通信详解第三篇模型协议