1.java中的序列化和反序列化是什么?
java的序列化是指将对象转化为字节流,主要是为了便于网络传输、持久化存储或者缓存。
java的反序列化是指将字节流转化为对象的过程,即从存储读取数据并重新创建对象。
java提供了java.io.Serializable接口来支持序列化。
serialVersionUID的作用是什么:验证作用
用来验证序列化对象的ID与反序列化对应的对象的ID是否相同
2.什么是java中的不可变类
关键特征:
1.声明类为final,不能被子类继承
2.类中所有的字段都是被private final修饰,确保它们在初始化之后不能被修改
3.通过构造函数初始化所有字段。
4.不提供任何修改对象状态的方法。
常见的不可变类有String、Integer等。
不可变类的优缺点:
优点:
1.线程安全:在并发环境下不需要考虑同步问题。
2.缓存友好:可以安全地被缓存和共享
缺点:
1.性能问题:在每次状态更新时都需要new一个对象。(例如String拼接)
3.java中Exception和Error的区别
Exception和Error都是Throwable的子类
Exception通常是可以通过程序去捕获的,例如使用try-catch代码块去捕获
Exception分为编译时异常和运行时异常,常见的编译时异常有:IOException。
常见的运行时异常有:NullPointerException、IllegalArgumentException等
Error通常是jvm系统级的异常,无法通过程序去捕获
常见的Error有OutOfMemoryError、StackOverflowError等
4.java的优势是什么?
1.面向对象
面向对象的三大特性:封装、继承、多态
2.自动垃圾回收机制
将内存交由GC管理,减轻程序员的负担
3.丰富生态
丰富第三方类库、网上全面资料、企业级的框架等
4.跨平台
Write once,Run anywhere 通过jvm实现
5.java是按值传递还是按引用传递?
在java中,参数都是按值传递,无论是基本类型还是引用类型
1.基本数据类型:传递的是基本类型的数值本身。
基本数据类型:
byte、short、int、long、float、double、char、boolean
2.引用数据类型:传递的是对象引用的内存地址。
6.为什么java不支持多重继承?
主要是java之父吸取C++教训,因为会产生菱形继承
为接口可以多实现?
因为接口当中无具体实现,必须要在子类实现方法(jdk8之前)
后面出现了default方法,如果接口有多个相同的默认方法,必须要在子类重写这个方法。
7.面向过程和面向对象的区别
面向对象编程:以类和对象作为基本单元来组织代码。关注对象之间的关系与交互
面向过程编程:以过程或函数作为基本单元来组织代码。关注执行的步骤和顺序
优缺点:
面向对象的优缺点:
优点:代码复用性、扩展性高,适合大型项目。
缺点:开发和理解成本高。
面向过程的优缺点:
优点:开发简单,适合小型项目。
缺点:代码复用性、扩展性差。
8.面向对象的三大特性
封装:将数据和行为封装在对象的内部,提供接口进行访问,隐藏实现细节,提高安全性。
继承:子类通过继承父类的属性和方法,实现代码的复用和扩展。
多态:对象可以通过父类或接口实现多态性调用,不同的对象在运行时可以展现不同的行为。
9.方法重载和方法重写有什么区别?
两者都是面向对象中多态特性的体现
方法重载:
在一个类中允许有多个同名方法,只要它们的参数列表不同(参数的个数、类型、顺序)
方法重写:
子类在继承父类或接口,对父类或接口中的方法的实现
注意点:
在重写时,子类重写的方法的访问等级不能比父类更加严格
10.java的内部类是什么?有什么用?
java内部类是指在一个类中定义的类。内部类可以访问外部类的成员变量和方法,甚至私有的成员。
java内部类有:
1.成员内部类
可以访问外部类的所有成员,包括私有成员
2.匿名内部类
没有类名的内部类
3.静态内部类
只能访问外部类的静态成员
4.局部内部类
定义在方法和代码块中的内部类
11.jdk8有哪些新特性
1.引入lambda表达式
2.引入接口的默认方法
3.引入Stream流式接口
4.元空间取代了永久代
5.修改了HashMap和ConcurrentHashMap的实现
12.String、StringBuffer、StringBuilder的区别
13.java中包装类型和基本类型的区别
基本类型:它们是直接存储数据的变量,存储在栈上,性能相对较高,不支持null。
包装类型:包装类型是类,存储在堆上,性能相对较差(涉及内存分配和垃圾回收),支持null。
14.接口和抽象类的区别
设计思想:
接口它是自上而下设计的。
抽象类是自下而上设计的,往往都是同一些类共同特点抽象出来的。
方法实现:
接口的方法默认是public abstract修饰的。
抽象类可以包含abstract方法和具体方法。
构造函数:
接口没有构造函数,成员变量都是public static final修饰的
抽象类有构造函数,成员变量可以有不同的修饰符
继承:
接口可以多继承
抽象类只能单继承
15.JDK和JRE的区别
JRE:是java的运行环境,包含jvm、核心类库和其他支持运行java程序的文件。
jvm:执行java的字节码,提供java运行环境。
JDK:是JRE的超集,即完整的java运行环境,包含了JRE、以及用于开发、调试和监控java应用程序的工具。
开发工具:如编译器(javac)、调试器(jdb)、打包工具(jar)等
16.JDK提供的工具
javac:java编译器,将java源代码编译成字节码
java:运行java应用程序的命令,使用jvm来解释并执行编译后的字节码文件
jdb:java调试工具,用于在命令行中调试java应用程序
jar:java打包工具
javadoc:生成API文档的工具
17.equals方法、==、hashCode方法
hashcode:用于散列存储结构中确定对象的位置。可用于快速比较两个对象的是否相同,如果两个对象的哈希值不相同,那么这两个对象肯定不相同。
equals:默认实现就是==,比较两者的内存地址是否相同
通常需要我们自己在自定义类中去重写这个方法,以基于对象属性进行内容的比较
==:基本数据类型比较的是值,引用类型比较的是两者的内存地址是否相同
18.什么是java的动态代理
java的动态代理是指在程序运行时创建代理对象的机制。动态代理允许程序在运行决定代理对象的行为,而不需要像静态代理那样在编译时确定。
主要用途:
1.简化代码:通过代理可以减少重复代码,尤其是在横切关注点(如日志记录,事务管理,权限控制等)方面。
2.实现AOP:是AOP的基础,可以在方法调用的前后插入额外的逻辑。
3.增强灵活性:因为代理对象是在运行是生成的,可以动态地改变行为。
19.动态代理与CGLIB的区别
动态代理是基于接口实现的,所以要求一定是有定义接口的。
CGLIB是基于ASM字节码生成工具,它是通过继承的方式生成目标类的子类来实现代理类,所以要注意final方法。
20.java中注解原理是什么?
注解其实就是一个标记,是一种提供元数据的机制,用于给代码添加说明信息。可以标记在类上、方法上、属性上等。注解本身不影响程序运行,但是可以通过工具,或者框架对这些信息进行特殊处理,如代码生成,运行时处理。
21.反射机制
可以在程序运行时获取类的结构信息(如方法、字段、构造函数)并操作对象的一种机制。反射机制提供了在运行时动态船舰对象、调用方法、访问字段等功能,而无需在编译时知道这些类的具体信息。
22.SPI
SPI是一种插件机制,用于在程序运行时动态地加载某些功能的实现。
理解版:
API:我去水果店买水果,说“我要一盒苹果”,店员给我一盒已经包装好的苹果
SPI:我给店员一个具体的包装方式(比如“用红色盒子,每盒装5个”),店员按照我的要求来包装水果。
23.泛型
类型安全:将运行时异常转编译时异常
代码重用:不用为一个类型创建一个集合,而是可以使用多种不同类型。
消除显示类型转换:类型擦除帮我们转换好了
24.泛型擦除
定义:泛型擦除是指在编译时将泛型信息进行擦除,使原本数据类型转为object类。
作用:提高了对象的向后兼容性。
影响:在程序运行时不能获取原本对象数据类型。
25.浅拷贝与深拷贝区别
浅拷贝:浅拷贝创建一个新对象,但是它的字段指向的是原对象相同的内存地址。
深拷贝:深拷贝不仅复制对象本身,还递归复制对象所有的引用。新对象与原对象是完全独立互不影响的。
26.Integer的缓存池
在-128和127范围内的Integer对象会被缓存和复用。
原理:
java在自动装箱时,对于值在-127到128范围内的int类型,会直接返回一个已经缓存的Integer对象,而不是创建新的对象。
27.java的类加载过程
三个阶段
1.加载:通过类加载器将类文件加载到内存中,生成一个Class对象
类加载器:是jvm中用于动态加载类文件的组件。它将.class文件中的字节码加载到内存中,并将其转化Class对象,以供jvm执行。
jdk8时的三种类加载器:
1.启动类加载器Bootstrap ClassLoader
2.扩展类加载器Extension ClassLoader
3.应用程序类加载器Application ClassLoader
双亲委派模型:类加载器会先把类加载请求交由父类加载器处理,只有父类加载器找不到类时,才由当前类加载器执行。
2.验证:确保加载的类信息符合jvm规范,没有安全问题。
3.准备:给类的静态变量分配内存,并设置默认初始值。
4.解析:jvm将常量池内的符号引用替换为直接引用。
5.初始化:执行类构造器方法。
28.BigDecimal
是java提供的一个高精度计算的不可变类,属于java.math包。
为什么能够保证精度:
因为使用了任意精度的整数表示法,而不是浮动的二进制表示。
29.使用new String语句会在java中创建多少个对象
会创建一个或两个对象
主要看字符串常量池中是否存在这个字符串对象的引用
29.final和finally
1.final:用于修饰类、方法和变量,主要用来设计不可变类、确保类的安全性、优化性能。
类:被final修饰的类不能被继承。
方法:不能被重写。
变量:不可重新赋值,常用于定义常量。
2.finally:与try-catch语句块结合使用,用于确保无论是否发生异常,finally代码块都会执行。
主要用于释放资源(如关闭文件、数据库连接等)。
30.如果一个线程在java中被两次调用start()方法,会发生什么?
会报错
一旦线程开始执行,它的状态不能回到初始状态。线程的生命周期不允许它从终止状态回到可运行状态。
31.java的访问修饰符有哪些?
public:可以被任何类访问。
protected:可以被同一个包的类访问,或者是子类。
默认:只能被同一个包的类访问。
private:内部可以访问,外部不可以。
32.静态方法和实例方法的区别
静态方法是用static修饰的,它是属于类的,而不属于实例,可以直接通过类名调用,可以访问静态变量和静态方法,不能直接访问实例变量和实例方法
33.for和for each的区别
for循环:适合用复杂操作,例如根据索引进行操作、反向遍历等。
for each:简单遍历,不需要访问索引。
34.sleep()和wait()方法的区别
1.sleep是属于Thread类的方法,释放cpu给其他线程,不释放锁资源。
2.wait是属于Object类的方法,释放cpu给其他线程,释放锁资源。
需要通过其他线程通过notify()和notifAll()唤醒
必须配合synchronized一起使用
35.BIO、NIO和AIO
BIO:调用操作时会被阻塞,直到操作完成后才继续执行。
NIO:调用操作后可以立即返回,即使操作未完成。
AIO:调用操作后,不需要等待操作完成。