java学习笔记(三)—— 数据类型、数据类型转换

一、java的数据类型

java的数据类型分为两大类:

  • 八大基本数据类型
    • 整数类型
      • byte 占1个字节:-128 ~ 127
      • short 占2个字节:-32768 ~ 32767
      • int (常用)占4个字节:-2147483648 ~ 2147483647(21亿)
      • long 占8个字节:-9223372036854775808 ~ 9223372036854775807
    • 浮点类型
      • float 占4个字节
      • double常用)占8个字节
    • 字符类型 char 占2个字节
    • 布尔类型 只占1位
  • 引用数据类型 (除了基本数据类型,剩下的就是引用类型)
    • 接口
    • 数组、
 //八大基本数据类型
        int num1 =10;
        byte num2= 100;
        short num3 =30;
        long num4=30L; //不加L没法区分是其他类型还是long类型
        
        float num5=5.12F;//加F,道理同上
        double num6=1.234567898765431;
        
        char c='你';
        
        boolean flag=true;

主要注意这两个:

 1. 整型拓展

         //二进制0b    八进制0   十进制    十六进制0x
        int num1 =0b1010; //=(1×2×2×2)+(0×2×2)+(1×2)+0=10
        int num2 =0120;   //=(1×8×8)+(2×8)+0=80
        int num3 = 1234;  //=(1×10×10×10)+ (2×10×10)+(3×10)+4=1234
        int num4 = 0xfff; //(15×16×16)+(15×16)+15=4095

2.浮点型拓展

1)如下情况,在num1和num2都输出为0.1时,num1却不等于num2

        float num1 = 0.1f;     //0.1
        double num2 = 1.0/10;  //0.1

        System.out.println(num1);  //0.1
        System.out.println(num2);  //0.1
        System.out.println(num1==num2); //flase

2)在num1和num2都输出为0.6时,num1却不等于num2

        float num1 = 0.6f;     //0.6
        double num2 = 0.6;  //0.6

        System.out.println(num1);  //0.6
        System.out.println(num2);  //0.6
        System.out.println(num1==num2); //false

3)当num1和num2都输出为0.0625时,true

        float num1 = 0.0625f;
        double num2 = 0.0625;

        System.out.println(num1);  //0.0625
        System.out.println(num2);  //0.0625
        System.out.println(num1==num2); //true

4)这种情况下却输出了true

        float f1 = 212121212f;
        double d1 = f1+1;

        System.out.println(f1==d1);  //true

        究其原因,问题出在浮点数在计算机中的表示。我们以IEEE754标准的单精度浮点数格式为例,其表示方法如下:

        你会发现,这种表示方式只能表示刚刚好由2^(-n)组合起来的数:

k1×2^(-1) + k2×2^(-2) + k3×2^(-3) + k4×2^(-4)+...kn×2^(-n)           kn=0或1

        所以,这样是没法表示十进制的0.1的。只有0.59375这种“刚刚好”的数,才能用0.10011B表示出来。0.59376或者0.6都是没法表示的。

        也就是说,虽然我们的float和double能表示如下这么大范围的数,

         但实际上是离散的,中间有很多数都表示不了(比如0.1、0.6),只能以一个接近它的数去表示。

刚刚解释完了小数部分,那么对于例4)里的大数呢?怎么解释?

        float型占4字节,int型也占4字节。int型的32位(最大21亿)都用来表示数值,而float在IEEE754标准中,只有后23位用来表示数值。但是超过21亿的大数float也能表示,就只能砍掉23位以后的位数,舍去精度找一个接近但是不等于的数去表示它,所以也是离散

综上,我们得出一个结论,避免使用浮点数去进行数值比较

那么对于小数或者大额数字如何精确表示呢?经典场景就是微信支付和支付宝(或者银行业务),钱可不能近似表示

        用BigDecimal这个数学工具类。

3. 字符拓展

1)Unicode编码

        java默认采用Unicode编码而不是ASCII,每一个字符都对应一个int型数值。只需要记住,字符的本质是数值

        Unicode包含了ASCII。也就是说,无论用ASCII编码还是Unicode编码,A-Z都对应65-90.

        char a ='a';
        char b ='明';

        System.out.println((int)a);  //97
        System.out.println(a);  //a
        System.out.println((int)b); //26126
        System.out.println(b);  //明

         ASCII码只能表示英文,对于英美这样的国家足够了。Unicode编码占两个字节,最多可以表示65536个字符,对于汉语还是不够用(10万字左右)。Unicode只是一种概念编码,而UTF-8是其一种实现形式。

        因为我们使用汉语,一般使用UTF-8,UTF-8是可变长的编码,对于汉字占3个字节,足够汉语的使用了。

二、数据类型转换

        首先,将除布尔值以外的数据类型按照精度由低到高排列:

byte(1) -> short char(2) -> int(4) -> long(8) -> float (4) -> double(8)

自动类型转换:把级别低的类型赋值给级别高的类型时,自动完成类型转换

强制类型转换:反之,必须使用类型转换运算。此时可能导致①内存溢出②精度的损失

        // 1.自动类型转换
        int a =50;
        double b = a;
        System.out.println(a);  //50
        System.out.println(b);  //50.0

        // 2.强制类型转换
        int c = 98;
        System.out.println((char)c);  //int->char的强制转换  //'b'
            // 1) 内存溢出问题---->byte截断int的低8位
        int d =128;
        byte e = (byte)d;
        System.out.println(e);  //-128

        int a = 128+256; // ...1_1000_0000
        byte b =(byte)a;
        System.out.println(b);  //-128
            // 2) 精度损失问题
        double f=123456786.3215498754;
        float ff=(float)f;
        System.out.println(ff);  //1.23456784E8

例1)

        //JDK7的新特性,大数之间用下划线分割便于阅读
        int money=10_0000_0000;
        int year=20;

        int total1=money*year; //200亿,int最大表示21亿
        System.out.println(total1);

        long total2=money*year;
        System.out.println(total2);

        long total3=money*((long)year);
        System.out.println(total3);

三、装箱

在JDK1.5 之前我们把int装箱到Integer里还要借用Integer.valueOf(3)方法,同理拆箱也是。

在JDK 1.5之后就可以自动装箱了

Integer i = 10;  //装箱
int n = i;   //拆箱

1. 自动拆装箱带来的弊端

        注意,是自动拆装箱带来的弊端,意思是像JDK1.5之前那样手动的话就不会有这个问题。

        自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。

Integer sum = 0; for(int i=1000; i<5000; i++){   sum+=i; } 

        上面的代码sum+=i可以看成sum = sum + i,但是+这个操作符不适用于Integer对象,首先sum进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成Integer对象。由于我们这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。 

如何避免:只能靠程序员的水平去避免。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值