😉😉 学习交流群:
✅✅1:这是孙哥suns给大家的福利!
✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料
🥭🥭3:QQ群:583783824 📚📚 工作微信:BigTreeJava 拉你进微信群,免费领取!
🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞
💞💞5:以上内容,进群免费领取呦~ 💞💞💞💞
文章目录
我们每天都在写方法的调用,但是我们能搞明白其中的原理和JVM当中的操作步骤么?这就是本文的意义。
官方说法:
在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这个符号引用用真实的方法字面量代替
官方说法:
当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接。
说人话:
静态链接:这种方式在编译阶段就已经把符号引用直接转换为了直接引用。
官方说法:
如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接。
说人话:
动态链接:这种方式在运行阶段才能把符号引用直接转换为直接引用。
绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。这个不论是编译器确定还是运行期确定都只会发生一次,不会修改。
对应的方法的绑定机制为:早期绑定 (Early Bindng)和晚期绑定(Late Binding)。
官方说法:
早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也就可以使用静态链接的方式将符号引用转换为直接引用。
说人话:
早期绑定是和我们的静态绑定相对应的。
官方说法:
如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也就被称之为晚期绑定
说人话:
晚期绑定是和我们的动态绑定相对应的。
- 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();//晚期绑定
- }
-
- }
- 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();//晚期绑定
- }
-
- }
光标放到cat这个类上查看他的jclasslib
invokeSpecial是早期绑定字节码指令,invokevirtual是晚期绑定的字节码指令。
随着高级语言的横空出世,类似于Java一样的基于面向对象的编程语言如今越来越多,尽管这类编程语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持封装、继承和多态等面向对象特性
既然这一类的编程语言具备多态特性,那么自然也就具备早期绑定和晚期绑定两种绑定方式。
Java中任何一个普通的方法其实都具备虚函数的特征,也就是运行期才能确定下来,它们相当于c++语言中的虚函数 (c++中则需要使用关键字virtual来显式定义)。
如果在Java程序中不希望某个方法拥有虚函数的特征时,则可以使用关键字final来标记这个方法。也就是一个方法不想被晚期绑定,直接把他给final修饰即可。
文章目录
不从恶人的计谋,不站罪人的道路,不坐亵慢人的座位,惟喜爱耶和华的律法,昼夜思想,这人便为有福!他要像一棵树栽在溪水旁,按时候结果子,叶子也不枯干。凡他所做的尽都顺利。
ISO在制定标准化OSI之前,对网络体系结构相关的问题进行了充分的讨论最终提出了作为通信协议设计指标的 OSI参考模型。这一模型将通信协议中必要的功能分成了7层。通过这些分层,使得那些比较复杂的网络协议更加简单化。
在这一模型中,每个分层都接收由它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务。上下层之间进行交互时所遵循的约定叫做“接口”。同一层之间的交互所遵循的约定叫做“协议”协议分层就如同计算机软件中的模块化开发。
OSI 参考模型的建议是比较理想化的。它希望实现从第一层到第七层的所有模块,并将它们组合起来实现网络通信。分层可以将每个分层独立使用,即使系统中某些分层发生变化,也不会波及整个系统。因此,可以构造一个扩展性和灵活性都较强的系统。此外,通过分层能够细分通信功能,更易于单独实现每个分层的协议,并界定各个分层的具体责任和义务。这些都属于分层的优点。
而分层的劣势,可能就在于过分模块化、使处理变得更加沉重以及每个模块都不得不实现相们的外理逻辑问题
关于协议的分层,我们再以 A 与C对话为简单说明一下。在此,我们只考虑语言层和通信设备层这两个分层的情况
首先,以电话聊天为例,图1.17 上部分中的 A 与C 两个人正在通过电话(通信设备) 用汉语 (语言协议) 聊天。我们详细分析一下这张图。
表面上看 A 跟C是在用汉语直接对话,但实际上 A与C都是在通过电话机的听筒听取声音,都在对着麦克风说话。想象一下如果有一个素未见过电话机的人见到这个场景会怎么想?恐怕他一定会以为 A 和C在跟电话机聊天吧。
其实在这个图中,他们所用的语言协议作为麦克风的音频输入,在通信设备层被转换为电波信号传送出去了。传送到对方的电话机后,又被通信设备层转换为音频输出,传递给了对方。因此,A与C其实是利用电话机之间通过音频转化声音的接口实现了对话
通常人们会觉得拿起电话与人通话,其实就好像是直接在跟对方对话,然而如果仔细分析,在整个过程中实际上是电话机在做中介,人们口中说出的汉语是一层协议,汉语到达电话机之后经过电话机协议进行转换这是电话层的协议。
那么如果我们假定语言层相同而改变了通信设备层,情况会如何? 例如,将电话机改为无线电。通信设备层如果改用无线电,双方依旧可以痛快的通话,整体的内容通信并没有因为一层协议修改而变得不可用
那么,如果通信设备层使用电话机,而语言层改为英语的话情况又会如何?很显然,电话机本身不会受限于使用者使用的语言。因此,这种情况与使用汉语通话时完全一样,依然可以实现通话(上图下部分)。
OSI 参考模型将协议整理并分为了易于理解的7个分层:
OSI参考模型终究是一个“模型”,它也只是对各层的作用做了一系列粗略的界定,并没有对协议和接口进行详细的定义。若想要了解协议的更多细节,还是有必要参考每个协议本身的具体规范。
许多通信协议,都对应了 OSI 参考模型7个分层中的某层。通过这一点,可以大致了解该协议在整个通信功能中的位置和作用。
1:应用层
为应用程序提供服务并规定应用程序中通信相关的细节。包括文件传输、电子邮件、远程登录等协议。
2:表示层
将应用处理的信息转换为适合网络传输的格式,或将来自下一层的数据转换为上层能够处理的格式。因此它主要负责数据格式的转换。具体来说,就是将设备固有的数据格式转换为网络标准传输格式。不同设备对同一比特流解释的结果可能会不同。因此,使它们保持一致是这一层的主要作用。
3:会话层
负责建立和断开通信连接 (数据流动的逻通路),以及数据的分等数据传输相关的管理。
4:传输层
起着可靠传输的作用。只在通信双方节点上进行处理,而无需在路由器上处理。
5:网络层
将数据传输到目标地址。目标地址可以是多个网络通过路由器连接而成的某一个地址。因此这一层主要负责寻址和路由选择。
6:数据链路层
负责物理层面上互连的、节点之间的通信传输。例如与1个以太网相连的2个节点之间的通信。将01序列划分为具有意义的数据帧传送个对方(数据帧的生成与接收)
7:物理层
负责01比特流与电压高低或者是光闪灭之间的转换