面试必备基础知识 — Java基础(一)

数据类型

基本数据类型

基本数据类型

数据类型二进制位数默认值
byte8位0
short16位0
int32位0
long64位0L
float32位0.0f
double64位0.0d
char16位‘u0000’
boolean~false

boolean只有两个值 true 和false,可以使用1bit 来存储,但是具体大小没有规定。JVM在编译时期,将boolean类型的数据转换为int类型,使用1来表示true,0表示false。JVM支持boolean数组,但是是通过读写byte数组来实现的

包装类型

基本的数据类型对应的都有包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。

原始类型对应的封装类
byteByte
shortShort
charCharacter
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean

自动装箱与拆箱

自动装箱与拆箱 就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之,将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作自动装箱与拆箱,自动装箱与拆箱从JDK1.5开始引入

自动装箱与拆箱的要点

  • 自动装箱时,编译器调用 valueOf 将原始类型值转换成对象。同时自动拆箱时,编译器通过调用类似 intValue(),doubleValue()这类的方法将对象转换成原始类型值。
  • 自动装箱是将boolean值转换成Boolean对象,byte值转换成Byte对象,char转换成Character对象,float值转换成Float对象,int转换成Integer,long转换成Long,short转换成Short,自动拆箱则是相反的操作。

自动装箱实例:
Consider the following code:

List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
    li.add(i);

虽然我们将 i 定义为int基本类型(而不是Integer对象)添加到li,但是代码仍会编译,而不会报错。因为它会自动从i创建一个Integer对象并将该对象添加到 li 中。
编译器在运行时将原代码转换为以下代码:

List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
    li.add(Integer.valueOf(i));

Java中的自动装箱与拆箱

缓存池

new Integer(123)Integer.valueOf(123) 的区别在于:

  • new Integer(123) 每次都会创建一个新的对象;
  • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。(Integer i = 123; 会触发自动装箱)
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y);    // false
Integer m = Integer.valueOf(123);
Integer n = Integer.valueOf(123);
System.out.println(m == n);   // true

valueOf() 方法的实现,就是JVM先判断值是否在缓存池中,

  • 如果在的话就直接返回缓存池中的内容
  • 如果不在,我们使用new Integer创建一个对象,并返回该对象的引用地址。

源码分析:
Integer.valueOf()中有个静态内部类IntegerCache,里面有个常量cache[],也就是Integer常量池(其实就是缓存池技术,利用空间换时间的策略,也叫对象池),在常量池(对象池)中Integer已经默认创建了数值【-128-127】的Integer缓存数据。

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
        static {
            // high value may be configured by property
            int h = 127;
	        ……
        }
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

基本类型对应的缓冲池:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char int the range \u0000 to \u007F

使用这些基本数据类型对应的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象。

注意:最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改

String

源码分析

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
    	private final char value[];
    	……

String被 final 修饰,因此它不可被继承。(Integer等包装类也不能被继承)
在Java 8中,String内部使用char数组存储数据。
value数组 被声明为final ,也就是说value数组初始化之后就不能再引用其它数组。并且String 内部没有改变 value数组的方法,因此可以保证String不可变。

不可变的好处

  1. String Pool 的需要:
    字符串池是 方法区 中的特殊存储区。创建字符串时,如果该字符串已存在于字符串池中,则将返回现有字符串的引用,而不是创建新对象。
    如果字符串是可变的,则使用一个引用更改字符串会导致其他引用的值错误。
  2. 缓存hash值
    String 的hash值经常被用到,比如String 用作HashMap 的key。不可变的特性可以使得哈希值也不可变,因此只需要进行一次计算。这样更有效
  3. 安全性
  4. 线程安全:
    String不可变性天生具备线程安全,可以在多个线程中安全地使用。

String、StringBuffer、StringBuilder

可变性线程安全
String不可变安全
StringBuffer可变安全(内部使用 synchronized 进行同步)
StringBuilder可变不安全

String Pool

在Java语言中有八种基本数据类型和一种比较特殊得类型String。这些类型为了使他们在运行的过程中速度更快,更节省内存,都提供了一种常量池的概念。常量池就类似一个Java系统级别提供的缓存。
8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊,它的主要使用方法有两种:

  • 直接使用双引号声明出来的String对象会直接存储在常量池中
  • 如果不是用双引号声明的String对象,可以使用String提供的intern方法,intern方法会从字符串常量池中,查询当前字符串是否存在,若不存在,就会将当前字符串放入常量池中。
    深入解析String#intern

字符串常量池 保存着所有字符串字面量(一个字符串字面量就是两个双引号之间的字符序列),这些字面量在编译时期就确定。还可以使用String的 intern方法在运行过程中将字符串添加到字符串常量池中。

当一个字符串调用 intern方法时,如果String Pool中已经存在一个字符串和该字符串相等(使用equals()方法判断),那么就会返回String Pool中字符串的引用;否则,就会在String Pool中添加一个新的字符串,并返回这个新字符串的引用。

//使用new String()创建两个不同的对象
String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);   // false
//使用intern()方法获取同一个字符串引用
String s3 = s1.intern();
String s4 = s1.intern();
System.out.println(s3 == s4);   // true
//使用字面量的形式创建字符串,会自动将字符串放入String Pool中
String s5 = "bbb";
String s6 = "bbb";
System.out.println(s5 == s6);  // true

new String(“abc”)

使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有"abc"字符串对象)

  • "abc"属于字符串字面量,因此编译时期会在 String Pool中创建一个字符串对象,指向这个字符串字面量;
  • 然后使用new 的方式会在堆中创建一个字符串对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值