Java之隐秘的角落

概况

主要说下工作中经常见到,但是不经常使用的一些小知识

断点调试

基础使用

  1. 运行到下一行

  2. 进入自定义方法(就是你自己写的方法)

  3. 跳出方法

  4. 查看所有的断点

  5. 让断点失效

  6. 跳出jdk中定义的方法,与3类似

  7. 进入jdk中定义的方法,与2类似

  8. 综合了2和7

  9. 跳出当前执行的方法,例如:打断点进入这个方法,大眼一看就不是这个方法的问题,就可以用这个

  10. 针对自定义代码,不需要打断点,光标放在哪一行,就跳转的哪一行,前提是能执行到你的光标位置

  11. 针对jdk代码,不需要打断点,光标放在哪一行,就跳转的哪一行,前提是能执行到你的光标位置

  12. 跳转到正在执行的那一行,你打断点的时候,已经执行了几行,手动点击了很多方法,这个可以一下回到代码正在执行的位置

  13. 值就算器,可以计算当前内存中的值

  14. 我也不知道

  15. 强制返回,有时候好不容易造一条数据,代码一执行,数据就要重新造,只能停止项目,再重启,就可以用这个方法

  16. 同15,不过是抛异常的形式

条件断点

如图,我想让它在i=500的时候执行断点

接口

jdk8之前,接口中只能定义抽象方法

jdk8中,接口可以直接声明静态方法,普通方法(使用default关键字修饰)

jdk9中,接口可以声明为私有方法,供默认方法调用

public interface InterfaceA {

    //jdk1.8之前义抽象方法
    void showA();

    //jdk1.8定义静态方法
    static void showA(){
        System.out.println("定义静态方法");
    }
    
    //jdk1.8定义普通方法
    default void showB(){
        System.out.println("定义普通方法");
    }

   //jdk9中定义普通方法
   private String showC(){
        return "定义了私有方法";
    }

   //jdk9中使用普通方法
   default String showD(){
        return showC();
    }

}

注意点:

  1. 接口中的静态方法只能接口直接调用,实现类不能调用

  2. 当一个实现类实现多个接口时,接口中都含有同名,同参数的默认方法,实现类需要重写默认方法

  3. 当一个实现类的父类和接口空都有同名,同参数的方法,自己未实现该方法,以父类的方法为主(类的优先原则)

  4. 子类调用自己中的方法method(),调用父类中的方法super.method(),调用接口中的默认方法InterfaceA.super.method()

运算符>>>>>

在源码中经常见到位运算符 ,例如在HashMap的源码中有如下表述

 static final int tableSizeFor(int cap) {
     int n = cap - 1;
     n |= n >>> 1;
     n |= n >>> 2;
     n |= n >>> 4;
     n |= n >>> 8;
     n |= n >>> 16;
     return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
 }

那具体代表什么呢?详细内容见 运算符>>和>>>有什么区别以及原码、反码、补码

  1. >> 表示右移,如果该数为正,则高位补0,若为负数,则高位补1。如:int i=15; i>>2的结果是3,移出的部分将被抛弃。

转为二进制的形式可能更好理解,0000 1111(15)右移2位的结果是0000 0011(3),0001 1010(18)右移3位的结果是0000 0011(3)。

  1. >>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。

按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。其他结构和>>相似。

transient关键字

java中的transient关键字,transient是短暂的意思。

对于transient 修饰的成员变量,在类的实例对象的序列化处理过程中会被忽略。 因此,transient变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。

补充知识点

  1. 基础数据类型默认为是序列化的,自定义引用数据类型网络传输过程中需要手动序列化

  2. 静态(static)变量的值不会序列化。因为静态变量的值不属于某个对象。

  3. transient修饰的变量不会序列化