近7000字长文详细讲解Java包装类,面试稳了

Java
253
0
0
2023-05-28
标签   Java面试

零基础学习之 Java 包装类

说起Java包装类就不得不说Java的特性 – 面向对象。Java是Sun公司的程序 James Gosling ,Bill Joe本来打算试图修改和扩展C 的功能,新开发一个语言Oak的发展。 C语言 是一个面向过程的语言,改进后的Java是面向对象,这是一个非常大的改进,这也是Java发展至今依旧非常流行的原因。

但是,Java又不是完全的面向对象,它沿用了C语言的基本数据类型(这是为了便于开发者的使用,使得在进行基本的数据计算时,开发者可以直接使用基础类),但当需要和Java其他对象结合使用,如存入集合中,就需要将基础数据类型实例封装为Java对象,这样操作起来又比较麻烦了,为了满足面向对象的这一特性,Java的 java.lang 包中设置了包装类,使得每一个基本类型都有对应的包装类,这样直接就方便了开发者的使用。

简单理解来说:包装类就是为了使得Java中的基本数据类型具有面向对象的特性。

基本介绍

基本数据类型对应的包装类有8个(,根据其继承关系可以分成三类: char acter、Number、 boolean 。继承关系图如下:

近7000字长文详细讲解Java包装类,面试稳了

这8个包装类和基本数据类型的对应关系如下表:

基本数据类型

包装类(java.lang包)

Byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

char

Character

boolean

Boolean

包装类的使用

把基本类型变成包装类对象的过程称为装箱。

转为包装类的对象,是为了使用专门为对象设计的API和特性(比如 泛型 )

在JDK1.5之前,这个转化过程需要手动实现,即使用包装类的 构造器 来创建对象。(称为手动装箱);

在JDK1.15之后,这个转化过程可以自动实现,即直接赋值。(称为自动装箱)

代码示例

 import org. junit .Test;//导入junit包,用来进行单元测试(比main方法好用,一个类可以创建多个程序入口)

public class Demo7 {
 

    /**
     *  Integer(Byte,Double,Float,Long,Short类似)
     */    @Test
    public  void  test1(){
 
        int i1 = 10; //定义基本数据类型(整型)

//基本数据类型转化成包装类
        //手动装箱(使用构造器)
        Integer i2 = new Integer(i1);
        Integer i3 = new Integer("11"); //也可以是字符类型,但是必须是数字,否则报错
        //自动装箱(直接赋值)
        Integer i4 = i1;

//输出结果,测试验证
        System.out.println(i1);
        System.out.println(i2);
        System.out.println(i3);
        System.out.println(i4);


    }

    /**
     * Character
     */    @Test
    public void test2(){
 
        char c1 = 'a'; //定义基本数据类型(字符型)

//基本数据类型转化成包装类
        //手动装箱(构造器)
        Character c2 = new Character(c1);
//Character c3 = new Character("a"); 不能是字符,如果是字符就会分不清,本身就是了

        //自动装箱(直接赋值)
        Character c4 = c1;

//输出结果,测试验证
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c4);
    }

    /**
     * Boolean
     */    @Test
    public void test3(){
 
        boolean b1=true; //定义基本数据类型(布尔型)
        
//基本数据类型转化成包装类
        //手动装箱
        Boolean b2=new Boolean(b1);
        Boolean b3=new Boolean("true");//只要参数不是true这个 字符串 ,都返回false
        if(b3)
            System.out.println("b3=true");
        else
            System.out.println("b3=false");

        //自动装箱(直接赋值)
        Boolean b4=b1;

//输出结果,测试验证
System.out.println(b1);
System.out.println(b2);
System.out.println(b4);

    }
}  

与装箱相反,拆箱就是把包装类对象转化为基本类型的过程。

转为基本数据类型,一般是因为需要运算,Java中的大多数 运算符 是为基本数据类型设计的。比较、算术等,这样的效率更高

在JDK1.5之前,这个转化过程需要手动实现,即通过对应的包装类调用xxxValue()方法。(称为手动拆箱);

在JDK1.15之后,这个转化过程可以自动实现,即直接赋值。(称为自动拆箱)

代码示例

 import org.junit.Test;

public class Demo7 {
 

    /**
     *  Integer(Byte,Double,Float,Long,Short类似)
     */    @Test
    public void test1(){
 
        int i1 = 10;//定义基本数据类型(整型)

        //自动装箱,用于后面拆箱
        Integer i4 = i1;

//包装类转化为基本数据类型

        //手动拆箱(调用xxxValue())
        int i5 = i4.intValue();
        //自动拆箱(直接赋值)
        int i6 = i4;

//输出结果,测试验证
        System.out.println(i1);
        System.out.println(i4);
        System.out.println(i5);
        System.out.println(i6);

    }

    /**
     * Character
     */    @Test
    public void test2(){
 
        char c1 = 'a';//定义基本数据类型(字符型)

        //自动装箱,用于后面拆箱
        Character c4 = c1;
        
        //包装类转化为基本数据类型
        //手动拆箱
        char c5 = c4.charValue();
        //自动拆箱
        char c6 =c4;

//输出结果,测试验证
        System.out.println(c1);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);

    }

    /**
     * Boolean
     */    @Test
    public void test3(){
 
        boolean b1=true; //定义基本数据类型(布尔型)

       //自动装箱,用于后面拆箱
        Boolean b4=b1;

 //包装类转化为基本数据类型
        //手动拆箱
        boolean b5=b2.booleanValue();
        //自动拆箱
        boolean b6=b2;
        
//输出结果,测试验证
        System.out.println(b1);
        System.out.println(b4);
        System.out.println(b5);
        System.out.println(b6);

    }
}  

包装类常见的API

基本数据类型和字符串之间的转换

(1)把基本数据类型转为字符串(调用valueOf()方法)

 import org.junit.Test;

public class Demo8 {
 
    /**
     * 基本数据类型转化为字符型
     */    
    @Test
    public void test(){
 

    int a = 10; //定义基本数据类型

    //String str = a;//不能直接转换
    
    //方式一:
    String str = a + "";
    //方式二:
    String str1 = String.valueOf(a);
    
    }
}  

(2)把字符串转为基本数据类型

String转换成对应的基本类型 ,除了Character类之外,其他所有包装类都具有parseXxx() 静态方法 可以将字符串参数转换为对应的基本类型:

 public  static  byte parseByte(String s)
public static short parseShort(String s)
public static int parseInt(String s)
public static long parseLong(String s)
public static float  parseFloat (String s)
public static double parseDouble(String s)
public static boolean parseBoolean(String s) 
 int a = Integer.parseInt("整数的字符串");
double a = Double.parseDouble("小数的字符串");
boolean b = Boolean.parseBoolean("true或false");  

注意: 如果字符串参数的内容无法正确转换为对应的基本类型,

则会抛出 java.lang.NumberFormat Exception 异常。

数据类型的最大值和最小值

求某个数据类型的最大值和最小值,直接调用MAX_VALUE和MIN_VALUE方法

 import org.junit.Test;

public class Demo8 {
 
   /**
     * Integer类型的最大值和最小值(其他类似)
     */    @Test
    public void test1(){
 
        
        //最大值
        int maxValue = Integer.MAX_VALUE;
        //最小值  
        int minValue = Integer.MIN_VALUE;

//输出结果,验证测试
        System.out.println(maxValue);
        System.out.println(minValue);
    }

}  

转大小写

如果转包装类型的大小写,则需要调用 toUpperCase ()方法和toLowerCase()方法

 import org.junit.Test;

public class Demo8 {
 
    /**
     * Character转大小写
     */ 
    @Test
    public void test2(){
 

        char x1 = Character.toUpperCase('x');
        char x2 = Character.toLowerCase('X');

        System.out.println(x1);
        System.out.println(x2);
    }

}  

如果转包装类型的 进制 ,则需要调用对应方法( 二进制 toBinaryString(),十六进制toHexString(),八进制toOctalString())

 package com.atguigu.demo;

import org.junit.Test;

public class Demo8 {
 

    /**
     * 转进制
     */
    @Test
    public void test3(){
 

        int i = 6; //十进制的6

        String s1 = Integer.toBinaryString(i); //二进制
        String s2 = Integer.toHexString(i); //十六进制
        String s3 = Integer.toOctalString(i); // 八进制 

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
    }
}  

包装类对象的缓存问题

有一部分包装类提供了对象的缓存。对于频繁使用的包装类对象,其类在初始化时就会提前创建好对象,当需要使用该包装类的对象时,如果该对象包装的值在缓存的范围内(这个范围是在Java源码中设置的),就返回缓存的对象;当该对象的值大于缓存的范围,就会创建新的对象并返回。

下面以Integer的源码进行说明

 Integer i = 10; //自动装箱,默认会调用valueOf方法

/**
 * Integer的自动装箱源码
*/
public static Integer valueOf(int i) {
    //判断i的值,是否在一个范围  -128 ~ 127  从数组中取值(地址)
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        //如果值在这个范围,返回一个数组中的值
        return IntegerCache.cache[i + (-IntegerCache.low)];
        //如果不在这个范围,new一个(和自己new的对象没区别)
    return new Integer(i);
}  

各个包装类对应的 缓存 对象大小如下表:

包装类

缓存对象

Byte

-128~127

Short

-128~127

Integer

-128~127

Long

-128~127

Float

没有

Double

没有

Character

0~127

Boolean

true和false

面试常考

包装类中“== ”与equals的用法比较,可以算是非常重要的考点了。

包装类中的equals方法和String类一样,都是重写了Object类中的equals方法,因此比较的是内容而不是地址,而“= =”比较的依然是引用变量的地址,只是当包装类型和与之相对应的基本类型进行“==”比较时会先做自动拆箱处理。具体可以分类如下:

  • ①如果在默认范围内的自动装箱,则相等(比较地址)
  • ②如果比较的对象有自己new的,则不相等(比较地址)
  • ③如果比较的对象值不在范围内部也是不想等的(比较地址)
  • ④如果有基本数据类型参与对比,包装类型就会自动拆箱,就会变成了基本数据类型的对比,
  • 这个时候比的就是值了。

常见笔试或面试问题举例

 import org.junit.Test;

public class Demo9 {
 

    @Test
    public void test(){
 
        Integer i1 = 10; //1. Integer这个类会加载  2. 在创建i2这个局部变量
        Integer i2 = 10; 
        System.out.println(i1 == i2); //true 对比地址

        Integer i3 = new Integer(10);
        System.out.println(i1 == i3); //false 对比地址

        Integer i4 =300;
        Integer i5 =300;
        System.out.println(i4 == i5);//false 对比地址

        Integer i6 = 300;
        int i7 = 300;
        System.out.println(i6 == i7); //true 对比值(因为有基本数据类型(i6会转为int在对比) )

    }
}