杰瑞科技汇

String 是 Java 基本数据类型吗?

目录

  1. Java 基本数据类型

    String 是 Java 基本数据类型吗?-图1
    (图片来源网络,侵删)
    • 什么是基本数据类型?
    • 四大类八种
    • 类型默认值
    • 类型转换
  2. Java String

    • String 的特殊性
    • 不可变性
    • 创建方式与内存分配
    • 常用方法
  3. 基本数据类型与 String 的转换

    • 基本类型 -> String
    • String -> 基本类型

Java 基本数据类型

什么是基本数据类型?

在 Java 中,数据类型分为两大类:基本数据类型引用数据类型

  • 基本数据类型:Java 语言内置的、最简单的数据类型,它们不是对象,没有方法,变量中直接存储的是“值”本身,它们存储在栈内存 中,速度快,但空间有限。
  • 引用数据类型:所有由 class, interface, arrayenum 创建的类型,它们的变量存储的是一个“引用”(内存地址),指向堆内存中的实际对象。

四大类八种

Java 定义了 8 种基本数据类型,可以分为 4 大类:

String 是 Java 基本数据类型吗?-图2
(图片来源网络,侵删)
数据类型 大小 (字节) 默认值 范围 说明
整数类型
byte 1 0 -128 ~ 127 字节,用于节省空间
short 2 0 -32768 ~ 32767 短整型
int 4 0 -2³¹ ~ 2³¹-1 最常用的整数类型
long 8 0L -2⁶³ ~ 2⁶³-1 长整型,数字后加 Ll
浮点类型
float 4 0f 精确到小数点后 7 位 单精度浮点数,数字后加 fF
double 8 0d 精确到小数点后 15 位 最常用的浮点类型,数字后可加 dD
字符类型
char 2 '\u0000' \u0000 ~ \uffff 单个 16 位 Unicode 字符,用单引号 括起来
布尔类型
boolean 1 false true / false 只能取 truefalse,通常用于逻辑判断

注意:

  • long 类型的字面量必须后缀 L,否则会被当作 int 处理,如果超出 int 范围会编译错误。long num = 10000000000L;
  • float 类型的字面量必须后缀 f,否则会被当作 double 处理。float price = 19.99f;

类型默认值

当在类中定义成员变量(全局变量)但没有显式初始化时,Java 会为它们提供默认值。局部变量没有默认值,必须显式初始化才能使用

数据类型 默认值
byte, short, int, long 0
float, double 0
char '\u0000' (空字符)
boolean false
所有引用类型 null

类型转换

基本数据类型之间可以转换,但要遵循规则:

  1. 自动类型转换 (隐式转换)

    String 是 Java 基本数据类型吗?-图3
    (图片来源网络,侵删)
    • 规则:从小类型到大类型转换,数据不会丢失。
    • 顺序byte -> short -> int -> long -> float -> double
    • char -> int 也是自动的。
    • 示例
      int i = 100;
      long l = i; // int 自动转换为 long
      double d = i; // int 自动转换为 double
  2. 强制类型转换 (显式转换)

    • 规则:从大类型到小类型转换,可能造成精度丢失或数据溢出。
    • 语法(目标数据类型) 变量
    • 示例
      double d = 9.8;
      int i = (int) d; // 强制转换,小数部分被舍弃,i 的值为 9
      long l = 1000L;
      int j = (int) l; // long 强制转换为 int

Java String

String 是 Java 中最常用的引用数据类型,但它有一些非常特殊的性质。

String 的特殊性

  • String 不是基本数据类型,它是一个 final 类,位于 java.lang 包中。
  • 它被广泛使用,以至于 Java 语言为其提供了一些“语法糖”,使得它的使用看起来像基本类型。

不可变性

这是 String 最核心、最重要的特性:String 对象一旦被创建,其内容(值)就不能被改变。

  • 当你尝试修改一个 String 对象时,JVM 实际上会创建一个新的 String 对象来存储修改后的内容,而原来的对象保持不变。
  • 示例
    String s = "hello";
    s = s + " world"; // 这行代码没有修改原来的 "hello" 对象
    // 1. 首先在内存中创建一个新的字符串 "hello world"
    // 2. 然后让变量 s 指向这个新的对象
    // 3. "hello" 对象如果不再被引用,就会被垃圾回收器回收

为什么设计成不可变?

  1. 线程安全:不可变对象天生就是线程安全的,因为它们不会被多个线程同时修改。
  2. 便于缓存和哈希不变,String 对象的 hashCode() 值在对象生命周期内也永远不会改变,这可以安全地作为 HashMap 等哈希结构中的键。
  3. 字符串常量池优化:JVM 为了优化性能,使用了一个特殊的内存区域——字符串常量池

创建方式与内存分配

String 有两种主要的创建方式,它们的内存分配机制完全不同:

  1. 字面量赋值(推荐)

    • String s = "hello";
    • JVM 执行流程
      1. 首先在字符串常量池 中查找是否存在 "hello" 这个字符串。
      2. 如果存在,则直接将变量 s 指向池中的 "hello"
      3. 如果不存在,则在池中创建一个新的 "hello" 对象,然后将 s 指向它。
    • 优点:可以复用池中的字符串对象,节省内存。
  2. new 关键字创建

    • String s = new String("hello");
    • JVM 执行流程
      1. 堆内存 中创建一个新的 String 对象,内容为 "hello"
      2. 检查字符串常量池中是否存在 "hello"
      3. 如果不存在,则在池中也创建一个 "hello" 对象。
      4. 将变量 s 指向堆内存中创建的那个新对象。
    • 缺点:无论如何都会在堆中创建新对象,如果池中没有,还会在池中再创建一个,效率较低,内存占用也较多。

示例对比:

String s1 = "hello";
String s2 = "hello"; // s1 和 s2 指向常量池中的同一个 "hello" 对象
System.out.println(s1 == s2); // 输出 true,比较的是地址(引用)
String s3 = new String("hello");
String s4 = new String("hello"); // s3 和 s4 分别指向堆中两个不同的 "hello" 对象
System.out.println(s3 == s4); // 输出 false
System.out.println(s1 == s3); // 输出 false,s1 在池中,s3 在堆中

常用方法

String 提供了非常丰富的方法来操作字符串:

  • length(): 返回字符串长度。
  • charAt(int index): 返回指定索引处的字符。
  • substring(int beginIndex, int endIndex): 截取子字符串。
  • toUpperCase() / toLowerCase(): 转换为大写/小写。
  • trim(): 去除字符串首尾的空格。
  • split(String regex): 根据正则表达式分割字符串。
  • equals(Object anObject): 比较字符串内容是否相等(区分大小写)。
  • equalsIgnoreCase(String anotherString): 比较字符串内容是否相等(不区分大小写)。
  • compareTo(String anotherString): 按字典顺序比较两个字符串。
  • contains(CharSequence s): 判断是否包含指定序列。

基本数据类型与 String 的转换

在实际开发中,经常需要在基本数据类型和 String 之间进行转换。

基本类型 -> String

有三种常用方法:

  1. 使用 号(最简单)

    int num = 123;
    String str1 = num + ""; // "" 是空字符串,与任何类型相加都会变成字符串拼接
  2. 使用 String.valueOf() (最推荐)

    int num = 123;
    String str2 = String.valueOf(num); // 代码更清晰,性能也较好
    // 还有其他重载方法:valueOf(long, float, double, char, boolean, Object)
  3. 使用包装类的 toString() 方法

    int num = 123;
    String str3 = Integer.toString(num);
    // long: Long.toString(), double: Double.toString() 等

String -> 基本类型

使用包装类的静态 parseXxx()valueOf() 方法。

  • int: Integer.parseInt(String s)
  • long: Long.parseLong(String s)
  • double: Double.parseDouble(String s)
  • float: Float.parseFloat(String s)
  • boolean: Boolean.parseBoolean(String s)
  • char: s.charAt(0)

示例与异常处理: 如果字符串格式不正确("abc" 无法转成数字),这些方法会抛出 NumberFormatException,在实际应用中最好使用 try-catch 结构。

String strNum = "100";
String strInvalid = "abc";
// 转换为 int
int num1 = Integer.parseInt(strNum); // 成功,num1 = 100
System.out.println(num1);
// 处理可能出现的异常
try {
    int num2 = Integer.parseInt(strInvalid); // 会抛出 NumberFormatException
} catch (NumberFormatException e) {
    System.out.println("无法将字符串 '" + strInvalid + "' 转换为整数!");
}
特性 基本数据类型 String
类型 Java 内置,不是对象 引用数据类型(final 类)
存储 栈内存 堆内存,字符串常量池
变量中直接存储值 变量中存储引用(地址)
可变性 值可变 不可变
创建 int a = 10; String s = "hello";new String("hello");
比较 比较值 比较引用地址,equals() 比较内容
转换 可通过强制/自动转换互转 可与基本类型通过包装类互相转换

理解这些基础概念对于编写高效、健壮的 Java 代码至关重要。

分享:
扫描分享到社交APP
上一篇
下一篇