Java中有8种基本数据类型,其中4种整型、2种浮点类型、1种表示Unicode的字符型和1种boolean类型。
类型 | 储存需求 | 取值范围 |
---|---|---|
int | 4个字节 | -2147483648~2147483647(20亿) |
short | 2个字节 | -32768~32767 |
long | 8个字节 | -9223372036854775808~9223372036854775807 |
byte | 1个字节 | -128~127 |
java整型的范围与平台无关。长整形数值后有一个后缀L,十六进制数值前缀0x,八进制前缀0,从Java7开始 0b前缀表示二进制。0b1001 就是9 。
java中没有任何无符号类型。
(1)如下代码无法通过编译:
int a = 1;
short b = a;
a是int类型,b是short类型,int类型表示的数据范围要比short类型大,不能将表示范围大的值赋给表示范围小的变量。
(2)如下代码可以通过编译:
short a = 1;
int b = a;
a是short类型,b是int类型,int类型表示的数据范围要比short类型大,可以将表示范围小的值赋给表示范围大的变量。
小结:可以将表示范围小的值赋给表示范围大的变量;但不能直接将表示范围大的值赋给表示范围小的变量,只能通过强制类型转换实现。
下面程序运算结果
byte a=-128; a--; System.out.println(a); a=127; a++; System.out.println(a);
第二个输出为-128
原理如下:
计算机中运算以补码的形式进行
正数的补码为其本身
负数的补码为其绝对值的按位取反后+1
-128 的补码为 10000000 自减一后得到 0111 1111 为十进制127
127 二进制 01111 1111 加一后得到 1000 0000 为十进制-128的补码
Java中有两种浮点类型 float 和double
类型 | 存储需求 |
float | 4字节 |
double | 8字节 |
float类型的数值后面有一个F,没有F后缀的浮点类型默认为double类型。不能将double类型的值赋给float类型的变量,即便该double类型的值处于float类型的范围内也是不可以的。总之,能否成功赋值取决于等号右边的值类型与等号左边的变量类型是否一致。
如何将double类型的值赋给float类型的变量?
答案就是(1)强制类型转换,将double类型的值强制转换为float类型。(2)使用java语言的支持。
强制转换的语法: 类型 变量名 = (类型)变量值;
1 NaN(不是一个数字),如果一个计算结果不符合数学逻辑,那么得到的结果将是NaN。例如一个整数除以0,或者计算负数的开平方。需要注意的是,整数除0会产生一个异常,而浮点数除0得到的结果将会是无穷大或者NaN.
2 利用system.out.println(2.0-1.1)得到的结果将是0.8999999999,而不是0.9。因为浮点型数据用二进制系统表示,二进制系统无法精确到分数的1/10,如果需要在数值计算中不含有任何舍入误差,应该使用BigDecimal类。
3 两个数值进行二元操作时(例如n+f,n为整型,f为浮点型),先要将两个操作数转换为同一类型,然后再进行计算
如果两个操作数中有一个为double类型,另一个数将转换为double类型,
否则如果一个为float类型,另一个转换为float类型,
否者如果一个为long类型 ,另一个转换为long类型,
否则两个数都被转换为int类型。
Java中,char类型用UTF-16编码表示一个代码单元。建议不要再程序中使用char类型,除非确定需要对UTF-16代码单元进行操作。
只有两个值 true和false
从概念上讲,Java字符串就是Unicode字符序列。Java没有内置的字符串类型,而在标准Java类库中提供了一个预定义类,很自然地叫做String。
String类型不属于基本数据类型,但在函数运算的时候 ,遵循值传递。
字符串是一个常量,具有不可变性。当对字符串进行重新赋值时,只是让它引用了另外一个字符串。同理,当使用+拼接字符串时,会生成新 的String 对象,而不是向原有的 String 对象追加内容。
为什么要这么做呢?看起来好像是修改一个代码单元比创建一个新字符串更加简洁,而且效率也不高。但是不变字符串有一个有点:编译器可以让字符串共享。所有的字符串都放在一个池子里。Java设计者认为共享带来的高效率远远高于提取、拼接字符串带来的低效率。
String 有一个池子,叫字符串常量池。
(1)使用“ ”声明的字符串(采用字面值方式赋值)都被放到这个池子里。每次使用这种方式声明变量的时候,都会先检查池子里没有这个字符串存在,如果已经有了,那么直接返回这个字符串的地址。
String str3 = "bbb"; String str4 = "bbb"; System.out.println(str3 == str4);
(2) 使用“+”拼接生成字符串,使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到StringPool中;使用包含变量的字符串连接符如"aa" +s1创建的对象是运行期才创建的,存储在heap中。
String s2 = "sss111"; String s3 = "sss" + "111"; String s4 = "sss" + s1; System.out.println(s2 == s3); //true System.out.println(s2 == s4); //false
a 首先在 String Pool 中查找有没有“aaa”这个字符串对象,如果有,则不在 String Pool 中再去创建“aaa”这个对象了,直接在堆中(heap)中创建一个“aaa”字符串对象,然后将堆中的这个“aaa”对象的地址返回来,赋给 s 引用,导致 s 指向了堆中 创建的这个“aaa”字符串对象。
b 如果没有,则首先在 String Pool 中创建一个“aaa“对象,然后再在堆中(heap)创 建一个”aaa“对象,然后将堆中的这个”aaa“对象的地址返回来,赋给 s 引用, 导致 s 指向了堆中所创建的这个”aaa“对象。
总之,使用了new就在堆中产生了新的对象
class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }
结果是:
true true true true false true
经过前面的介绍,可以发现使用“==”是不能判断字符串相等的,应该使用equcals方法。下面是String类重写equals方法源码。
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
char charAt(int index)
返回给定位置代码单元
indexOf(String str)
subString(int beginIndex,int endIndex)
返回一个新字符串。这个字符串包含原始字符串从beginIndex到endIndex-1的所有代码单元
有的时候需要频繁地拼接字符串,这个时候如果使用“+”进行拼接的效率是很低的,因为每次都会产生新的String对象,既耗时又浪费空间。应当使用StringBuilder或者StringBuffer的appand方法进行字符串拼接。
这两个类的API是相同的,StringBuffer是线程安全的,但是其效率有些低。因此从JDK5.0开始引入了StringBuilder。如果不是多线程去操作字符串的时候,应该使用StringBuilder。
版权声明:本文为博主原创文章,未经博主允许不得转载。