Java基础
目录
三、Java 中 Exception 和 Error 有什么区别?
十一、Java 中 String、StringBuffer 和 StringBuilder 的区别是什么?
十六、Java 中 hashCode 和 equals 方法是什么?它们与 ==操作符有什么区别?
十七、Java 中的 hashCode 和 equals 方法之间有什么关系?
二十七、String s = new String("abc")会创建几个对象?
二十八、如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
一、java中的序列化和反序列化是什么?
思维导图
回答:
序列化就是将对象转换为字节流的过程,反序列话就是将字节流转换为对象的过程,也就是序列化的逆过程,主要应用在网路传输、远程调用、持久化存储和分布式系统数据交换当中。java要想实现对象的序列化需要实现Serializable接口,底层实现序列化是用到了ObjectOutputStream这个类,而反序列化则是用到了ObjectInputStream这个类。
serialVersionUID的作用是什么?
就是一个版本号的作用,来确保数据在序列化的过程中被修改而导致不一致的问题,在序列化的时候判断UID是否跟当前对象的UID一致,如果一致就说明当前对象没有被其他线程修改过,此时可以继续序列化,其本质就是一个乐观锁。
transient关键字有什么用?
这个关键字可以标记在不想被序列化的字段上,确保不被序列化。
二、什么是java的不可变类?
思维导图
回答:
不可变类就是创建后其状态,也就是对象的字段无法被修改的类。一般是通过final关键字去创建一个不可变类,最常见的例子就是String字符串,String被创建后其值不可变,假设有s+='a',也只是创建了一个新对象,并将s的引用指向了新对象,s的旧引用指向的老对象的值没有变化还是s。
不可变类主要有线程安全、缓存友好等优点,但是也有缺点例如性能问题,当执行了过多的字符串操作,可能会创建大量字符串对象,浪费内存空间。
三、Java 中 Exception 和 Error 有什么区别?
思维导图
回答:
从定义上来讲,Exception是指程序能够处理的异常情况,而Error则是JVM层次内系统级的错误,一般程序不能够处理。Exception和Error的共同之处就是都是Throwable类的子类,java代码只有继承了Throwable类的实例才能被throw或catch。
四、你觉得java的优势是什么?
思维导图
回答:
我觉得java的优势有跨平台性、垃圾回收、生态、面向对象四个优势。
其中跨平台性主要体现在,java代码被编译成字节码,然后被不同平台下的JVM编译成对应平台的机器码并交由对应平台执行,从而实现跨平台性,这也就是java“一次编译,到处运行”的原因。
java内部的JVM有内存回收机制,极大地减少了程序员内存管理的成本。
java有丰富的第三方类库和成熟的开发框架以及各种中间件。
java还是一种面向对象的语法,其封装继承多态的特性也使得java可扩展性强。
五、什么是java的多态特性?
思维导图
回答
多态的定义是:同一个接口或父类引用变量可以指向不同的对象实例,并根据实际指向的对象类型执行相应的方法。
多态还分为编译时多态和运行时多态,编译时多态主要体现为方法重载,方法重载就是同一个类中可以定义多个同名方法,但参数列表不同,java编译器会根据传入的参数来决定调用哪一个方法。
运行时多态体现为方法重写,方法重写就是子类重写父类中的一个或多个方法。通过父类引用调用方法时,实际上执行的是子类重写后的方法。
六、java中的参数传递是按值还是按引用?
java中的参数传递都是值传递,其中基本数据类型传递的是值,引用数据类型传递的是地址值。
七、为什么java不支持多重继承?
因为不想走C++的老路,C++支持多重继承,这就导致在继承过程中可能会出现歧义的情况,具体如下:
D继承B和C(多重继承),B和C共同继承A,A的方法在B和C中都得到重写,在D想调用A中方法时,因为B和C都有不同的实现,此时就会出现歧义,不知道应该调用哪个了。
八、面向对象编程和面向过程有什么区别?
面向对象是以对象作为编程指导或中心,通过对象间的交互操作来实现具体的功能,最直观的表现就是封装继承多态,数据和行为封装在一个对象中。
面向过程就是以函数作为编程指导或中心,通过函数间的调用来实现具体的功能,数据和行为是分开的。
面向对象更加模块规范化,且扩展性强,但是开发难度高,适合大型项目。
面向过程更加直接,但扩展性弱,维护成本高,不易协作,适合小型项目快速开发。
九、Java 方法重载和方法重写之间的区别是什么?
首先方法重载就是在同一个类中允许有多个重名方法,但是参数列表不同(个数、顺序、类型),通过传进来的参数来调用对应的方法。而方法重写就是字类去重写父类的方法,为该方法提供新的实现或扩展。
方法重载的参数列表,返回类型都可以不一样,但是方法重写的参数列表和返回类型都必须和父类的保持一致。而且子类方法的访问修饰不能比父类更严格且不能抛出比父类更多的异常,也就是子类要一直生活在父类的阴影下。
十、什么是java内部类?
内部类是指在一个类的内部定义的类。 成员内部类:可以访问外部类的所有成员 静态内部类:可以访问外部类的静态成员 局部内部类:定义在方法或代码块中,仅在代码块或方法中可见,通常用于临时的对象构建 匿名内部类:没有类名的内部类,通常用于创建短期使用的对象实例,尤其是在接口回调或者事件处理时被广泛使用。
十一、Java 中 String、StringBuffer 和 StringBuilder 的区别是什么?
线程安全:String、StringBuffer 线程不安全:StringBuilder
String是不可变类,底层用final修饰,每次对String进行修改的时候,会生成新的副本,从而占用更多的资源,频繁大量的修改,会造成资源的浪费
StringBuffer为了解决String的可能造成资源浪费问题,底层使用char,新增了append方法来修改字符串,同时各个修改方法加上了sychronized同步锁,所以它是线程安全的,但是需要消耗一定的性能作为代价
StringBuilder是在StringBuffer的基础上,将同步锁给去除掉了,舍弃了线程安全但换来了更高的性能
使用场景: 1、String:适用与少量的修改 2、StringBuffer:修改频率很高,需要保证线程安全的情况下使用 3、StringBuilder:修改频率很高,不需要保证线程安全 细节:由于StringBuffer和StringBuilder底层是数组实现,所以会涉及到扩容的机制,如果在使用时知道大概的数据量,在创建实例时可以给其赋予初始大小,减少扩容次数,提高性能
十二、java的Stringbuilder是怎么实现的?
StringBuilder
内部有一个字符数组,这个数组用来存储字符串。当你开始拼接字符串时,StringBuilder
会先检查这个内部数组是否有足够的空间来存放新的字符串。如果内部数组空间不够,StringBuilder
会自动进行扩容。它会创建一个新的更大的数组,并将旧数组的内容复制到新数组中,然后再加上新的字符串。这个过程叫做动态扩容。
十三、Java 中包装类型和基本类型的区别是什么?
1.基本数据类型占用的内存小,效率高,包装数据类型占用的内存大 2.基本数据类型的默认值为0,false,包装数据类型的默认为null 3.基本数据类型如果是局部变量存放在栈中,如果是成员变量存放在堆中,包装数据类型存放在堆中 4.包装数据类型可以用于泛型,基本数据类型不可以用于泛型 5.基本数据类型直接赋值,包装数据类型需要通过new对象 6.基本数据类型使用==比较值,包装数据类型使用==比较内存地址,使用重写后的equals比较值
十四、接口和抽象类有什么区别?
接口是协议,调用方无需关心实现细节,实现方维护底层实现,在实现发生变更时,调用方无需感知; 抽象类是模版,即一些类共有的部分可以抽象出来,提高代码复用,便于子类扩展。
十五、JDK和JRE有什么区别?
1.JDK =JRE +开发工具集(例如 Javac,java 编译工具等
-
JRE = JVM + Java SE 标准类库(java 核心类库)
3.如果只想运行开发好的 .class 文件 只需要 JRE
十六、Java 中 hashCode 和 equals 方法是什么?它们与 ==操作符有什么区别?
hashCode: 快速比较两个对象是否相同,hash码不同,肯定不相等。但是hash码相同,也不一定相等。 equals方法:比较两个对象的内容是否相等。通常需要自己实现对象的比较逻辑。 ==:如果是引用,比较的是内存地址:如果是基本数据类型,比较的是值。
十七、Java 中的 hashCode 和 equals 方法之间有什么关系?
这两者的关系主要体现在HashMap和HashSet中,HashMap和HashSet底层都是有数组作为数据结构的,所以在查询的时候会先用hashCode方法去计算获得key的唯一hash值,也就是这个key在数组中所在的位置,然后在这个位置中去使用equals方法去比较具体的属性值是否一致。所以说两个对象的equals()相等,那么他们的hashCode()也必须相等,那是因为hashCode()如果不相等就会导致hashMap和HashSet中存在相同的key值,这显然不符合定义。
十八、什么是java中的动态代理?
动态代理是一种在运行时生成代理对象的机制,允许在不修改原始类的情况下,为其方法调用添加额外的行为。 AOP(面向切面编程)是动态代理的一个实际应用,它通过代理为核心业务逻辑添加横切关注点(如日志、事务等)。 在 Java 中,Spring AOP 可以基于 JDK 动态代理或 CGLIB 动态代理来实现。 简单来说,AOP 通过动态代理来实现面向切面的编程。
十九、JDK 动态代理和 CGLIB 动态代理有什么区别?
JDK动态代理:基于Java反射,只能代理实现了接口的类。首先通过InvocationHandler接口得到一个切面类,然后利用Proxy根据目标类的类加载器、接口和切面类得到一个代理类。
CGLIB代理:基于字节码技术,可以代理所有对象。首先通过Methodlnterceptor接口得到一个拦截类,new一个enhancer,传入需要代理的类,创建callback方法并设置拦截类,再使用enhancer.create()方法返回一个代理类,同时这个代理类和方法不能被final修饰。
二十、java的注解原理是什么?
注解就是一个标记,是给机器看的,就是在类或者方法或属性中设置一些标记,注解本身不影响代码执行,相当于标记一些元数据,注解一些代码,可以生命文档也可以作为切面增强。
其中@Retention可以说明注解的有效访问,source、class、runtime
@Target可以说明注解应用元素,field、method等。
二十一、你使用过java的反射机制吗?如何应用反射?
Java 的反射机制是指在运行时获取类的结构信息(如方法、字段、构造函数)并操作对象的一种机制。
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性。
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。其本质是JVM得到Class对象之后,再通过Class对象进行反编译,从而获取对象的各种信息。
java反射的优点:
可以动态地获取类的信息,不需要在编译时就知道类的信息。 可以动态地创建对象,不需要在编译时就知道对象的类型。 可以动态地调用对象的属性和方法,在运行时动态地改变对象的行为。
应用场景有:
spring就是使用反射机制来读取配置文件,实现依赖注入和aop。
二十二、什么是泛型?泛型的作用是什么?
泛型允许类、接口和方法在定义时使用一个或多个类型参数,这些类型参数在使用时可以被指定为具体的类型。
类型安全:运行时异常转为编译时异常,提早发现异常,确保类型安全 代码重用:方法或者类,可以使用泛型,使方法和类能够处理多种不同的数据类型。而不用每个数据类型都写一个方法或者类。
二十三、java的泛型擦除是什么?
java的泛型擦除是指java编译器在编译过程中将所有的泛型信息删除的过程,这样做的目的是为了保证java版本的兼容性,因为在java5之前一些集合比如ArrayList和LinkedList都是非泛型化的,java5之后这两个集合都是泛型化的,为了保证这两个java版本的兼容性,就有这个泛型擦除。
会在编译的时候将<E>替换成Object,并通过插入类型转换指令保持类型安全和多态性。
二十四、Java 中的深拷贝和浅拷贝有什么区别?
深拷贝:不仅拷贝对象本身和基本类型成员变量,堆内的引用对象也会复制一份(相互独立不干扰) 浅拷贝:仅拷贝对象本身和基本类型成员变量,共享堆内的引用对象(仅复制引用地址)
二十五、什么是 Java 的 Integer 缓存池?
java的Interger缓存池为了提高性能和减少内存,在-128到127以内的对象会被缓存并复用,例如:interger a =127,这时候就会将a放进interger缓存池,在interger b =127的时候,并不是重新创建创建一个对象,而是去interger缓存池查找有没有这个值的缓存对象,有的话直接拿过来用,没有才去重新创建并存入缓存池。
二十六、java的类加载过程是怎样的?
Java的类加载过程包括加载、链接和初始化三个主要步骤。 1.在加载阶段,通过类加载器将类文件加载到内存中,生成一个Class对象。 2.在链接阶段,包括 验证 、 推备 和 解析 三个子阶段,确保类的字节码安全并为静态变量分配内存和进行符号引用解析。 3.最后在初始化阶段,执行类的初始化逻辑,将静态变量和静态代码块的初始化操作整合并执行。
二十七、String s = new String("abc")会创建几个对象?
1.首先,new会先在堆内存中创建一个String对象(第一个对象,称它为new String对象吧),并让s引|用指向该对象。
2.JVM用字面量”abc“去字符串常量池中尝试获取“abc”对应的String对象的引用。 2.1 如果获取成功,则让new String对象引用常量池中的"abc” 2.2 如果获取失败,则在堆内存中创建一个"abc"的String对象(第二个对象),并把它的引用保存在字符串常量池。然后让newString 对象引用常量池中的"abc"。
所以,使用new String方法时,会创建1个或者2个对象。
二十八、如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
会报错!因为在 Java 中,一个线程只能被启动一次!所以尝试第二次调用 start() 方法时,会抛出 legalThreadStateException 异常。这是因为一旦线程已经开始执行,它的状态不能再回到初始状态。线程的生命周期不允许它从终止状态回到可运行状态。
二十九、java的IO流是什么?
Java的I/O流是用于处理数据输入输出的类库,可以从各种位置读取数据,也可以将数据写入特定位置I/O流分为两大类: 字节流:处理8字节数据,适合处理二进制文件,比如图片、视频。承担任务的类有Inputstream和Outputstream类及其子类。 字符流:处理16字节数据,适合处理文本文件。承担任务的类有Reader和Writer及其子类。
三十、java的基本数据类型有哪些?
四种八类 1.整型
-
byte 1字节
-
short 2字节
-
int 4字节
-
long 8字节
2.浮点型
-
float 4字节
-
double 8字节
-
字符型
-
char 2字节
4.布尔型
-
boolean 不定
四十一、什么是java的自动拆箱和装箱?
自动装箱:将基本数据类型自动的转化为包装类型 自动拆箱:将包装类型自动转化为基本数据类型 减少了代码复杂度,减少了代码的编写常见于集合处理 算数运算。
四十二、什么是java中的迭代器?
迭代器就是java集合框架提供的一种用来遍历集合元素的接口,可以遍历和修改集合的元素(set,map)。 通过ltearator. hasNext()看是否有下一个元素。
通过ltearator. next()返回其元素。
四十三、Java 运行时异常和编译时异常之间的区别是什么?
编译时异常是指在编写程序时编译器检查出来的异常,需要显示的进行处理,try catch 进行捕获或者throw扔出。常见的编译异常,如FileNotFoundException,IOException等 运行时异常 ,是在程序运行时抛出的异常,需要在代码编写时处理好逻辑,减少运行时异常。常见的运行时异常如算数异常,空指针异常,数组下标越界异常等
四十四、Java 中的访问修饰符有哪些?
访问权限:用来控制类、方法、变量的访问级别,有4种:public、protected、default、private public:访问权限最大,当前类、当前包、子类(不同包)、不同包,可以访问 protected:当前类、当前包、子类(不同包),可以访问 default:当前类、当前包,可以访问 private:当前类,可以访问
四十五、Java 中静态方法和实例方法的区别是什么?
静态方法:1.属于类 2.可以使用类名访问 3.不能访问实例变量和实例方法 4.场景:作为工具类的方法实例方法:1.属于对象 2.只能通过对象访问 3.可以访问静态变量和静态方法
六、什么是 Java 中的双亲委派模型?
双亲委派模型是 Java 类加载机制的设计模式之一。它的核心思想是:类加载器在加载某个类时,会先委派给父类加载器去加载,父类加载器无法加载时,才由当前类加载器自行加载。 工作流程: 当一个类加载器(如自定义类加载器)试图加载某个类时,先将加载请求向上委派给父类加载器,父类加载器再向上委派给它的父类,直到根类加载器(Bootstrap ClassLoader)。
在 JDK9 之前,Java 自身提供了 3种类加载器: 1.启动类加载器( Bootstrap classLoader ),它是属于虚拟机自身的一部分,用 C++实现的,主要负责加载<JAVA_HOME>\1ib 目录中或被xbootclasspath 指定的路径中的并且文件名是被虚拟机识别的文件。它是所有类加载器的爸爸。 2.扩展类加载器( Extension classloader),它是 Java 实现的,独立于虚拟机,主要负责加载<JAVA HOME>\lib\ext 目录中或被java.ext.dirs 系统变量所指定的路径的类库, 3.应用程序类加载器( Application classoader),它是Java 实现的,独立于虚拟机。主要负责加载用户类路径( classpath)上的类库,如果我们没有实现自定义的类加载器那这玩意就是我们程序中的默认加载器。 所以一般情况类加载会从应用程序类加载器委托给扩展类再委托给启动类,启动类找不到然后扩展类找,扩展类加载器找不到再应用程序类加载器找。
为什么要有双亲委派机制?
安全性:避免重复加载类。例如,java.lang.0bject 类只能由根类加载器加载,防止恶意代码加载不受信任的类来替代系统核心类。 一致性:保证同一个类在 JVM 中只会被加载一次,确保在整个应用中使用的是同一个类对象。
双亲委派机制先自下而上委托,再自上而下加载,那为什么不直接自上而下加载? 因为本来类加载器是组合关系,也就是子加载器只记录了父加载器,父加载器没记录子加载器(找不到子加载器)其次如果先父加载器接活再传给子加载器,假设有5个子加载器(比如5个平级的自定义加载器)传给哪个加载呢?每个试过去嘛?效率就不高了。
一般聊到双亲委派机制会说到类加载过程,具体看以下博文:
四十七、java中sleep和wait方法的区别?
1.sleep方法 属于Thread类中的方法 释放cpu给其它线程 不释放锁资源 seep(1000)等待超过1s被唤醒
-
wait方法 属于Object类中的方法 释放cpu给其它线程,同时释放锁资源 wait(1000) ,等待超过1s被唤醒 ,wait() 一直等待需要通过notify或者notifyAll进行唤醒 ,wait 方法必须配合 synchronized 一起使用,不然在运行时就会抛出legalMonitorStateException异常
四十八、什么是BIO、NIO、AIO?
BIO(阻塞IO):人一直盯着水烧开,水烧开之后亲自关火 NIO(非阻塞IO):人在烧水的时候去干别的事情,时不时看着水烧没烧开,烧开之后亲自关火 AIO(异步IO):人找了一个帮手,帮手在烧水的时候一直盯着,水烧开之后帮手关火,然后提醒人水烧开了。人全程不管烧水的事情
四十九、什么是Channel?
是非阻塞式IO中的一个核心概念(NIO),是一种更有利于数据读写操作的数据结构
1.Channel是双向的,可以同时进行读取和写入
2.非阻塞式的,可以引入Selector实现多路复用,并发操作。
-
Channel有四种实现,SocketChannel、ServerSocketChannel、DatagramChannel、FileChannel
五十、什么是 Selector?
selector是NIO 中IO多路复用的一个组件,它可以通过一个单独的线程同时监视多个通道(Channel)的事件。