Java教程

1、Java基础面试题

本文主要是介绍1、Java基础面试题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. Java语言特点

1、简单易学

2、面向对象(封装,继承,多态)

3、平台无关性(Java虚拟机实现)

4、支持多线程

5、可靠性

6、安全性

7、支持网络编程并且方便

8、编译与解释并存

2. JVM & JDK & JRE

JVM:Java 虚拟机是运行 Java 字节码的虚拟机,有针对不同系统的特定实现。并不止一种!只要满足 JVM 规范,都可以开发自己的专属 JVM。

JDK:Java Development Kit,是功能齐全的 Java SDK。拥有 JRE 所拥有的的一切,还有 javac (编译器)和 javadoc、jdb(工具),能够创建和编译程序。
    
JRE:Java 运行时环境,运行 已编译 的Java程序所需内容的集合,包括JVM,Java 类库,java 命令和其他的一些基础构建。但是,不能用于创建新程序。

3. 字节码

字节码:「.class 」文件,JVM 可以理解的代码,不面向任何特定的处理器,只面向虚拟机。
    
一定程度上解决了传统解释型语言执行效率低的问题,又保留了可移植的特点。
    
无须重新编译便可在多种不同操作系统的计算机上运行

4. Java 和 C++的区别

Java 不提供指针来直接访问内存,程序内存更加安全

Java 的类是单继承的(但接口可以多继承),C++ 支持多重继承;

Java 有自动内存管理垃圾回收机制(GC),不需要程序员手动释放无用内存

C++ 同时支持 方法重载 和 操作符重载(增加了复杂性),但是 Java 只支持方法重载

5. Java 语言关键字

1、访问控制:private、protected、public

2、类,方法和变量修饰符:abstract、class、extends、final、implements、interface、native、new、static、strictfp、synchronized、transient、volatile、enum

3、程序控制:break、continue、return、do、while、if、else、for、instanceof、switch、case、default、assert

4、错误处理:try、catch、throw、throws、finally

5、包相关:import、package

6、基本类型:boolean、byte、char、double、float、int、long、short

7、变量引用:super、this、void

8、保留字:goto、const
    
所有关键字都是 小写 的
    
default 很特殊,既属于程序控制,也属于类,方法和变量修饰符,还属于访问控制
 
注意:true、false、null 实际是字面值,同时,不可以作为标识符来使用。

6. 基本数据类型

默认值及所占空间大小如下

image

8种基本数据类型
  
  6种数据类型
  	4种整数型:byte(Byte)、short(Short)、int(Integer)、long(Long)
  
  	2种浮点型:float(Float)、double(Double)
  
  1种字符类型:char(Character)
  
  1种布尔型:boolean(Boolean)
  
Java 的每种基本类型所占存储空间的大小不会随机器硬件架构的变化而变化,是比其他语言编写的程序更具可移植性的原因之一
  
注意:
1、long 类型一定要在数值后面加上 L ,否则将作为整型解析
  
2、char 单引号 '',String 双引号 ""

7. 字符型常量和字符串常量的区别

1、形式:字符常量是 「单引号」引起的一个字符,字符串常量是「双引号」引起来的0个或若干个字符
  
2、含义:字符常量相当于一个整型值(ASCII 值)可以参加表达式运算;字符串常量代表一个 地址值(该字符串在内存中存放的位置)
  
3、占内存大小:字符常量占 2 个字节,字符串常量占若干个字节

8. 基本类型和包装类型的区别

包装类型不赋值就是 null,基本类型有默认值且不是 null
  
包装类型可用于泛型,而基本类型不可以
  
基本数据类型的 「局部变量」 存放在 Java 虚拟机 『栈』中的局部变量表中,基本数据类型的 「成员变量」(未被 static 修饰)存放在 Java虚拟机的 『堆』 中。

包装类型属于 对象类型,几乎所有对象实例都存放在 堆 中。
  
相比于对象类型,基本数据类型占用的空间非常小

9. 包装类型的缓存机制

Byte、Short、Integer、Long :默认创建数值[-128,127]的相应类型的缓存数据

Character:创建了数值在[0,127]范围的缓存数据
  
Boolean:直接返回 True 或 False
  
Float、Double:并没有实现缓存机制
  
如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡
  
记住:所有整型包装类对象之间「值」的比较,全部使用 『equals』方法比较。

10. 自动装箱与拆箱

装箱:将基本类型用它们对应的引用类型包装起来(调用包装类的 「valueOf()」方法)

拆箱:将包装类型转换为基本数据类型(调用「xxxValue()」方法)
  
注意:如果频繁拆装箱,也会严重影响系统的性能,尽量避免不必要的拆装箱操作

11. 自增自减运算符

++ 和 --

前缀:先自增/减,再赋值

后缀:先赋值,再自增/减

12. continue、break、return的区别

continue:指跳出当前的 「这一次」循环,继续下一次循环
  
break:指跳出「整个」循环体,继续执行循环下面的语句
  
return:用于跳出所在的方法,结束该方法的执行
  return; 用于没有返回值函数的方法
  
  return value; 用于有返回值函数的方法

13. 方法

方法的返回值:是指获取到的某个方法体中的代码执行后产生的结果。返回值的作用是接收出结果,使得它可以用于其他操作
  
1、无参数无返回值

2、有参数无返回值
  
3、有返回值无参数
  
4、有返回值有参数
  
静态方法:属于类,在类加载的时候就会分配内存,可以通过「类名」直接访问。在访问本类的成员时,只允许访问静态成员(变量和方法),不允许访问实例成员(实例成员变量和实例方法),实例方法不存在限制
 
非静态成员,属于实例对象,只有在对象实例化之后才存在,通过类的实例对象去访问

14. 重载和重写的区别

image

1、重载:同样的一个方法能够根据输入数据的不同,做出不同的处理。
  
  			发生在「同一个类中」(或者父类和子类之间),「方法名必须相同」,参数类型不同、个数不同、书序不同、返回值和访问修饰符可以不同
  
  			同一个类中「多个同名方法」根据『不同的传参』来执行不同的逻辑处理
  
2、重写:当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,就要覆盖父类方法
  
  			发生在「运行期」,是子类对父类的允许访问的方法的实现过程进行重新编写,「方法名、参数列表」必须相同,子类返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类
  	
  			子类对父类方法的重新改造,外部样子不能改变,「内部逻辑」可以改变
  
  			如果方法的返回类型是void和基本数据类型,则返回值重写时不可修改
  
  			如果方法的返回值是引用类型,重写时是可以返回该引用类型的子类的
  
3、Java 允许重载任何方法,而不只是构造器方法,构造方法无法被重写

15. 可变参数

Java5 开始,支持定义可变长参数「 String... args」,就是允许在调用方法时传入不定长度的参数

可变参数只能作为函数的最后一个函数,前面可以有也可以没有任何其他参数
  
遇到方法重载时,会优先匹配固定参数的方法,因为匹配度更高
  
编译后实际会转换成一个数组

16. 成员变量与局部变量

成员变量 局部变量
语法形式 属于类 在代码块、方法中定义的变量、方法的参数
存储方式 static修饰,属于类;没有则是属于实例。对象存在于堆内存 存在于栈内存
生存时间 是对象的一部分,随对象的创建而存在 局部变量随着方法的调用而自动生成,调用结束消亡
默认值 如果没有被赋初始值,则自动以类型的默认值赋值。final修饰的例外,必须显式赋值 不会自动赋值

17. 创建一个对象用什么运算符?对象实体与对象引用的不同

new 运算符,创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)

一个对象引用可以指向0个或1个对象
  
一个对象可以有n个引用指向它

18. 对象的相等和引用相等的区别

对象的相等一般比较 内存中存放的内容是否相等
  
引用相等一般比较 它们指向的内存地址是否相等

19. 类的构造方法的作用是什么

构造方法是一种特殊的方法,主要作用是完成 对象 的初始化工作

20. 如果一个类没有声明构造方法,该程序能正确执行吗?

可以执行,即使没有声明构造方法也会有默认的不带参数的构造方法

如果自己添加了类的构造方法(无论是否有参),Java就不会再添加默认的无参数的构造方法了
  
在创建对象的时候后面要加一个括号,因为要调用无参的构造方法
  
注意:重载了有参的构造方法,记得都要把无参的构造方法也写出来(无论是否用到),可以帮助我们在创建对象的时候少踩坑

21. 构造方法特点,能否被override

名字和类名相同

没有返回值,但不能用 void 声明
  
生成类的对象时自动执行,无需调用
  
构造方法不能被 override(重写),但可以 overlord(重载),可以看到一个类中有多个构造函数

22. 面向对象三大特征

1、封装:把一个对象的状态信息(属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。

2、继承:是使用已存在的 类的定义 作为基础建立新类的技术,可以增加新的数据或新的功能,也可以用父类的功能,但不能 选择性 地继承父类
  
  子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有
  
  子类可以拥有自己属性和方法,即子类可以对父类进行扩展
  
  子类可以用自己的方法实现父类的方法
  
3、多态:一个对象具有多种状态,具体表现为父类的引用指向子类的实例
  
  对象类型和引用类型之间具有 继承(类)/实现(接口)的关系
  
  引用类型变量发出方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定
  
  多态不能调用“只在子类存在但在父类不存在”的方法
  
  如果子类重写了父类的方法,真正执行的是子类覆盖的方法。没有覆盖,执行的是父类的
  

23. 接口和抽象类

1、共同点:
  
  不能被 实例化
  
  可以包含 抽象方法
  
  可以有默认实现的方法(Java8可以用 default 关键字在接口中定义默认方法)
  
2、区别:
  
  接口主要对 类 的行为约束,实现了某个接口 就具有了对应的行为
  
  抽象类主要用于代码复用,强调是所属关系
  
  一个类只能继承一个类,但是可以实现多个接口
  
  接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值
  
  抽象类的成员变量默认 default 可在子类中被重新定义,重新赋值

24. 深拷贝和浅拷贝区别,引用拷贝

浅拷贝:在堆上创建一个新的对象(区别于引用拷贝),如果原对象内部的属性是「引用类型」,会直接赋值内部对象的引用地址。拷贝对象和原对象共用同一个内部对象
  
深拷贝:完全赋值整个对象,包括这个对象所包含的内部对象
  
引用拷贝:两个不同的引用指向同一个对象
image image

25. Java 常见类

Object 类是所有类的父类,主要提供以下11个方法
  
public final native Class<?> getClass()//native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。

public native int hashCode()//native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。

public boolean equals(Object obj)//用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。

protected native Object clone() throws CloneNotSupportedException//naitive 方法,用于创建并返回当前对象的一份拷贝。

public String toString()//返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。

public final native void notify()//native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。

public final native void notifyAll()//native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。

public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。

public final void wait(long timeout, int nanos) throws InterruptedException//多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。

public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念

protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作

26. == 和 equals() 区别

1、== :对于基本数据类型来说,比较的是「值」;对于引用数据类型,比较的是 对象的「内存地址」
  
2、equals():不能判断基本数据类型的变量,只能用来判断『两个对象』是否相等。所有类都有 equals() 方法
  
  类没有重写:比较该类的两个对象时,等价于 ==
  重写了:比较两个对象中的属性是否相等

3、当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中创建一个 String 对象

27. hashCode()

作用是获取哈希码(int 整数),也称为散列码。作用是确定该对象在哈希表中的索引位置
  
任何类都包含,是本地方法,就是用C或C++实现,该方法通常用来讲对象的内存地址转换为整数之后返回
  
散列表存储的是键值对,快速找到所需要的对象

28. 为什么两个对象有相同的 hashCode 值,也不一定是相等

hashCode() 所使用的哈希算法也许刚好让多个对象传回相同的哈希值,越糟糕的哈希算法越容易碰撞,但这也与数据值域分布的特性有关
  
两个对象 hashCode 值相等,两个对象不一定相等(哈希碰撞)
  
hashCode 值相等 并且 equals() 方法也返回true,才认为这两个对象相等
  
hashCode 值不相等,直接认为不相等

29. String、StringBuffer、StringBuilder的区别

String StringBuffer StringBuilder
可变性 不可变 字符串变量 继承自 AbstractStringBuilder 类,使用 字符数组 保存字符串,没有使用final和private修饰,还提供了很多修改字符串的方法 字符串变量 同左
线程安全性 可以理解为常量,线程安全 对方法加了 同步锁 或者对调用的方法加了同步锁,线程安全 非线程安全
性能 进行改变都会生成新的 String 对象,然后指向新的 对象 对本身进行操作 相比StringBuffer仅能获得10%~15%左右的性能提升,却要冒多线程不安全的风险
String :操作少量数据

StringBuilder :单线程操作字符串缓冲区下操作大量数据
  
StringBuffer :多线程操作字符串缓冲区下操作大量数据

30. String 为什么是不可变

String 类中使用 final 关键字 修饰字符数组来保存字符串,不是不可变的根本原因,因为这个数组保存的字符串是可变的

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];
	//...
}

final 关键字修饰的

  类不能被继承
  
  方法不能被重写
  
  基本数据类型不能改变值
  
  引用类型不能再指向其他对象
  
1、保存字符串的数组被 final 修饰且为私有的,并且 String 类没有提供/暴露修改这个字符串的方法
  
2、String 类被 final 修饰导致其不能被继承,避免了子类破坏可变性

31. Java 9 为何要将 String 的底层实现 由 char[] 改成了 byte[]

新版 String 支持两个编码方案:Latin-1 和 UTF-16
  
字符串包含的汉字没有超过Latin-1,就是用此编码方案。byte 占一个字节(8位),char占用2个字节(16位),节省了一半的内存空间
  
包含的汉字超过 Latin-1 可表示范围内的字符,byte 和 char 所占用的空间是一样的

32. 字符串拼接用“+”还是 StringBuilder

Java 语言本身并不支持运算符重载,"+"和"+="是专门为 String 类重载过的运算符,也是Java中仅有的两个重载过的元素符
  
"+" 实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象

在循环内使用 "+" 进行字符串的拼接,存在比较明显缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象

直接使用 StringBuilder 对象进行字符串拼接,就不会存在问题

33. 字符串常量池的作用

字符串常量池:是JVM为了提升性能和减少内存消耗,针对字符串(String类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建
  
String s1 = new String("abc");这句话创建了几个字符串对象?
  
  如果字符串常量池中不存在字符串对象“abc”的引用,那么会在堆中创建 2 个字符串对象“abc”。
  
  如果字符串常量池中已存在字符串对象“abc”的引用,则只会在堆中创建 1 个字符串对象“abc”。
  
ldc 命令用于判断字符串常量池中是否保存了对应的字符串对象的引用,如果保存了的话直接返回,如果没有保存的话,会在堆中创建对应的字符串对象并将该字符串对象的引用保存到字符串常量池中。

34.intern 方法有什么作用

String.intern() 是一个 native(本地)方法,其作用是将指定的字符串对象的「引用」保存在『字符串常量池』中
  
保存了对应的字符串对象的引用,直接返回该引用
 
没有保存,那就再常量池中创建一个指向该字符串对象的引用并返回
  
String s1 = "Java"; // 在堆中创建字符串对象"Java",将字符串对象"Java"的引用保存在字符串常量池中
String s2 = s1.intern();
String s4 = s3.intern();
String s3 = new String("Java")// 会在堆中在单独创建一个字符串对象;

s1 == s2 == s4 != s3

35. String 类型的变量和常量做 “+”运算时发生了什么?

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";//常量池中的对象
String str4 = str1 + str2;//在堆上创建的新的对象
String str4 = new StringBuilder().append(str1).append(str2).toString();//对象引用和"+"的拼接方式,实际是此
String str5 = "string";//常量池中的对象

s3 == s5 != s4
  
对于编译期 可以确定值的字符串,即常量字符串,jvm 会将其存入字符串常量池。常量字符串拼接得到的字符串常量,在编译阶段就已经被存放在字符串常量池,得益于编译器的优化。
  
在编译过程中,Javac 编译器会进行 常量折叠(Constant Folding)的代码优化
  
常量折叠:会把 常量表达式 的值 求出来作为 常量嵌在最终生成的代码中,是Javac 编译器会对源代码做的极少量优化措施之一(代码优化几乎都在「即时编译器」中进行)
  
只有编译器在 程序编译期 就可以 确定的常量 才可以:
  
1、基本数据类型(byte、short、int、long、float、double、char、boolean)以及字符串常量

2、final 修饰的基本数据类型和 字符串变量(StringBuffer、StringBuilder)//字符串使用 final 关键字声明后,可以让编译期当做「常量」来处理;在『运行时』才能知道确切值的话,就无法对其优化,即使被final修饰
  
3、字符串通过 "+" 拼接得到的字符串、基本数据类型之间算数运算(加减乘除)、基本数据类型的位运算(<<、>>、>>>)
  
引用的值在程序编译期是无法确定的,编译期无法对其进行优化

36. 异常

image-20220427204823629

Java 异常类层次结构图概览

37. Throwable 类常用方法

String getMessage() :返回异常发生时的简要描述
  
String toString():返回异常发生时的详细信息
  
String getLocalizedMessage():返回异常对象的本地化信息。子类覆盖方法,可生成。未覆盖,则与getMessage() 返回结果相同

void printStackTrace():在控制台上打印 Throwable 对象封装的异常信息

38. Exception 和 Error 区别

Java 中,所有异常都有一个共同的祖先 java.lang 包中 Throwable 类
 
Exception:程序本身可以处理的异常,可以通过 catch 来进行捕获。分为受检查异常(Checked Exception),必须处理;不受检查异常(UnChecked Exception),可以不处理
  
Error:程序无法处理IDE错误,不建议通过 catch 获取。Java 虚拟机运行错误(Virtual MachineError0)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)。这些异常发生时,JVM 一般会选择线程终止

39. Checked Exception 和UnChecked Exception 区别

Checked Exception 受检查异常,在编译过程中,如果没有被 cathc/throw 处理的话,就没办法通过编译
  
除了 RuntimeException 及其子类之外,其他的 Exception 类及其子类都属于受检查异常
  
UnChecked Exception 不受检查异常 不处理也可以正常通过编译
  
  NullPointerException(空指针错误)
  
  IllegalArgumentException(参数错误比如方法入参类型错误)
  
  NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)
  
  ArrayIndexOutOfBoundException(数组越界错误)
  
  ClassCastException(类型转换错误)
  
  ArithmeticException(算术错误)
  
  SecurityException(安全错误比如权限不够)
  
  UnsupportedOperationException(不支持的操作错误比如重复创建同一用户)

40. try-catch-finally 如何使用

try 块:用于捕获异常,其后可接零个 或多个 catch 块,如果没有 catch块,则必须跟一个 finally 块
  
catch 块:用于处理try捕获到的异常

finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或catch块中遇到 return 语句时,finally 语句块将在方法返回之前被执行
  
注意:不要在 finally 语句块中使用 return ! try语句块中的return语句会被忽略。因为try语句中的return返回值会先被暂存在一个本地变量中,且本地变量的值就变为了 finally 语句中的return 返回值

41. finally 中的代码一定会执行吗?

不一定!
  
比如 finally 之前虚拟机被终止运行,其中代码就不会被执行
  
1、程序所在的线程死亡

2、关闭 CPU

42. 如何使用 try-with-resources 代替 try-catch-finally

1、适用范围(资源的定义):任何实现 java.lang.AutoCloseable 或者 java.io.Closeable 的对象
  
2、关闭资源和 finally 块的执行顺序:在 try-with-resources 语句中,任何catch 或 finally 块在声明的资源关闭后运行
  
面对必须要关闭的资源,总是应该优先使用 try-with-resources 而不是 try-finally。随之产生的代码更简短,更清晰,产生的异常对我们也更有用
  
Java中类似 InputStream、OutputStream、Scanner、PrintWriter等资源都需要我们调用 close() 方法来手动关闭,一般情况下都是通过 try-catch-finally 语句来实现这个需求
  
当多个资源需要关闭的时候,使用 try-with-resources 实现起来也非常简单,通过分号分隔,声明多个资源
  
try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
     BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
    int b;
    while ((b = bin.read()) != -1) {
        bout.write(b);
    }
}
catch (IOException e) {
    e.printStackTrace();
}

43. 异常使用有哪些需要注意的地方

1、不要把异常定义为 静态变量,会导致异常栈信息错乱。每次手动抛出异常,都需要手动 new 一个异常对象抛出

2、抛出的异常信息一定要有意义
  
3、建议抛出更具体的异常,比如字符串转换为数字格式错误的时候应该抛出 NumberFormatException 而不是其父类 IllegalArgumentException
  
4、使用日志打印异常之后就不要再抛出异常了(两者不要同时存在一段代码逻辑中)

44. 泛型

Java 泛型(Generics) 增强代码的可读性以及稳定性

编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法

静态泛型方法:public static < E > void printArray( E[] inputArray )

在Java中泛型只是一个占位符,必须在传递类型后才能使用。类在实例化时才能真正的传递类型参数。
由于静态方法的加载先于类的实例化,所以是没有办法使用类上声明的泛型。只能使用自己声明的 <E>

45. 项目中哪里用到了泛型

自定义接口通用返回结果 CommonResult<T> 通过参数 T 可根据具体的返回类型动态指定结果的数据类型

定义 Excel 处理类 ExcelUtil<T> 用于动态指定 导出的数据类型

构建集合工具类(参考 Collections 中的 sort,binarySearch 方法)

46. 反射

通过反射可以获取任意一个类的所有属性和方法,还可以调用

优点:可以让代码更加灵活、为各种框架提供开箱即用的功能提供了便利2
缺点:运行时有了分析操作类的能力,同样也增加了安全问题。比如:无视泛型参数的安全检查(编译时)。性能也要稍微差点,不过对框架实际影响不大。

应用场景:框架、注解

动态代理的实现也依赖反射,使用反射类 Method 来调用指定的方法

47. 注解

Annotation(注解),可以看做是一种特殊注释,主要用于修饰类、方法和变量

本质是一个继承了 Annotation 的特殊接口

注解只有被解析之后才会生效,常见有两种:

编译器直接扫描:编译器在编译 java 代码的时候扫描对应的注解并处理

运行期通过反射处理:

48. I/O

image-20220507234015107

序列化:将数据结构或对象转换成二进制字节流的过程

反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程

序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中

49. Java 序列化中如果有些字段不想进行序列化,怎么办

使用 transient 关键字修饰
  
作用:阻止实例中那些用此关键字修饰的变量序列化,不会被持久化和恢复
  
只能修饰变量,不能修饰类和方法
在反序列化后,变量值将会被置成类型的默认值
static 变量 不属于任何对象,无论有没有 transient ,均不会被序列化
  
Scanner
  Scanner input = new Scanner(System.in);
String s  = input.nextLine();
input.close();

BufferedReader
  BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();

50. IO流分为几种

IO-操作方式分类

IO-操作对象分类

流的流向:输入流和输出流

操作单元划分:字节流和字符流

流的角色:节点流和处理流
  
InputStream/Reader:所有输入流的基类,字节输入流/字符输入流
  
OutputStream/Writer:宿友输出流的基类,字节输出流/字符输出流
  
不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,为什么还要分成字节流和字符流?
  
  字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且如果不知道编码类型就很容易出现乱码问题
  
  音频文件、图片等媒体文件用字节流,涉及字符用字符流
这篇关于1、Java基础面试题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!