一、数据类型
基本数据类型
数值类型:
数据类型 | 封装类型 | 存储需求(字节) | 取值范围=(-2^(8*存储需求)~2^(8*存储需求)-1) |
---|---|---|---|
byte | Byte | 1 | -2^8~2^7-1(-128~127) |
short | Short | 2 | |
int | Integer | 4 | |
long | Long | 8 | |
float | Float | 4 | |
double | Double | 8 |
面试考点:取值范围,运算,拆装箱,比较,类型转换
运算and类型转换
实心箭头代表无信息丢失,虚箭头表示有精度损失
案例:
byte i = 1;
i = i + 1;//报错,因为运算的时候byte转换成了int类型
i = (byte)(i + 1);//可以,使用了强制类型转换
i += 1;//可以,这种结合赋值会隐式进行强制类型转换
注意:结合赋值会隐式进行强制类型转换
位运算里:~n = -n - 1
自动装拆箱and比较
自动装箱和拆箱大部分人的印象应该就是这样子的:
Integer i = 1;//自动将int类型装箱为Integer
int a = new Integer(5);//自动拆箱为int
那么面试的考点应该是下面这样子的:
- 基本型和基本型封装型进行
==
运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较。 - 两个Integer类型进行“==”比较,还要看Integer对象创建的方式,这里还有一个缓存池的概念。Integer缓存的是-128~127
- 两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
- 基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行3中的比较。
Integer i = 9;
int j = 9;
System.out.println(i == j);//true,i自动拆箱,然后进行比较
Integer k = 9;
Integer kk = new Integer(9);
Integer kkk = Integer.valueOf(9);
System.out.println(i == k);//true。i,k创建方式不是new,而且值在缓存池里,所以==比较对象的会是同一个地址
System.out.println(i == kk);//false。kk是new的,所以内存地址不一样。
System.out.println(i == kkk);//true。如果值在缓存池里valueOf会直接返回对应缓存,否则调用new Integer
Integer ii = 128;
Integer jj = 128;
System.out.println(ii == jj);//false.如果值在缓存池里valueOf会直接返回对应缓存,否则调用new Integer
System.out.println(i.equals(k));//方法为public boolean equals(Object obj)
System.out.println(i.equals(kk));//
基本类型对应的缓冲池如下:
boolean values true and false
all byte values
short values between -128 and 127
int values between -128 and 127
char in the range \u0000 to \u007F
boolean类型:
封装类型:Boolean,取值为true|false.
面试考点:逻辑符的短路
逻辑符的短路:
逻辑符的短路表示按顺序执行&&,||
时,如果前面语句满足了判断那么就不会执行后面的语句:
if(true||5/0==0){
...
}
执行前半句得到true,逻辑短路不会执行后面的语句,故不会报错。
实际上位运算符&,|
也可以表示与和或,代表的是一种非短路的运算。如果上述条件改为|
那么就会报错。
char类型:
char原本用于表示单个字符。现在可以描述一些Unicode字符。封装类型为:Character,取值范围现在是0~2^16-1.
面试考点:封装类型,常见char对应int值
字符 | ASCII码值 |
---|---|
‘0’ | 48 |
‘a’ | 97 |
‘A’ | 65 |
注意:当赋值为整型的时候不是代表对应的值,而是ASCII值:
char a = 1;
char b = '1';//a!=b
String类型
string的面试考点一般有 判断是否相等,equals(),不可变性,StringBuffer/StringBuilder的区别
内部实现
String类被声明为 final,因此它不可被继承。
而且内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
常用的String的创建
String s = "java";
我们把这类创建称为字面量 方式,直接使用双引号将字符数组value[]括起来。String s = new String("java");
使用构造函数构造String对象。
之所以要区分这两种不同创建方式是因为他们在创建String对象的时候会有不同的表现形式。
字面量创建:
使用字面量的方式创建,首先JVM会到字符串常量池中检查是否有内容为java
的对象存在。
如果不存在,那么会先在在堆内存创建一个内容为java
的String对象,然后将指向该对象的内存地址引用存入字符串常量池中。
如果存在则返回该引用。
如果是String s = "ja"+"va";
这样的方式创建字符串,由于编译优化,那么在编译器会直接在字符串常量池创建内容为java
的引用,而没有ja,va
这两个。
但是如果是String s1 = "ja";String s = s1 + "va";
由于无法在编译器确定s的内容,jvm会在运行时确认。而在运行时确认需遵循以下规则:只要s1是变量,不论s1指向池中的字符串对象还是堆中的字符串对象,运行期s1 + “aa”操作实际上是编译器创建了StringBuilder对象进行了append操作后通过toString()返回了一个字符串对象存在heap上。
在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中;
在JDK7.0版本,字符串常量池被移到了堆中了。因为方法区的内存太小,只能存放1009个,而现在可以通过指定-XX:StringTableSize参数初始化字符串常量池的大小。
构造方法创建:
使用构造方法创建时,不过字符串常量池是否有相应的内容的String对象引用,都会在堆上新建一个String对象。
对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。
调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
案例:
String a = "java";
String b = "java";
String c = new String("java");
String cc = String.valueOf("java");
String ccc = new StringBuilder("java").toString();
String d = "ja"+"va";
System.out.println(a == b);//true
System.out.println(a == d);//true
System.out.println(a == c);//false
System.out.println(a == cc);//true
System.out.println(a == ccc);//false
StringBuffer和StringBuiler:
- StringBuffer线程安全,StringBuiler线程非安全。
- StringBuiler牺牲了对方法的互斥锁,所以运行速率比StringBuffer高。
- 都继承了AbstractStringBuilder。