Java基本数据类型

Java 基本数据类型

Java 中的几种基本数据类型是什么?对应的包装类型是什么?各自占用多少字节?

8 种基本数据类型:byte 1,short 2,int 4,long 8,float 4,dobule 8,char 2,boolean 1

对应的包装类型:Byte,Short,Interger,Long,Float,Double,Character,Boolean

对应占用的字节:1,2,4,8,4,8,2,1

注意:short 是 2 字节

讲讲 int 的取值范围是多少?

想想字节取值范围的关系。

  • int 有 4 个字节,也就是占 32 个比特位,
  • 所以取值范围就是【-2 的 31 次方到 2 的 31 次方减 1】,即约为 -2,147,483,648 到 2,147,483,647。

需要注意的是,这个范围是针对有符号的整数类型。

如果使用【无符号】的整数类型(如 Java 中的 unsigned int),则范围将从 0 到 2^32 - 1,即约为 0 到 4,294,967,295。

基本类型和包装类型的区别?

五大区别:

用途

  • 基本类型一般用来定义一些常量和局部变量,我们在其他地方比如方法参数、对象属性中很少会使用基本类型来定义变量。
  • 包装类型可用于泛型,而基本类型不可以。

存储方式

  • 基本数据类型的【局部变量】存放在 Java 虚拟机中的局部变量表中,基本数据类型的【成员变量】(未被 static 修饰 )存放在 Java 虚拟机的堆中。
  • 包装类型属于对象类型,几乎所有对象实例都存在于堆中。

占用空间

相比于包装类型(对象类型),基本数据类型占用的空间往往非常小。

默认值

  • 成员变量包装类型的默认值是 null

  • 基本类型有默认值,但不固定。

    • byte:0
    • short:0
    • int:0
    • long:0L
    • float:0.0f
    • double:0.0d
    • char:‘\u0000’
    • boolean:false

比较方式

  • 对于基本数据类型来说,== 比较的是值。
  • 对于包装数据类型来说,== 比较的是对象的内存地址。所有整型包装类对象之间值的比较,全部使用 equals() 方法。

包装类型的缓存机制了解吗?

另一种说法是:包装类型的常量池技术。

Java 基本数据类型的包装类型大部分都用到了缓存机制来提升性能(除了浮点型)。即会默认创建相应类型的缓存数据

例如:Byte,Short,Interger,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False

当使用自动装箱的方式将一个基本数据类型的值转换为包装类型时,如果这个值在缓存范围内,那么就直接返回缓存中的对象,否则就创建一个新的对象

由于包装类型的值是存储在堆内存中的,因此在进行大量的数值计算时,使用包装类型会比直接使用基本数据类型更加耗时和占用内存。为了提高程序的性能和效率,Java 提供了包装类型的缓存机制。

为什么要有包装类型?

在 Java 中,包装类型是将基本数据类型(如 int、double 等)封装成对象的一种机制

Java 中引入包装类型的主要原因是为了提供一些额外的功能和灵活性,这些功能在基本数据类型上不可用。

以下是一些包装类型的常见用途:

  1. 包装类型可以使基本数据类型具有对象特性。例如,可以将包装类型存储在集合中(如 List、Map 等),而基本数据类型不能。
  2. 包装类型具有面向对象的行为。例如,可以使用 toString() 方法将包装类型转换为字符串,而基本数据类型不能。
  3. 包装类型可以为 null。例如,如果尝试将基本数据类型赋值为 null,则会引发空指针异常。但是,将包装类型赋值为 null 是可以的。(一般声明变量时用引用类型,而参数类型用基本数据类型)
  4. 包装类型支持自动装箱和拆箱。自动装箱是指将基本数据类型自动转换为相应的包装类型,而自动拆箱是指将包装类型自动转换为相应的基本数据类型。这使得代码更加简洁和易于编写。

总之,包装类型可以使 Java 代码更加灵活和易于维护。它们可以使基本数据类型具有对象特性,并提供了许多基本数据类型上不可用的功能。此外,Java 中的包装类型还可以用于处理空值和进行类型转换,这些在基本数据类型上是不可能实现的。

自动装箱与拆箱了解吗?原理是什么?

装箱就是将基本类型用它们对应的引用类型包装起来,原理是调用了包装类的 valueOf() 方法;

拆箱是将包装类型转换为基本数据类型,相应的调用的是 xxxValue() 方法,比如 intValue() 方法。

eg:

  • Integer i = 10 等价于 Integer i = Integer.valueOf(10) – 装箱
  • int n = i 等价于 int n = i.intValue() – 拆箱

原理:

基本类型与相应的包装类型用 == 号比较会怎么样?

Integer a = new Integer(10);
Integer b = new Integer(10);

System.out.println(a == b); // 输出 false,因为比较的是引用

int c = 10;
System.out.println(a == c); // 输出 true,因为自动拆箱后比较的是值

为什么浮点数运算的时候会有精度丢失的风险?

浮点数运算精度丢失代码演示:

float a = 2.0f - 1.9f;
float b = 1.8f - 1.7f;
System.out.println(a); // 0.100000024
System.out.println(b); // 0.099999905
System.out.println(a == b); // false

这是因为计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。

如何解决浮点数运算的精度丢失问题?

使用 BigDecimal 可以实现对浮点数的运算,并且不会造成精度丢失。

通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");

BigDecimal x = a.subtract(b); // sub 减法
BigDecimal y = b.subtract(c);

System.out.println(x); /* 0.1 */
System.out.println(y); /* 0.1 */
System.out.println(Objects.equals(x, y)); /* true */

超过 long 整型的数据应该如何表示?

基本数值类型都有一个表达范围,如果超过这个范围就会有数值溢出的风险。

在 Java 中,64 位(8字节) long 整型是最大的整数类型。

如果需要表示超过 long 整型的数据,可以使用 Java 提供的 BigInteger

import java.math.BigInteger;
public class BigIntegerDemo {
    public static void main(String[] args) {
        BigInteger a = new BigInteger("12345678901234567890");
        BigInteger b = new BigInteger("98765432109876543210");
        BigInteger c = a.add(b);
        System.out.println(c);
    }
}
  • BigInteger 类的加、减、乘、除等运算都是通过调用方法来实现的,而不是像基本数据类型那样使用运算符。
  • BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。
  • 需要注意的是,BigInteger 类的运算时间和空间成本比基本数据类型高得多,即运算的效率相对较低。

什么是引用类型?

在 Java 中,除了基本数据类型和 void 类型以外,其它所有类型都是引用类型。

  • void 类型是一种特殊的类型,它表示没有返回值的方法或表达式的类型。
  • 在 Java 中,void 类型不属于基本数据类型,也不属于引用类型,而是一种独立的类型。

常见的引用类型包括:

  1. 类类型(Class):代表类的类型。
  2. 接口类型(Interface):代表接口的类型。
  3. 数组类型(Array):代表数组的类型。
  4. 枚举类型(Enum):代表枚举的类型。
  5. 泛型类型(Generics):代表泛型类或泛型方法的类型。
  6. 注解类型(Annotation):代表注解的类型。
  7. 自定义类型(Custom):在程序中自定义的类型,如自定义的类、接口、枚举等。
MyClass obj = new MyClass();  // 使用 new 关键字创建 MyClass 类的对象,并将对象赋值给 obj 变量

此时,obj 变量存储的是对象的内存地址,即对象的引用。因此,通过 obj 变量可以访问对象的属性和方法。

NPE 问题?

NPE 问题就是:空指针异常(NullPointerException,NPE)问题。

在 Java 中,自动拆箱是将包装类型自动转换为相应的基本数据类型的过程,而如果包装类型为null,自动拆箱就会引发空指针异常(NullPointerException,NPE)。

这是因为基本数据类型不支持为 null 值,因此在尝试使用为 null 的包装类型时,Java 会尝试将其转换为基本数据类型,从而引发 NPE 异常。

以下是一个简单的示例,展示了自动拆箱引发 NP E问题的情况:

Integer num = null;
int i = num; // 自动拆箱,将null转换为int类型,引发NPE异常

为了避免自动拆箱引发的 NPE 问题,可以使用条件语句或显式拆箱来检查包装类型是否为 null。例如,可以使用以下代码检查包装类型是否为 null:

Integer num = null;
// 条件语句
int i = (num != null) ? num : 0;

使用显式拆箱的代码如下:

Integer num = null;
// 显示拆箱
int i = num != null ? num.intValue() : 0;

可以看出来,两者代码差不多,在这里其实 num 等价于 num.intValue()

最后这个代码没加括号是因为:在 Java 中,三目运算符(?:)的优先级比赋值运算符(=)高,而比相等运算符(==)和不等运算符(!=)低。因此,num != null 会先执行,代码可以不加括号而直接编写。

你可能感兴趣的:(Java,java,开发语言)