zoukankan      html  css  js  c++  java
  • java编译时与运行时概念与实例详解 -------------------(***************************************************************************)

    Java编译时与运行时很重要的概念,但是一直没有明晰,这次专门博客写明白概念.

    基础概念

    编译时 

    编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字节码,.另外还有啥链接器.汇编器.为了了便于理解我们可以统称为编译器) 

    那编译时就是简单的作一些翻译工作,比如检查老兄你有没有粗心写错啥关键字了啊.有啥词法分析,语法分析之类的过程.就像个老师检查学生的作文中有没有错别字和病句一样.如果发现啥错误编译器就告诉你.所以有时一些人说编译时还分配内存啥的肯定是错误的说法.

    运行时 

    所谓运行时就是代码跑起来了.被装载到内存中去了.(你的代码保存在磁盘上没装入内存之前是个死家伙.只有跑到内存中才变成活的).而运行时类型检查就与前面讲的编译时类型检查(或者静态类型检查)不一样.不是简单的扫描代码.而是在内存中做些操作,做些判断.(这样很多编译时无法发现的错误,在运行就可以发现报错了,最好还是写的的时候就避免这个逻辑错误就好了)

    举列子

    1
    2
    3
    4
    int arr[] = {1,2,3};
    int result = arr[4];
    System.out.println(result);
    Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 4

    上面的代码你一瞧你知道是错误的代码,数组越界了.但用编译器没有报错,run后才出现了ArrayIndexOutOfBoundsException.可见编译器其实还是挺笨的,还没你脑瓜子那么聪明啊,于是你想虽然编译器笨了点,但运行起来时发现了错误也还不算太坏.

    面试题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    理解这几个概念可以更好地帮助你去了解一些基本的原理。下面是初学者晋级中级水平需要知道的一些问题。
    Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢?
     
    public class ConstantFolding {
     
     static final int number1 = 5;
     
     static final int number2 = 6;
     
     static int number3 = 5;
     
     static int number4= 6;
     
     public static void main(String[ ] args) {
     
     int product1 = number1 * number2; //line A
     
     int product2 = number3 * number4; //line B
     
     }
     
    }
                                                                                                                                                                                

    A.在行A的代码中,product的值是在编译期计算的,行B则是在运行时计算的。如果你使用Java反编译器(例如,jd-gui)来反编译ConstantFolding.class文件的话,那么你就会从下面的结果里得到答案。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class ConstantFolding
    {
     static final int number1 = 5;
     static final int number2 = 6;
     static int number3 = 5;
     static int number4 = 6;
     
     public static void main(String[ ] args)
     {
     int product1 = 30;
     int product2 = number3 * number4;
     }
    }

    常量折叠是种Java编译器使用的优化技术。由于final变量的值不会改变,因此就可以对它们优化。Java反编译器和javap命令都是查看编译后的代码(例如,字节码)的利器。

    方法重载:这个是发生在编译时的。方法重载也被称为编译时多态,因为编译器可以根据参数的类型来选择使用哪个方法。

    1
    2
    3
    4
    public class {
     public static void evaluate(String param1); // method #1
     public static void evaluate(int param1); // method #2
    }

    如果编译器要编译下面的语句的话:

    1evaluate(“My Test Argument passed to param1”); 

    它会根据传入的参数是字符串常量,生成调用#1方法的字节码

    方法覆盖:这个是在运行时发生的。方法重载被称为运行时多态,因为在编译期编译器不知道并且没法知道该去调用哪个方法。JVM会在代码运行的时候做出决定。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class A {
     public int compute(int input) { //method #3
     return 3 * input;
     }
    }
     
    public class B extends A {
     @Override
     public int compute(int input) { //method #4
     return 4 * input;
     }
    }

    子类B中的compute(..)方法重写了父类的compute(..)方法。如果编译器遇到下面的代码:

    1
    2
    3
    public int evaluate(A reference, int arg2) {
     int result = reference.compute(arg2);
    }

    编译器是没法知道传入的参数reference的类型是A还是B。因此,只能够在运行时,根据赋给输入变量“reference”的对象的类型(例如,A或者B的实例)来决定调用方法#3还是方法#4

    泛型(又称类型检验):这个是发生在编译期的。编译器负责检查程序中类型的正确性,然后把使用了泛型的代码翻译或者重写成可以执行在当前JVM上的非泛型代码。这个技术被称为“类型擦除“。

    换句话来说,编译器会擦除所有在尖括号里的类型信息,来保证和版本1.4.0或者更早版本的JRE的兼容性。

    1List myList = new ArrayList(10); 

    编译后成为了:

    1List myList = new ArrayList(10); 

    异常(Exception):你可以使用运行时异常或者编译时异常。

    运行时异常(RuntimeException)也称作未检测的异常(unchecked exception),这表示这种异常不需要编译器来检测。

    RuntimeException是所有可以在运行时抛出的异常的父类。一个方法除要捕获异常外,如果它执行的时候可能会抛出

    RuntimeException的子类,那么它就不需要用throw语句来声明抛出的异常。 

    例如:NullPointerException,ArrayIndexOutOfBoundsException,等等 

    受检查异常(checked exception)都是编译器在编译时进行校验的,通过throws语句或者try{}cathch{} 语句块来处理检测异常。编译器会分析哪些异常会在执行一个方法或者构造函数的时候抛出。

    public class Main {
        public static void main(String[] args) {
            String a = "a";
            String b = "b";
            String s1= a + b;
            String s2= a + b;
            System.out.println(s1 == s2);
        }
    }

    执行结果为: false。 
    我们反编译生成的class文件:

    我们知道,对于字符串进行 a + b的代码,运行中是这样处理的: 
    String s2 = (new StringBuffer()).append(a).append(b).toString(); 
    所以最终得到的s1和s2是不相等(==)的。 (https://blog.csdn.net/feigeswjtu/article/details/78996691

    自古英雄出炼狱,从来富贵入凡尘。
  • 相关阅读:
    Linux下openSSL安装并颁发证书
    js控制自动上传文件
    Swoole 4.5v安装使用
    Flask-SQLAlchemy 的基本使用
    Flask入门之二
    微信消息订阅
    Flask入门之一
    MySQL主从库快速搭建
    FastAPI连接mysql傻瓜式
    UOJ Round总结
  • 原文地址:https://www.cnblogs.com/yunliu0603/p/11138552.html
Copyright © 2011-2022 走看看