1. Java语言有几种基本类型,分别是什么?
在Java中,基本数据类型分为两大类:原始数据类型(Primitive Data Types)和引用数据类型(Reference Data Types)。原始数据类型又分为四类:整数类型、浮点类型、字符类型和布尔类型。
- 整数类型(Integer Types):
- byte:8位,有符号,范围为-128到127。
- short:16位,有符号,范围为-32,768到32,767。
- int:32位,有符号,范围为-2^31到2^31-1。
- long:64位,有符号,范围为-2^63到2^63-1。
- 浮点类型(Floating-Point Types):
- float:32位,单精度浮点数。
- double:64位,双精度浮点数。
- 字符类型(Character Type):
- char:16位,无符号,表示Unicode字符。
- 布尔类型(Boolean Type):
- boolean:表示逻辑值,只能取
true
或false
。
这些基本数据类型是Java语言的基础,用于存储简单的数据值。在Java中,对象都是引用数据类型,包括类、接口、数组等。这些基本数据类型具有不同的大小和范围,根据需要选择合适的类型来存储数据。
2. int[]类型是不是基本类型?
不是,int[]
不是基本数据类型,而是一种引用数据类型。在Java中,数组是一种引用数据类型,它可以包含基本数据类型的元素或其他引用类型的元素。int[]
表示一个整数类型的数组,其中的元素都是 int
类型。
基本数据类型是存储简单数值的类型,而引用数据类型是用来存储对象引用的类型。基本数据类型直接包含数据值,而引用数据类型包含对存储在内存中的对象的引用。
当你声明一个 int[]
类型的数组时,实际上创建了一个对象,该对象存储了一组整数,并且变量(数组名)存储的是对该对象的引用。因此,int[]
是引用数据类型,而不是基本数据类型。
3. 什么是128陷阱?什么是装箱?什么是拆箱?为什么要有包装类?
128 位整数陷阱(128-bit Integer Trap):
Java 中的基本数据类型 long
是 64 位的,而在某些场景下需要表示更大的整数值,比如超过 Long.MAX_VALUE
。在这种情况下,有时候会考虑使用 BigInteger
类,它可以表示任意大小的整数,但由于其灵活性和大数计算的特性,性能可能相对较低,而且在处理一些常规整数时不如基本数据类型高效。
装箱和拆箱(Boxing and Unboxing):
- 装箱: 将基本数据类型转换为对应的包装类对象。例如,将
int
装箱为Integer
。 - 拆箱: 将包装类对象转换为对应的基本数据类型。例如,将
Integer
拆箱为int
。
// 装箱 int primitiveInt = 42; Integer boxedInt = Integer.valueOf(primitiveInt); // 拆箱 int unboxedInt = boxedInt.intValue();
- 包装类(Wrapper Classes):
- Java 提供了一组包装类,用于将基本数据类型转换为对象,以便在需要对象的上下文中使用。以下是常见的包装类:
Boolean
:对应基本数据类型boolean
Byte
:对应byte
Short
:对应short
Integer
:对应int
Long
:对应long
Float
:对应float
Double
:对应double
Character
:对应char
- 通过使用包装类,可以在需要对象的情况下使用基本数据类型,也可以在集合类中存储基本数据类型,因为集合类通常只能存储对象。
- 为什么要有包装类?:
- 对象化: 在需要对象而基本数据类型不够时,可以使用包装类将其转化为对象。
- 集合框架: 集合类(如
List
、Set
、Map
等)只能存储对象,因此需要包装类来存储基本数据类型的值。 - 泛型: 泛型也要求使用对象,而不是基本数据类型。
- 包装类提供了一种将基本数据类型转换为对象的方式,使得在某些情况下,可以方便地在面向对象的环境中使用基本数据类型。同时,自动装箱和拆箱的特性使得在基本数据类型和其对应的包装类之间进行转换更加方便。
4. 位运算有哪几种?
位运算是一种对二进制位进行操作的运算,Java 提供了几种常见的位运算操作符:
- 按位与(&):
- 两个相应的位都为1时,结果为1;否则,结果为0。
- 按位或(|):
- 两个相应的位只要有一个为1,结果就为1;否则,结果为0。
- 按位异或(^):
- 两个相应的位不同,结果为1;相同,结果为0。
- 取反(~):
- 每个位上的0变成1,1变成0。
- 左移(<<):
- 将操作数的所有位向左移动指定的次数,右侧空出的位用0填充。
- 右移(>>):
- 将操作数的所有位向右移动指定的次数,左侧空出的位根据符号位(正数补0,负数补1)或者补0进行填充。
- 无符号右移(>>>):
- 将操作数的所有位向右移动指定的次数,左侧空出的位总是用0填充。
这些位运算操作符可以用于执行一些底层的位级操作,如掩码、权限控制、压缩存储等。在一些特定的场景中,位运算可以提高程序的执行效率。
5. “>>”和”>>>”的区别是什么?
>>
和 >>>
都是右移操作符,但它们在处理带符号整数和无符号整数时有一些区别。
>>
右移操作符:
int x = -8; System.out.println(x >> 1); // 结果为 -4
- 对于正数,
>>
和>>>
的效果相同,都是将所有位右移,左侧空出的位用0填充。 - 对于负数,
>>
采用“算术右移”,即将所有位右移,左侧空出的位用符号位填充(即保持符号位不变)。
>>>
无符号右移操作符:
>>> 无符号右移操作符: 无论正数还是负数,>>> 都是采用“逻辑右移”,即将所有位右移,左侧空出的位总是用0填充。
- 无论正数还是负数,
>>>
都是采用“逻辑右移”,即将所有位右移,左侧空出的位总是用0填充。
6. String类的常用函数有哪些?列举十种。
String
类是 Java 中用来表示字符串的类,它提供了许多常用的方法来操作字符串。以下是 String
类的一些常用方法,其中列举了十种:
length()
方法:
- 返回字符串的长度,即包含的字符数。
charAt(int index)
方法:
- 返回字符串中指定索引位置的字符。
substring(int beginIndex)
和 substring(int beginIndex, int endIndex)
方法:
substring(int beginIndex)
返回从指定索引开始到字符串末尾的子字符串。substring(int beginIndex, int endIndex)
返回从指定索引开始到指定索引结束之前的子字符串。
concat(String str)
方法:
- 将指定字符串连接到该字符串的末尾。
indexOf(String str)
和 indexOf(String str, int fromIndex)
方法:
indexOf(String str)
返回指定子字符串在该字符串中第一次出现的索引。indexOf(String str, int fromIndex)
从指定的索引位置开始,返回指定子字符串在该字符串中第一次出现的索引
toUpperCase()
和 toLowerCase()
方法:
toUpperCase()
将字符串中的所有字符转换为大写。toLowerCase()
将字符串中的所有字符转换为小写。
trim()
方法:
- 返回一个字符串,删除了原字符串开头和末尾的所有空格。
startsWith(String prefix)
和 endsWith(String suffix)
方法:
startsWith(String prefix)
判断字符串是否以指定的前缀开始。endsWith(String suffix)
判断字符串是否以指定的后缀结束。
replace(char oldChar, char newChar)
和 replace(CharSequence target, CharSequence replacement)
方法:
replace(char oldChar, char newChar)
替换字符串中的所有指定字符。replace(CharSequence target, CharSequence replacement)
替换字符串中的所有指定字符序列。
split(String regex)
方法:
- 使用给定的正则表达式拆分字符串,返回一个字符串数组。
7. String和StringBuffer,StringBuilder的区别有哪些?所有类名包含Buffer的类的内部实现原理是什么?有什么优势?
String
、StringBuffer
和 StringBuilder
是 Java 中用于处理字符串的三个主要类,它们有一些关键的区别,主要体现在可变性、线程安全性和性能上。
String
类:
在选择使用 String
、StringBuffer
或 StringBuilder
时,需要根据具体的需求来决定。如果在多线程环境下,需要线程安全性,则选择 StringBuffer
;如果在单线程环境下,并且不需要线程安全性,则选择 StringBuilder
,由于 StringBuilder
不进行同步,因此性能更好。如果字符串是常量,不需要修改,则选择 String
。
- 不可变性: 字符串是不可变的,一旦创建,内容无法修改。
- 线程安全: 由于字符串是不可变的,所以是线程安全的。
- 性能: 由于不可变性,每次对字符串进行修改都会创建一个新的字符串对象,可能导致性能开销。
StringBuffer
类: - 可变性: 字符串缓冲区,可以修改其中的内容。
- 线程安全:
StringBuffer
是线程安全的,各个方法都进行了同步处理。 - 性能: 在多线程环境下使用时,相对于
StringBuilder
,由于同步处理,性能稍逊一筹。StringBuilder
类: - 可变性: 字符串生成器,可以修改其中的内容。
- 线程安全:
StringBuilder
是非线程安全的,不进行同步处理。 - 性能: 在单线程环境下,由于不进行同步处理,性能较好。关于所有类名包含 "Buffer" 的类的内部实现原理,通常这些类都是基于缓冲区(Buffer)实现的。缓冲区是一块临时存储区域,用于临时保存数据,提高读写的效率。这些类通常使用数组作为底层数据结构,通过对数组的操作来实现对字符串的修改。缓冲区的使用可以避免频繁的对象创建和销毁,从而提高字符串操作的效率。
优势: - 性能:
StringBuffer
和StringBuilder
通过使用可变的缓冲区,避免了频繁的对象创建和销毁,提高了字符串操作的性能。 - 灵活性: 可以方便地对字符串进行修改,而不需要创建新的字符串对象。
8. String字符串的不可变是指哪里不可变?
字符串的不可变性是指在创建之后,字符串对象的内容不可被修改。具体来说,不可变性表现在以下几个方面:
值不可变:
一旦字符串对象被创建,其中的字符序列不可更改。
长度不可变:
字符串的长度在创建后也是不可变的。无法通过直接修改字符串对象来改变其长度。
不可变性的好处:
- 线程安全性: 由于字符串是不可变的,多个线程可以安全地共享字符串对象,而无需担心修改冲突。
- 安全性: 字符串不可变性提供了一定的安全性,因为它们无法在创建后被意外地修改。
- 缓存: 由于字符串的不可变性,可以进行一些优化,例如字符串常量池的使用,以及缓存哈希码等。
9. 字符串常量池是什么?不同的JDK版本都分别位于哪个区域?
字符串常量池(String Constant Pool)是 Java 中用于存储字符串常量的一个特殊的内存区域。字符串常量池的目的是提高字符串的重用性,减少内存的占用。
在 Java 中,字符串常量池位于方法区(Method Area),这是一种线程共享的内存区域,存储了类的结构信息、静态变量、常量池等数据。
不同的 JDK 版本中,字符串常量池的具体位置可能有所变化:
- JDK 6 及之前:
- 字符串常量池位于永久代(Permanent Generation)中。
- JDK 7 和 JDK 8:
- JDK 7 中还是位于永久代。
- JDK 8 引入了元空间(Metaspace),替代了永久代。字符串常量池被移至堆中,与堆共享内存。
- JDK 9 及之后:
- JDK 9 进一步改进了内存模型,移除了永久代,完全采用元空间,字符串常量池仍然位于堆中。
在 JDK 7 和 JDK 8 中,字符串常量池的移动到堆中的改变,是为了解决永久代内存泄漏的问题。元空间的引入进一步改善了类的元信息存储机制,避免了永久代的一些限制和问题。
请注意,由于不同的 JDK 实现和配置可能有所不同,具体的内存区域分配情况可能会有一些变化。上述描述主要是针对 Oracle JDK 和 OpenJDK 的情况。
10. Java异常类有哪些?分别管理什么异常?
Java 中的异常分为两大类:检查异常(Checked Exception)和非检查异常(Unchecked Exception)。
检查异常(Checked Exception):
- IOException:
- 用于处理输入输出操作中可能发生的异常,如文件读写等。
- FileNotFoundException:
- 继承自 IOException,表示尝试打开一个不存在的文件时抛出的异常。
- ParseException:
- 通常用于处理字符串解析为日期等格式时可能发生的异常。
- SQLException:
- 用于处理与数据库相关的异常。
- ClassNotFoundException:
- 在使用 Class 类的 forName 方法时,如果指定的类不存在,会抛出此异常。
非检查异常(Unchecked Exception):
- RuntimeException:
- 这是一个非常常见的非检查异常的父类,包括以下几种:
- ArithmeticException: 用于处理算术运算中可能发生的异常,如除以零。
- NullPointerException: 表示对一个对象调用方法、访问字段或数组元素时,对象引用为 null。
- ArrayIndexOutOfBoundsException: 表示数组下标越界。
- IndexOutOfBoundsException: 表示索引越界,通常由于集合操作中的错误使用引起。
- IllegalArgumentException: 表示传递给方法的参数值不合法。
- IllegalStateException: 表示对象的状态不合法。
- NumberFormatException: 表示字符串转换为数字时的格式错误。
- ConcurrentModificationException: 在使用迭代器遍历集合的过程中,如果集合的结构发生变化,会抛出此异常。
- NullPointerException:
- 虽然
NullPointerException
属于RuntimeException
的子类,但由于其普遍性,特别列出。 - 表示对一个对象调用方法、访问字段或数组元素时,对象引用为 null。
- ArrayIndexOutOfBoundsException:
- 同样属于
RuntimeException
的子类,表示数组下标越界。
这些异常类用于处理在程序运行期间可能出现的各种错误状况。检查异常在编译期强制处理,程序员必须捕获或声明抛出,而非检查异常通常是运行时异常,程序员可以选择捕获和处理,也可以不处理。