[Java]基本数据类型

基本数据类型

在java中有8种基本的数据类型,下面来看它们能表示的范围:
  • byte:-128 - 127
  • boolean:true/false
  • char: \u0000 - u\ffff ’
  • short:-32768 - 32768
  • int:-2147483648-2147483648
  • float:-3.40292347E+38-3.40292347E+38
  • long:-9233372036854477808-9233372036854477808
  • double:-1.79769313486231570E+308-1.79769313486231570E+308
因为表示范围的不同,在进行转换的时候会有一些问题,比如:
        byte x = -1;
        System.out.println((int) x);// -1
        int y = 255;
        System.out.println((byte) y);// -1
在从低到高转换的时候会用符号位填充,而从高到低转换的时候会直接截取。那如果想把byte当做是一个无符号的,那么怎么取到它所表示的值?如下:
        byte x = -2;
        System.out.println((int) (x & 255));// -1
在使用浮点数的时候需要按照精度处理(比如Format),如下:
        double x = 1.15;
        System.out.printf("%1.1f\n", x);// 四舍五入
        System.out.printf("%1.1f\n", x - 0.05);// 向下取整
        System.out.printf("%1.1f\n", x + 0.05);// 向上取整
浮点数在存储的时候也是二进制的,在十进制能表示的数在二进制上可能有有一定的偏差。所以需要注意的一点:
不要写while(x != y)这种结束条件,可以写成while(Math.abs(x-y) < e),其中e是一个很小的数。
最后在需要用反射获取参数为int的方法是,可以使用int.class.

String

虽然String并不是基础类型,但用的比较多所以一起看下:
public final class String{
	private final char value[];
	private final int offset;
	private final int count;
	private int hash;
}
可以看出来,真正的字符串的内容保存在char value[]中,而在substring的时候是不会新的char数组来重复保存,只需生成一个新的String对象并设置好对应的偏移量即可:
        String str1 = "abcd".substring(0, 3);
        String str2 = "abc";
        String str3 = "abcd";
在运行时可以看到:

可以看到:
str1.value == str3.value

同时我们发现str1 != str2,这是因为在substring的时候生成了新的对象,如果是下面的写法的话,会发现str1 == str2:

        String str1 = "abcd".substring(0, 3).intern();
        String str2 = "abc";

为了性能和内存资源的考虑,JVM会将String用一个哈希表保存起来,如果在后面用到同样的字符串就直接从这个哈希表中拿出来用,而不需要创建新的String对象,所以就会看到上面的结果。而intern方法就是将String放入String pool中,并返回对应的对象。


也有其他类型的Literal Pool(比如Integer),但是并不是说任意两个相同值的Integer就能用==进行比较了。而在这里有代码运行的结果争议很大:

        String s1 = "abc";
        String s2 = "abc";
        String s3 = s1 + s2;
        System.out.println(s3 == s3.intern());

根据前面说的应该返回false,在JDK 6中也的确如此,但是在JDK 7中的返回值却是true:

JDK 7中的String pool并不拷贝调用intern的String实例,只是在池中记录了每组内容相同的String实例首个被intern的那个实例的引用,所以结果为true。而在JDK 6中,在常量池中创建了一个新的String实例,并将该实例的引用返回,所以结果为false。所以intern的行为还是很依赖虚拟机的实现。

这样实现起来常量池中要保存的内容确实少了很多。另外,看到关于创建了多少String实例的帖子:

        String s1 = new String("xyz");
        String s2 = new String("xyz");

同样和JVM如何实现有关。


编码解码

首先来看和Java本身相关的三个概念:
  • class文件采用utf-8编码
  • jvm运行时采用utf-16编码
  • java中的字符串采用unicode编码

其中unicode使用"\udddd"的形式表示,比如:

        String \u4e00 = "\u4e00";
        System.out.println(\u4e00);// 一
下面进入正题,要明白为什么会出现乱码问题就有明白两个概念:

  • 编码:从string变成byte[]
  • 解码:从byte[]变成string

byte[]本身是没有任何含义的,它只是用来存储信息(比如它可以存放数字、图像等),而string是有含义的。string变成byte的过程就好比上课记笔记的时候,将老师的话用英语记录还是用汉语记录,不用的语言就是对信息的不同编码方式。


在使用时自然应该用正确的解码方式对信息进行处理,比如你不懂英语自然就看不懂用英语写的笔记。看下面代码:

        String str = "你好";
        byte[] b_gbk = str.getBytes("GBK");// [-60, -29, -70, -61]
        byte[] b_utf_8 = str.getBytes("utf-8");// [-28, -67, -96, -27, -91, -67]
        String str_gbk = new String(b_gbk, "GBK");// 你好
        String str_utf_8 = new String(b_utf_8, "utf-8");// 你好

下面来模拟一个出现乱码的过程已经一个伪的解决过程:

        // 出现乱码的过程
        String str = "你好";
        byte[] b_utf_8 = str.getBytes("utf-8");// [-28, -67, -96, -27, -91, -67]
        String str_gbk = new String(b_utf_8, "gbk");// 浣犲ソ
        byte[] b_gbk = str_gbk.getBytes("gbk");// [-28, -67, -96, -27, -91, -67]
        
        // 从乱码中尝试解析出原来的字符,就是上面的逆过程
        b_utf_8 = str_gbk.getBytes("gbk");// [-28, -67, -96, -27, -91, -67]
        String str_utf_8 = new String(b_utf_8, "utf-8");// 你好


urlencode

在遇到有编码问题的时候,最简单暴力的方法就是用urlencode对字符串先编码,再传输。等接收方拿到字符串之后,进行解码即可。

----------END----------

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值