😉😉 学习交流群:
✅✅1:这是孙哥suns给大家的福利!
✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料
🥭🥭3:QQ群:583783824 📚📚 工作微信:BigTreeJava 拉你进微信群,免费领取!
🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞
💞💞5:以上内容,进群免费领取呦~ 💞💞💞💞
文章目录
一:方法的调用
我们每天都在写方法的调用,但是我们能搞明白其中的原理和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修饰即可。
文章目录
前言
网络与通信中可以根据其数据发送方法进行多种分类。分类方法也有很多以下我们几种
一:面向有连接型与面向无连接型
1:大致概念
通过网络发送数据,大致可以分为面向有连接与面向无连接两种类型:
2:面向有连接型
面向有连接型中,在发送数据"之前,需要在收发主机之间连接一条通信线路
面向有连接型就好比人们平常打电话,输入完对方电话号码拨出之后,只有对端拿起电话才能真正通话,通话结束后将电话机扣上就如同切断电源。
因此在面向有连接的方式下,必须在通信传输前后,专门进行建立和断开连接的处理。如果与对端之间无法通信,就可以避免发送无谓的数据。
3:面向无连接型
面向无连接型则不要求建立和断开连接。发送端可于任何时候自由发送数据。反之,接收端也永远不知道自己会在何时从哪里收到数据。因此,在面向无连接的情况下,接收端需要时常确认是否收到了数据。
这就如同人们去邮局寄包裹一样。负责处理邮递业务的营业员,不需要确认收件人的详细地址是否真的存在,也不需要确认收件人是否能收到包裹,只要发件人有一个寄件地址就可以办理邮寄包亵的业务。面向无连接通信与电话通信不同,它不需要拨打电话、挂掉电话之类的处理,而是全凭发送端自由地发送自己想要传递出去的数据。
因此,在面向无连接的通信中,不需要确认对端是否存在。即使接收端不存在或无法接收数据,发送端也能将数据发送出去。
二:电路交换与分组交换
1:分组交换概念
目前,网络通信方式大致分为两种:电路交换和分组交换。
电路交换技术的历史相对久远,主要用于过去的电话网。而分组交换技术则是一种较新的通信方式,从20 世纪60年代后半叶才开始逐渐被人们认可。本系列文章着力介绍的 TCP/IP,正是采用了分组交换技术。
交换机与交换机之间则由众多通信线路再继续连接。因此计算机之间在发送数据时,需要通过交换机与目标主机建立通信电路。我们将连接电路称为建立连接。建立好连接以后,用户就可以一直使用这条电路,直到该连接被断开为止。
如果某条电路只是用来连接两台计算机的通信线路,就意味着只需在这两台计算机之间实现通信,因此这两台计算机是可以独占线路进行数据传输的。但是,如果一条电路上连接了多台计算机,而这些计算机之间需要相互传递数据,就会出现新的问题。鉴于一台计算机在收发信息时会独占整个电路,其他计算机只能等待这台计算机处理结束以后才有机会使用这条电路收发数据。并且在此过程中谁也无法预测某一台计算机的数据传输从何时开始又在何时结束。如果并发用户数超过交换机之间的通信线路数,就意味着通信根本无法实现。
为此,人们想到了一个新的方法,即让连接到通信电路的计算机将所要发送的数据分成多个数据包,按照一定的顺序排列之后分别发送。这就是分组交换。有了分组交换,数据被细分后,所有的计算机就可以一齐收发数据,这样也就提高了通信线路的利用率。由于在分组的过程中,已经在每个分组的首部写人了发送端和接收端的地址,所以即使同一条线路同时为多个用户提供服务,也可以明确区分每个分组数据发往的目的地,以及它是与哪台计算机进行的通信。
2:分组交交换过程
在分组交换中,由分组交换机(路器) 连接通信线路。
分组交换的大致处理过程是:发送端计算机将数据分组发送给路由器,路由器收到这些分组数据以后,缓存到自己的缓冲区,然后再转发给目标计算机。因此,分组交换也有另一个名称:蓄积交换。
路由器接收到数据以后会按照顺序缓存到相应的队列当中,再以先进先出的顺序将它们逐一发送出去。
在分组交换中,计算机与路由器之间以及路由器与路由器之间通常只有一条通信线路。因此,这条线路其实是一条共享线路。在电路交换中,计算机之间的传输速度不变。然而在分组交换中,通信线路的速度可能会有所不同。根据网络拥堵的情况,数据达到目标地址的时间有长有短。另外,路由器的缓存饱和或溢出时,至可能会发生分组数据丢失、无法发送到对端的情况。
三:根据接收端数量分类
网络通信当中,也可以根据目标地址的个数及其后续的行为对通信进行分类如广播、多播等就是这种分类的产物。
1:单播
字面上就是指1对1通信。早先的固定电话就是单播通信的一个典型例子。
2:广播
字面上具有“播放”之意。因此它指是将消息从1台主机发送给与之相连的所有其他主机。广播通信"的一个典型例子就是电视播放,它将电视信号一齐发送给非特定的多个接收对象。
此外,我们知道电视信号一般都有自己的频。只有在相应频段的可接收范围内才能收到电视信号。与之类似,进行广播通信的计算机也有它们的广播范围。只有在这个范围之内的计算机才能收到相应的广播消息。这个范围叫做广播域。
3:多播
多播与广播类似,也是将消息发给多个接收主机。不同之处在于多播要限定某一组主机作为接收端。多播通信"最典型的例子就是电视会议,这是由多组人在不同的地方参加的一种远程会议。在这种形式下,会由一台主机发送消息给特定的多台主机。电视会议通常不能使用广播方式。否则将无从掌握是谁在哪儿参与电视会议。
4:任播
通信任播是指在特定的多台主机中选出一台作为接收的一种通信方式。虽然这种方式与多播有相似之处,都是面向特定的一群主机,但是它的行为却与多播不同。任播通信“从目标主机群中选择一台最符合网络条件的主机作为目标主机发送消息。通常,所被选中的那台特定主机将返回一个单播信号,随后发送端主机会只跟这台主机进行通信。
任播在实际网络中的应用有 DNS 根域解服器