Java常见API面试题

x33g5p2x  于2022-02-15 转载在 Java  
字(3.8k)|赞(0)|评价(0)|浏览(286)

Java常见API面试题

自动装箱与拆箱

装箱:将基本类型用它们对应的引用类型包装起来;原理:Integer.valueOf() 方法

拆箱:将包装类型转换为基本数据类型;原理:Integer.intValue() 方法

Java 为每个原始类型提供了包装类型:

原始类型: boolean,char,byte,short,int,long,float,double

包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

包装类型的常量池技术了解么?

Java 基本类型的包装类的大部分都实现了常量池技术。

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

Integer a= 127 与 Integer b = 127相等吗

如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false

Integer a1 = 128;
    Integer b1 = 128;
    System.out.println(a1 == b1); // false

    Integer a2 = 127;
    Integer b2 = 127;
    System.out.println(a2 == b2); // true

String的创建机理是什么?什么是字符串常量池?

  • 创建机理:由于String在Java世界中使用过于频繁,为了提高内存的使用率,避免开辟多块空间存储相同的字符串,引入了字符串常量池(字符串常量池位于堆内存中)
  • 运行机制:在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用

String 是最基本的数据类型吗

不是。Java 中的基本数据类型只有 8 个,除了基本类型,剩下的都是引用类型基本数据

类型中用来描述文本数据的是 char,但是它只能表示单个字符,如果要描述一段文本,就需要使用 char 类型数组,但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,使用更加简便

String s = new String(“abc”);创建了几个字符串对象

当JVM遇到上述代码时,会先检索常量池中是否存在“abc”,如果不存在“abc”这个字符串,则会先在常量池中创建这个字符串。然后再执行new操作,在堆内存中创建一个String对象,对象的引用赋值给s。此过程创建了2个对象。

当然,如果检索常量池时发现已经存在了对应的字符串,那么只会在堆内创建一个新的String对象,此过程只创建了1个对象。

String为什么是不可变的吗?是否可以继承 String 类

final修饰的String类,代表了String类的不可被继承,final修饰的char[]代表了被存储的数据不可更改被创建,是无法修改的,即便你在后面拼接一些其他字符,也会把新生成的字符串存到另外一个地址但是,虽然final代表了不可变,但仅仅是引用地址不可变,并不代表了数组本身不会变。

在使用 HashMap 的时候,用 String 做 key 有什么好处?

因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。

String和StringBuffer、StringBuilder的区别是什么?

  • 可变性:

String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。

  • 线程安全性:

String中的对象是不可变的,也就可以理解为常量,线程安全。

StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的

StringBuilder并没有对方法进行加同步锁,所以是非线程安全的

  • 性能:

每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象

StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

StringBuilder > StringBuffer > String
总结:

1、在字符串内容不经常发生变化的业务场景,优先使用String类,例如常量声明、少量的字符串拼接操作等。

2、在单线程环境下,频繁地进行字符串的操作,建议使用StringBuilder,例如SQL语句拼装、JSON封装等

3、在多线程环境下,频繁地进行字符串的操作,建议使用StringBuffer,例如XML解析、HTTP参数解析与封装

字符型常量和字符串常量的区别?

形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符

含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)

占内存大小 : 字符常量只占 2 个字节; 字符串常量占若干个字节 (注意: char 在 Java 中占两个字节

java 中 IO 流分为几种?

按功能来分:
    输入流(input)、输出流(output)。
按类型来分:
    字节流和字符流。
    
- 字节流
  - Intputstream类:输入字节流的基类(抽象类)
    - FileIntputStream类:字节输入流
    - BufferedInputStream类:字节缓冲输入流(高效流)
  - OutputStream类:输出字节流的基类(抽象类)	
    - FileOutputStream类:字节输出流
    - BufferedOutputStream类:字节缓冲输出流(高效流)
- 字符流
  - Reader类:输入字符流的基类
    - FileReader类:读取字符文件的便捷流
    - BufferedReader类:字符缓冲输入流(高效流)
    - InputStreamReader类:字节流和字符流之间的桥梁(转换流)
  - writer类:输出字符流的基类
    - FileWriter类:写入字符文件的便捷流
    - BufferedWriter类:字符缓冲输出流(高效流)
    - OutputStreamWriter类:字节输出流和字符输出流之间的桥梁(转换流)

对象序列化流

- 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象  
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息  
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息  
- 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

BIO,NIO,AIO 有什么区别?

1、同步:调用者主动获取(等待或者轮询去查看结果)
2、异步:调用结果是被调用者在完成之后通知调用者
3、阻塞:该线程主动挂起
4、非阻塞:该线程不主动挂起而是继续执行
5、同步阻塞:调用者发出调用后,如果函数不能立即返回结果,则挂起所在的线程,等待结果(需要调用者主动去询问)
6、同步非阻塞:调用者在发出调用之后,如果当时有数据可读,则读取并返回,如果没有数据可读,则线程继续向下执行
7、异步阻塞:调用者发出调用之后,线程挂起,被调用的IO操作由系统来进行,等待结果之后,系统通过某种机制来通知调用者
8、异步非阻塞:调用者发出调用之后,线程基础进行其他操作,被调用的IO操作由系统来进行,有结果之后,系统通知调用者

一个IO操作分为俩个步骤:
	发起IO请求
	实际的IO操作

使用场景:
同步阻塞(BIO):线程发起IO请求,不管内核是否准备好IO操作,线程一直阻塞,直到完成
同步非阻塞(NIO):一个请求一个线程
异步非阻塞(AIO):一个有效请求一个线程

相关文章