😉😉 学习交流群:
✅✅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修饰即可。
文章目录
官网地址:http://www.docker.com
仓库地址:https://hub.docker.com
docker.com就是docker的官网,任何的文档都可以从docker网站上查看到。docker是可以安装在Mac、Windows、Linux上
镜像文件和容器虚拟化技术和dockerhub是什么关系呢?dockerhub是安装docker镜像的仓库。
Docker 并非是一个通用的容器工具,它依赖于已存在并运行的 Linux 内核环境。
Docker 实质上是在已经运行的 Linux 下制造了一个隔离的文件环境。因此它执行的效率几乎等同于所部署的 Linux 主机
一个隔离的文件环境,因此Docker 必须部署在 Linux 内核的系统上。如果其他系统想部署 Docker 就必须安装一个虚拟 Linux 环境

目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7(64-bit)上,要求系统为64位、Linux系统内核版本为 3.8以上,这里选用Centos7.x
Docker 镜像 (Image) 就是一个只读的模板。饶像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
它也相当于是一个root文件系统。比如官方镜像 centos7 就包含了完整的一套 centos7最小系统的 root 文件系统。
docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
仓库就是存放镜像的地方,镜像就类似于Java中的类模板。容器就是类new出来的一个一个对象,当然这里也就指的是一个一个的实例。
仓库是集中存放镜像的地方,docker提供了官方存放镜像了仓库。这样的话redis安装下载,就可以直接安装docker run xx进行下载就可以了。
仓库分为公开库和私有库,在国内我们一般使用阿里云或者是网易云等等。自己公司搭建一套也是可以的。
Docker 利用容器(Container) 独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和喝离的运行环境,它可以被启动、开始、停止、刑除。每个容器都是相互喝离的、保证安全的平台
可以把容器看做是一个简易版的Linux环境(包root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
需要正确的理解仓库/镜像/容器这几个概念:
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成 Docker突器实例(类似Java中new出来一个对象)。
image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
image 文件生成的容器实例,本身也是一个文件,称为镜像文件。容器实例
一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
仓库就是放一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了。