精华内容
下载资源
问答
  • 在同一个类中定义名字相同方法,但是参数类型和个数不同,这些方法之间关系就是重载。重载方法在编译期就完成识别。具体到每一个方法调用,java编译器会根据所传入参数声明类型来选择重载方法。重载...

    JVM是如何执行方法调用的

    在java程序中,一个类中出现多个名字相同,并且参数也相同的方法,那么他们是无法编译通过的。

    重载:

          在同一个类中定义名字相同的方法,但是参数的类型和个数不同,这些方法之间的关系就是重载。重载的方法在编译期就完成识别。具体到每一个方法调用,java编译器会根据所传入的参数的声明类型来选择重载方法。重载方法在编译阶段已经完成。

         选择过程分为三个阶段:

        1 不考虑对基本类型的自动拆装箱,以及可变长参数的情况下选取重载方法。

        2 上述情况下没有找到适配的方法,那么在允许自动拆箱的,不允许可变长参数的情况下选取重载方法。

        3 上述情况未找到适配的方法,那么在允许自动拆箱的,允许可变长参数的情况下选取重载方法。

    重载也可以发生在父子类中。如果子类定义了与父类中非私有方法同名的方法,而且这两个方法的参数类型不同,那么在子类中,这两个方法构成了重载。

    重写:

         父子类中如果两个方法都是静态的,那么子类的方法隐藏了父类的方法。如果这两个方法都不是静态的也不是私有的,方法名和参数类型相同,那么子类的方法重写了父类的方法。JAVA一个很重要的特性便是多态,方法重写就是多态的体现。允许子类继承父类的部分功能,也可以拥有自己独特的行为。

    JVM的静态绑定和动态绑定:

            某些文章中也称重载为静态绑定,重写为动态绑定。静态绑定:JVM在解析时便能够直接识别目标方法。动态绑定:需要在运行过程中根据调用者的动态类型来识别目标方法。

           JVM识别虚拟机方法的关键在于类名,方法名以及方法描述符方法描述符是由方法的参数类型和返回类型构成的。同一个类中同时出现多个名字相同切描述符也相同的方法,那么JVM在验证阶段报错。JVM能够通过方法描述符准确的识别目标方法。

    JVM中关于方法的重写的判定就是基于方法描述符的。也就是说,如果子类定义了与父类中非私有的,非静态的同名方法。那么只有当这两个方法的参数类型和返回方法一致,JVM才会判定重写。

    JAVA字节码调用相关的指令:

         1 invokestatic: 调用静态方法。

         2 invokespecial: 调用私有实例方法,构造器,super调用父类的实例方法和构造器,和实现接口的默认方法。

         3 invokevirtual: 调用非私有实例方法。

         4 invokeinterface: 调用接口方法。

         5  invokedynamic: 调用动态方法。

    调用指令的符号引用:

    编译过程中,我们并不知道目标方法的具体内存地址,JAVA编译器会暂时用符号引用来表示该目标方法。符号引用包括目标方法所在的类或接口的名字,以及目标方法的文件名和方法描述符。

    符号引用存储在class文件的常量池中。在执行使用符号引用的字节码前,JVM需要解释这些符号引用,并替换成实际引用。对于可以静态绑定的方法调用而言,实际引用是一个指向方法的指针。对于需要动态绑定的方法调用而言,实际引用是一个方法表的索引。

     

    虚方法:

         java里所有非私有实例方法调用都会被编译成invokevirtual指令。而接口方法调用都会被编译成invokeinterface指令。这两种指令都属于JVM的虚方法调用。

    静态绑定包括用于调用静态方法的invokestatic指令,和调用构造方法,私有实例方法以及超类非私有实例方法的invokeSpecial指令。

    JVM根据调用者的动态类型,来确定虚方法调用的目标方法,这个过程称为动态绑定。JVM用一种空间换时间的策略来实现动态绑定。

     

    方法表:

         类加载的准备阶段,除了静态字段的内存分配外,还会构造与该类相关联的方法表。这个数据结构是JVM实现动态绑定的关键所在。

         方法表本质是一个数组。每个数组元素指向一个当前类以及祖先类中非私有的实例方法。方法表满足俩个特质:1 子类方法表中包含父类方发表中所有方法。  2  子类方法在方法表中的索引值与所重写的父类方法的索引值相同。对于静态绑定的方法调用而言,实际引用将指向具体的目标方法。对于动态绑定的方法调用而言,实际引用则是方法表的索引值。在执行过程中,JVM将获取调用者的实际类型,并在该实际类型的虚方法表中,根据索引值获得目标方法。

         实际上,使用方法表的动态绑定与静态绑定相比,仅仅多出几个内存引用操作,访问栈上的调用者,读取调用者的动态类型,读取该类型的方法表,读取方法表中某个索引值对应的目标方法。

    但是即时编译还拥有两种性能更好的优化手段:内联缓存和方法内联。

    内联缓存:

         内联缓存是一种加快动态绑定的优化技术。他能够缓存虚方法调用中调用者的动态类型,以及该类型所对应的目标方法。之后的执行过程中,如果碰到已缓存的类型,内联缓存变回直接调用该类型所对应的目标方法,如果没有碰到已缓存的类型,内联缓存则退化到使用基于方法表的动态绑定。

     

    这部分资料看的脑壳疼,看了好多遍算是理顺了。。。    

    展开全文
  • 达内 coreJava 习题答案

    2010-02-10 19:49:01
    6、输出所有水仙花,把谓水仙花是指一个3位数,其各各位数字立方和等于其本身, 例如: 153 = 1*1*1 + 3*3*3 + 5*5*5 class DafodilNumber{ public static void main(String[] args){ System.out....
  • 文章目录一、Java基本数据类型关注点1:基本类型默认值0关注点2:开发时候注意数据溢出问题关注点3:不同类型不能自动装箱关注点4:MySQL int取值范围(先记在这,哈哈)二、浮点类型关注点1:原码、反码...

    一、Java中的基本数据类型

    Java中共有8种数据类型,分为三大类。
    字符型:char
    布尔型:boolean
    数值型:1. 整型:byte、short、int、long;2. 浮点型:float、double
    String不是基本数据类型,是引用类型。

    在这里插入图片描述


    关注点1:基本类型默认值0

    从表中可以看到基本数据类型的起始默认值都是0,但是每个之间都有区别。例如,char默认值是单引号'\u0000'表示NUL(空的不可见字符),其码值是0
    boolean类型的默认值是false,在JVM中仍然使用ICONST_0字节码指令赋值,即常数0

    boolean b = false;
    1: iconst_0
    2: istore_1
    

    关注点2:开发的时候注意数据溢出问题

    数据溢出的时候并不会报错,也没有任何提示。

    int i = 2147483647;
    int j = 1;
    System.out.println(i + j); 
    运行结果:-2147483648
    

    因此需要开发人员在同类型数据运算时,注意数据溢出的问题,并避免编写容易导致溢出的代码。

    int mid = (i + j) / 2;
    替换为
    int mid = i + (j - i) / 2;
    

    关注点3:不同类型不能自动拆装箱

    int i = 0;
    Long j = i;
    

    int类型的包装类是Integer,无法转化成Long类型。


    关注点4:MySQL int的取值范围(先记在这,哈哈)

    记得有这样一道面试题:如果采用自增int作为主键,主键不够用怎么办。很多小伙伴可能会答换成更大的类型long。无符号int类型作为主键,有着很大的取值范围,如果表的记录无需到达int取值上限,就需要考虑分表了。

    二、浮点类型

    关注点1:原码、反码、补码、移码

    对于正数,原码、反码、补码相同,均为正数本身。
    对于负数:原码的符号位是1。反码符号位为1,其他位为原码取反。补码为反码末尾加1。

    原码的出现是为了引入负数。

    原码:1111 1111 ~ 0111 1111
    真值范围:-127 ~127255个)
    其中1000 00000000 0000都表示0
    

    原码存在带符号位运算的问题。

    -1:1000 0001(原码)
    +1:0000 0001(原码)
    加和:1000 0010(原码) = -2是不正确的
    

    反码的定义:如果是正数则保持不变,如果是负数,则除符号位之外按位取反。

    -1:1111 1110(反码)
    +1:0000 0001(反码)
    加和:1111 1111(反码) = 1000 0000(原码) = -0 = 0
    

    补码的出现用于解决+0和-0的问题。补码的定义就是正数和 0 的补码不变,负数的补码是其对应的正数按位取反再 +1。有了补码,8进制就可以用1000 0000表示-128,此时8进制可以表示256个数。

    -1:1111 1111(补码)
    +1:0000 0001(补码)
    加和:(1)0000 0000(补码) = 0000 0000(原码) = 0
    

    移码是将符号位取反的补码。

    PS: 对于按位与操作,非常典型的场景是用于获取当前IP网段,即IP地址与掩码255.255.255.0进行按位与运算得到高24位。


    关注点2:浮点数的表示

    计算机内部采用二进制表示,浮点数是对实数的近似数值表示,其采用科学计数法来表示,由符号位、指数和有效数字三部分组成。
    以单精度浮点数为例,占4个字节32位,32位包含1个符号位、8个指数位和23个有效数字。有效数字位是小数点后二进制表示。

    符号位:0表示正数,1表示负数。
    指数位:存储指数对应的移码。将[-128, 127]平移成正数域,IEEE标准规定指数范围是[-126, 127]。指数位仅用于表示科学计数法指数大小。
    尾数位:以原码表示。正数为1,尾数形式为1.xyzxyz即有效数字。\

    例1:16.35

    0100-0001-1000-0010-1100-1100-1101
    0:表示正数
    100-0001-1131-127=4,表示指数是2^4=16
    000-0010-1100-1100-1101:尾数0.35
    

    例2:0.35

    0011-1110-1011-0011-0011-0011-0011
    0:表示正数
    011-1110-1127-127=1,表示20次方
    011-0011-0011-0011-0011:尾数位
    

    同样是0.35,为何尾数位不同?

    0.35(十进制) = 0.0101100110011001(二进制)
    16.35(十进制)= 1.0000010110011001(二进制)
    

    例2中尾数位是正确的,而对于例1中16.35,16的二进制为10000,转换为小数点前1的规格化是1.0000 * 2^4,占用了4个有效数字位。


    关注点3:定点数表示金额

    如上分析,使用浮点数是不一定能表示正确的数值,正如1-0.9结果不是0.1。在实际开发过程中,对精度要求高的运算过程都是采用定点数表示,并且是使用BigDecimalString参数构造器!!

    public class BigDecimalTest {
        @Test
        public void test1(){
            System.out.println(0.05 + 0.01);
        }
        @Test
        public void test2(){
            BigDecimal b1 = new BigDecimal(0.05);
            BigDecimal b2 = new BigDecimal(0.01);
            System.out.println(b1.add(b2));
        }
        @Test
        public void test3(){
            BigDecimal b1 = new BigDecimal("0.05");
            BigDecimal b2 = new BigDecimal("0.01");
            System.out.println(b1.add(b2));
        }
    }
    运行结果:
    0.060000000000000005
    0.06000000000000000298372437868010820238851010799407958984375
    0.06
    

    三、随机数与类型转换

    关注点1:生成随机数的方法

    返回[0, 10)中的随机整数
    1. (int)(Math.random() * 10)
    2. 利用Random工具类
    Random rand = new Random();
    rand.nextInt(10);
    

    因此,四舍五入等于当前数值加上0.5,再向下取整。方法适用于正负数。

    关注点2:类型提升

    (1)将比较小的类型(char/byte/short)传递给Integer.toBinaryString()方法,则该类型会自动转换为int。
    (2)基本数据类型执行算数计算或按位运算时,只要类型比int小(char、byte、short类型),运算之前会总动转为int类型,得到的结果也是int类型。如果往回赋值,截断。例如,short类型-1在无符号右移10位,值仍为-1。
    案例1:按位运算

    short s = -1;
    s = s >>> 10;
    过程:
    1. 原二进制表示: 
    1111 1111 1111 1111
    2. 先转换为32int类型
    1111 1111 1111 1111 1111 1111 1111 1111
    3. 进行移位操作
    0000 0000 0011 1111 1111 1111 1111 1111
    4. 赋值给s,截断
    1111 1111 1111 1111
    

    案例2:算数运算

    short x = 1;
    short y = 2;
    x = (short)(x * y);
    x *= y;
    

    复合赋值不需要强制类型转换。

    关注点3:除了布尔值外,其他基本数据类型可以相互转换。

    展开全文
  • 从两个不同的方向把链表连接起来,如此一来,从两个不同的方向形成了两条链,因此成为双链表。因此,双链表的灵活度要大于单链表。 结点的删除: <img alt="" src=...
  • 可以在不同的范围,以不同的顺序获取和释放锁 本工程中是从死锁、如何避免死锁、同步锁、读-写同步锁方面来介绍。 新增了 趣味练习:synchronized + 线程的挂起与唤醒,猜猜看输出什么? ...
  • 可能使用的都是不同的容器,无法进行内存或数据共享。如果要共享数据,则只能通过第三方服务,比如 Redis 等。</li><li>无运维</li><li>使用 Serverless 我们不需要关心服务器,不需要关心...
  •  软件分为32位和64位2种版本,分别支持32位和64位操作系统。  本程序需要JAVA环境支持。  如果您操作系统没有安装JAVA,请自行从JAVA官方网站http://java.com下载并安装。  如果没有安装JAVA,系统启动时会...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

java数拆分为不同的数

java 订阅