BlazeMaple BlazeMaple
首页
  • 基础知识

    • Java的基本数据类型
    • Java中的常用类String
    • Java中的异常
    • Java中的注解
    • Java中的反射机制
    • Java中的泛型
    • Java为什么是值传递
  • 集合框架

    • Java集合核心知识总结
    • HashMap的7种遍历方式
    • 源码分析
  • Java新特性

    • Java8新特性
  • IO流

    • Java基础IO总结
    • Java IO中的设计模式
    • Java IO模型
    • IO多路复用详解
  • 并发编程

    • 并发编程基础总结
  • JVM

    • JVM基础总结
  • MySQL

    • MySQL核心知识小结
    • MySQL 45讲
  • Redis

    • Redis核心入门知识简记
  • Spring
  • SpringCloud Alibaba
  • 开发工具

    • Git详解
    • Maven详解
    • Docker详解
    • Linux常用命令
  • 在线工具

    • json (opens new window)
    • base64编解码 (opens new window)
    • 时间戳转换 (opens new window)
    • unicode转换 (opens new window)
    • 正则表达式 (opens new window)
    • md5加密 (opens new window)
    • 二维码 (opens new window)
    • 文本比对 (opens new window)
  • 学习资源

    • 计算机经典电子书PDF
    • hot120
GitHub (opens new window)
首页
  • 基础知识

    • Java的基本数据类型
    • Java中的常用类String
    • Java中的异常
    • Java中的注解
    • Java中的反射机制
    • Java中的泛型
    • Java为什么是值传递
  • 集合框架

    • Java集合核心知识总结
    • HashMap的7种遍历方式
    • 源码分析
  • Java新特性

    • Java8新特性
  • IO流

    • Java基础IO总结
    • Java IO中的设计模式
    • Java IO模型
    • IO多路复用详解
  • 并发编程

    • 并发编程基础总结
  • JVM

    • JVM基础总结
  • MySQL

    • MySQL核心知识小结
    • MySQL 45讲
  • Redis

    • Redis核心入门知识简记
  • Spring
  • SpringCloud Alibaba
  • 开发工具

    • Git详解
    • Maven详解
    • Docker详解
    • Linux常用命令
  • 在线工具

    • json (opens new window)
    • base64编解码 (opens new window)
    • 时间戳转换 (opens new window)
    • unicode转换 (opens new window)
    • 正则表达式 (opens new window)
    • md5加密 (opens new window)
    • 二维码 (opens new window)
    • 文本比对 (opens new window)
  • 学习资源

    • 计算机经典电子书PDF
    • hot120
GitHub (opens new window)
  • 基础知识

    • Java的基本数据类型
      • 聊一聊Java中的常用类String
      • 聊一聊Java中的异常
      • 聊一聊Java中的注解
      • 聊一聊Java中的反射机制
      • 聊一聊Java中的泛型
      • 聊一聊Java为什么是值传递
    • 集合框架

      • Java集合核心知识总结
      • HashMap 的 7 种遍历方式
      • 源码分析

        • ArrayList源码分析
        • LinkedList源码分析
        • HashMap源码分析
        • ConcurrentHashMap源码分析
        • CopyOnWriteArrayList 源码分析
        • LinkedHashMap 源码分析
        • ArrayBlockingQueue 源码分析
        • PriorityQueue 源码分析
        • DelayQueue 源码分析
    • Java新特性

      • Java8新特性
    • Java基础
    • 基础知识
    BlazeMaple
    2023-10-29
    目录

    Java的基本数据类型

    # Java 中8 种基本数据类型

    • 6 种数字类型:
      • 4 种整数型:byte、short、int、long
      • 2 种浮点型:float、double
    • 1 种字符类型:char
    • 1 种布尔型:boolean

    默认值及其所占空间大小:

    基本类型 位数 字节 默认值 取值范围
    byte 8 1 0 -128 ~ 127
    short 16 2 0 -32768(-2^15) ~ 32767(2^15 - 1)
    int 32 4 0 -2147483648 ~ 2147483647
    long 64 8 0L -9223372036854775808(-2^63) ~ 9223372036854775807(2^63 -1)
    char 16 2 'u0000' 0 ~ 65535(2^16 - 1)
    float 32 4 0f 1.4E-45 ~ 3.4028235E38
    double 64 8 0d 4.9E-324 ~ 1.7976931348623157E308
    boolean 1 false true、false

    八种基本类型都有对应的包装类分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean

    # 基本类型和包装类型的区别?

    基本类型 vs 包装类型

    用途:除了定义一些常量和局部变量之外,我们在其他地方比如方法参数、对象属性中很少会使用基本类型来定义变量。并且,包装类型可用于泛型,而基本类型不可以。

    存储方式:基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。包装类型属于对象类型,我们知道几乎所有对象实例都存在于堆中。

    占用空间:相比于包装类型(对象类型), 基本数据类型占用的空间往往非常小。

    默认值:成员变量包装类型不赋值就是 null ,而基本类型有默认值且不是 null。

    比较方式:对于基本数据类型来说,== 比较的是值。对于包装数据类型来说,== 比较的是对象的内存地址。所有整型包装类对象之间值的比较,全部使用 equals() 方法。

    # 包装类型缓存机制

    Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False

    Integer 缓存源码:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static {
            // high value may be configured by property
            int h = 127;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    Character 缓存源码:

    public static Character valueOf(char c) {
        if (c <= 127) { // must cache
          return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }
    
    private static class CharacterCache {
        private CharacterCache(){}
        static final Character cache[] = new Character[127 + 1];
        static {
            for (int i = 0; i < cache.length; i++)
                cache[i] = new Character((char)i);
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    Boolean 缓存源码:

    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
    
    1
    2
    3

    如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。

    # 自动装箱与拆箱了解吗?原理是什么?

    什么是自动拆装箱?

    • 装箱:将基本类型用它们对应的引用类型包装起来;
    • 拆箱:将包装类型转换为基本数据类型;

    装箱其实就是调用了 包装类的valueOf()方法,拆箱其实就是调用了 xxxValue()方法。

    哪些地方会自动装拆箱?

    • 场景一:基本数据类型放入集合类

      List<Integer> list = new ArrayList<>();
      for(int i=0; i<10; i++){
          list.add(i);
      }
      
      1
      2
      3
      4
    • 场景二:包装类型和基本类型的大小比较

    • 场景三:包装类型运算

    • 场景四:三目运算符的使用

      boolean flag=true;
      Integer i = 1;
      int j = 0;
      int k = flag ? i : j;
      
      1
      2
      3
      4

      当第二位,第三位操作符分别为对象和基本类型时,就会对对象进行拆箱,如果这个时候的对象为null,就会发生空指针异常。

    • 场景五:函数参数与返回值

    # 为什么浮点数运算的时候会有精度丢失的风险?

    float a = 2.0f - 1.9f;
    float b = 1.8f - 1.7f;
    System.out.println(a);// 0.100000024
    System.out.println(b);// 0.099999905
    System.out.println(a == b);// false
    
    1
    2
    3
    4
    5

    计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。这也就是解释了为什么浮点数没有办法用二进制精确表示。

    // 0.2 转换为二进制数的过程为,不断乘以 2,直到不存在小数为止,
    // 在这个计算过程中,得到的整数部分从上到下排列就是二进制的结果。
    0.2 * 2 = 0.4 -> 0
    0.4 * 2 = 0.8 -> 0
    0.8 * 2 = 1.6 -> 1
    0.6 * 2 = 1.2 -> 1
    0.2 * 2 = 0.4 -> 0(发生循环)
    ...
    
    1
    2
    3
    4
    5
    6
    7
    8

    # 如何解决浮点数运算的精度丢失问题?

    BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。

    BigDecimal a = new BigDecimal("1.0");
    BigDecimal b = new BigDecimal("0.9");
    BigDecimal c = new BigDecimal("0.8");
    
    BigDecimal x = a.subtract(b);
    BigDecimal y = b.subtract(c);
    
    System.out.println(x); /* 0.1 */
    System.out.println(y); /* 0.1 */
    System.out.println(Objects.equals(x, y)); /* true */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 超过 long 整型的数据应该如何表示?

    基本数值类型都有一个表达范围,如果超过这个范围就会有数值溢出的风险。在 Java 中,64 位 long 整型是最大的整数类型。

    long l = Long.MAX_VALUE;
    System.out.println(l + 1); // -9223372036854775808
    System.out.println(l + 1 == Long.MIN_VALUE); // true
    
    1
    2
    3

    BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。相对于常规整数类型的运算来说,BigInteger 运算的效率会相对较低。

    # BigDecimal 详解

    # 常见方法

    创建:

    在使用 BigDecimal 时,为了防止精度丢失,推荐使用它的BigDecimal(String val)构造方法或者BigDecimal.valueOf(double val) 静态方法来创建对象。

    加减乘除:

    add 方法用于将两个 BigDecimal 对象相加,subtract 方法用于将两个 BigDecimal 对象相减。multiply 方法用于将两个 BigDecimal 对象相乘,divide 方法用于将两个 BigDecimal 对象相除。

    BigDecimal a = new BigDecimal("1.0");
    BigDecimal b = new BigDecimal("0.9");
    System.out.println(a.add(b));// 1.9
    System.out.println(a.subtract(b));// 0.1
    System.out.println(a.multiply(b));// 0.90
    System.out.println(a.divide(b));// 无法除尽,抛出 ArithmeticException 异常
    System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));// 1.11
    
    1
    2
    3
    4
    5
    6
    7

    在使用 divide 方法的时候尽量使用 3 个参数版本,并且RoundingMode 不要选择 UNNECESSARY,否则很可能会遇到 ArithmeticException(无法除尽出现无限循环小数的时候),其中 scale 表示要保留几位小数,roundingMode 代表保留规则。

    public enum RoundingMode {
       // 2.5 -> 3 , 1.6 -> 2
       // -1.6 -> -2 , -2.5 -> -3
    			 UP(BigDecimal.ROUND_UP),
       // 2.5 -> 2 , 1.6 -> 1
       // -1.6 -> -1 , -2.5 -> -2
    			 DOWN(BigDecimal.ROUND_DOWN),
    			 // 2.5 -> 3 , 1.6 -> 2
       // -1.6 -> -1 , -2.5 -> -2
    			 CEILING(BigDecimal.ROUND_CEILING),
    			 // 2.5 -> 2 , 1.6 -> 1
       // -1.6 -> -2 , -2.5 -> -3
    			 FLOOR(BigDecimal.ROUND_FLOOR),
       	// 2.5 -> 3 , 1.6 -> 2
       // -1.6 -> -2 , -2.5 -> -3
    			 HALF_UP(BigDecimal.ROUND_HALF_UP),
       //......
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    大小比较:

    a.compareTo(b) : 返回 -1 表示 a 小于 b,0 表示 a 等于 b , 1 表示 a 大于 b。

    BigDecimal a = new BigDecimal("1.0");
    BigDecimal b = new BigDecimal("0.9");
    System.out.println(a.compareTo(b));// 1
    
    1
    2
    3

    保留几位小数:

    通过 setScale方法设置保留几位小数以及保留规则。

    BigDecimal m = new BigDecimal("1.255433");
    BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN);
    System.out.println(n);// 1.255
    
    1
    2
    3
    # 等值比较问题

    BigDecimal 使用 equals() 方法进行等值比较, equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。

    BigDecimal a = new BigDecimal("1");
    BigDecimal b = new BigDecimal("1.0");
    System.out.println(a.compareTo(b));//0
    
    BigDecimal a = new BigDecimal("1");
    BigDecimal b = new BigDecimal("1.0");
    System.out.println(a.equals(b));//false
    
    1
    2
    3
    4
    5
    6
    7
    # BigDecimal工具类
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    
    /**
     * 简化BigDecimal计算的小工具类
     */
    public class BigDecimalUtil {
    
        /**
         * 默认除法运算精度
         */
        private static final int DEF_DIV_SCALE = 10;
    
        private BigDecimalUtil() {
        }
    
        /**
         * 提供精确的加法运算。
         *
         * @param v1 被加数
         * @param v2 加数
         * @return 两个参数的和
         */
        public static double add(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.add(b2).doubleValue();
        }
    
        /**
         * 提供精确的减法运算。
         *
         * @param v1 被减数
         * @param v2 减数
         * @return 两个参数的差
         */
        public static double subtract(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.subtract(b2).doubleValue();
        }
    
        /**
         * 提供精确的乘法运算。
         *
         * @param v1 被乘数
         * @param v2 乘数
         * @return 两个参数的积
         */
        public static double multiply(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.multiply(b2).doubleValue();
        }
    
        /**
         * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
         * 小数点以后10位,以后的数字四舍五入。
         *
         * @param v1 被除数
         * @param v2 除数
         * @return 两个参数的商
         */
        public static double divide(double v1, double v2) {
            return divide(v1, v2, DEF_DIV_SCALE);
        }
    
        /**
         * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
         * 定精度,以后的数字四舍五入。
         *
         * @param v1    被除数
         * @param v2    除数
         * @param scale 表示表示需要精确到小数点以后几位。
         * @return 两个参数的商
         */
        public static double divide(double v1, double v2, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException(
                        "The scale must be a positive integer or zero");
            }
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.divide(b2, scale, RoundingMode.HALF_EVEN).doubleValue();
        }
    
        /**
         * 提供精确的小数位四舍五入处理。
         *
         * @param v     需要四舍五入的数字
         * @param scale 小数点后保留几位
         * @return 四舍五入后的结果
         */
        public static double round(double v, int scale) {
            if (scale < 0) {
                throw new IllegalArgumentException(
                        "The scale must be a positive integer or zero");
            }
            BigDecimal b = BigDecimal.valueOf(v);
            BigDecimal one = new BigDecimal("1");
            return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
        }
    
        /**
         * 提供精确的类型转换(Float)
         *
         * @param v 需要被转换的数字
         * @return 返回转换结果
         */
        public static float convertToFloat(double v) {
            BigDecimal b = new BigDecimal(v);
            return b.floatValue();
        }
    
        /**
         * 提供精确的类型转换(Int)不进行四舍五入
         *
         * @param v 需要被转换的数字
         * @return 返回转换结果
         */
        public static int convertsToInt(double v) {
            BigDecimal b = new BigDecimal(v);
            return b.intValue();
        }
    
        /**
         * 提供精确的类型转换(Long)
         *
         * @param v 需要被转换的数字
         * @return 返回转换结果
         */
        public static long convertsToLong(double v) {
            BigDecimal b = new BigDecimal(v);
            return b.longValue();
        }
    
        /**
         * 返回两个数中大的一个值
         *
         * @param v1 需要被对比的第一个数
         * @param v2 需要被对比的第二个数
         * @return 返回两个数中大的一个值
         */
        public static double returnMax(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(v1);
            BigDecimal b2 = new BigDecimal(v2);
            return b1.max(b2).doubleValue();
        }
    
        /**
         * 返回两个数中小的一个值
         *
         * @param v1 需要被对比的第一个数
         * @param v2 需要被对比的第二个数
         * @return 返回两个数中小的一个值
         */
        public static double returnMin(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(v1);
            BigDecimal b2 = new BigDecimal(v2);
            return b1.min(b2).doubleValue();
        }
    
        /**
         * 精确对比两个数字
         *
         * @param v1 需要被对比的第一个数
         * @param v2 需要被对比的第二个数
         * @return 如果两个数一样则返回0,如果第一个数比第二个数大则返回1,反之返回-1
         */
        public static int compareTo(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.compareTo(b2);
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    帮助我们改善此页面! (opens new window)
    上次更新: 2024/08/13, 09:07:12
    聊一聊Java中的常用类String

    聊一聊Java中的常用类String→

    最近更新
    01
    SpringCloud Alibaba实战
    08-22
    02
    SpringCloud Alibaba核心知识
    08-22
    03
    两数之和
    08-08
    更多文章>
    Theme by Vdoing | Copyright © 2023-2024 BlazeMaple
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式