Java基础面试题
简介
本文主要为复习Java基础面试题的记录博客,会持续更新
面试题
JDK和JRE的区别
JDK 是功能齐全的 Java SDK ,它拥有 JRE的一切,还有编译器和工具。它能够创建和编译程序。
JRE 是 Java 运行时环境,包括 JRE和java常用的类库,是Java运行时环境。
重载和重写的区别
区别 | 重载 | 重写 |
---|---|---|
发生范围 | 同一个类 | 父子类 |
参数列表 | 必须修改 | 不能改 |
返回类型 | 可以修改 | 父类方法返回值类型相等 |
异常 | 可以修改 | 可以抛出相同的或者更小的异常 |
访问修饰符 | 可以修改 | 降低限制 |
发生时期 | 编译时期 | 运行时期 |
String,StringBuffer和StringBuilder的区别
String 是用 final修饰的char数组,所以String是不可变的。
StringBuffer和StringBuilder 都继承了 AbstractStringBuilder
,而AbstractStringBuilder
中的char数组没有被被final修饰,所以是可以改变的,
而StringBuffer和StringBuilder 的区别在于是否线程安全,StringBuffer是线程安全的,因为其所有的方法都用synchronized修饰。
总结:
对于单线程下少量的数据可以使用String。
对于单线程下大量数据使用StringBuilder。
对于多线程下大量数据使用StringBuffer。
下面是对应的源码图:
String源码:
AbstractStringBuilder源码:
StringBuffer 源码的方法添加sychronized
接口和抽象类的区别
相同点:
都不能被实例化;
只有在接口被实现了,或者抽象类被继承了才可以实例化。
不同点:
接口只能定义方法,不能实现方法(Java8中可以有default方法可以被实现),抽象类可以有普通的方法实现)
一个类可以实现的多个接口但只能继承一个抽象类
接口更像一种行为设计,而抽象类则是一种模板的设计。<联系到设计模式?接口强调特定功能的实现,而抽象类强调所属关系>
接口的成员变量默认是 static final的 并且必须赋值,不能修改,方法都是被public或abstract修饰的。
抽象类中变量默认是default的,在子类中可以被重新定义或者赋值,抽象方法被abstract 修饰,不可被private,default、static、native和synchronized修饰。
静态方法和实例方法有何不同
静态方法属于类,可以使用 类名.方法名 来实现调用,可以使用 对象名.方法名 来实现调用。
静态方法只能调用本类的静态成员(静态变量和静态方法),实例方法没有限制。
==和equals的区别
==:基本类型比较数值,引用类型比较地址
equals:没有重写,比较的是地址
重写了以后比较的是,重写的规则(一般是内容,比如String)
Object的equals方法:
String重写后的equals方法:
hashCode和equals
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
线程,程序,进程的区别
线程是执行任务的最小单位,一个进程至少包含一个线程
线程是由CPU调度的,占用进程资源<会不会问操作系统的调度算法?>
进程是由操作系统进行资源分配的,程序执行的最小单位
一个进程可以创建多个线程,多个线程共享一块内存空间和一组系统资源
线程和进程资源如图:
线程的基本状态
初始,运行,阻塞,超时等待,等待,终止
如图:
运行时常量池和堆
关于一个对象是在堆中创建还是说在运行时常量池中创建,
String a = new String("123");
String b = "123";
对于a,JVM会直接在堆中创建一个对象
而对于b ,JVM首先会在字符串常量池中查找是否有相同的,如果有,则直接引用字符串常量池中的引用,如果没有则会则会在堆中创建一个对象,并且在字符串常量池中注册一个。
Object常用方法
clone():
返回当前对象的一个拷贝
getClass():
返回当前对象的Class对象
hashCode():
返回本对象的哈希码,主要用在哈希表中,如HashMap
toString():
返回实例名称@哈希码
notify():
随机唤醒一个正在等待的线程
notifyAll():
唤醒所有等待的线程
wait():重载无参,一个参数,两个参数
暂停线程的运行,会释放锁,但是sleep()方法不会释放锁
finalize():
实例被垃圾回收时执行的方法。
如图所示:
Class类常用的方法
forName(String name):
返回指定name的Class对象
newInstance():
返回对象的一个实例
getName():
返回此Class对象的名称
getSuperClass():
返回当前对象的父类的Class对象
getInterfaces():
返回当前Class对象的接口
getClassLoader():
返回该类的类加载器
getSuperclass:
返回该类对应的超类
反射机制
在程序运行时期,我们可以知道这个类中所有的方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
静态编译: 在编译时确定类型,绑定对象
动态编译:运行时确定类型,绑定对象
优缺点:
优点:运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
类加载器
类加载器就是把类的信息装载到JVM中去,类加载器包括用户自定义加载器和启动类加载器
异常
异常和错误的父类是Throwable,
分为 Error和 Exception
- Errors:
-
- 栈溢出
-
- 堆溢出
-
- 虚拟机错误
- Exception:
-
- 检查异常:
-
-
- IO异常
-
-
-
- SQL异常
-
-
-
- 文件未找到异常
-
-
- 非检查异常:
-
-
- 数组下界超出异常
-
-
-
- 空指针异常
-
-
-
- 除零异常
-
异常结构图:
IO
按流向分为输入流和输出流
按操作单元分为子接口和字符流
按照流的角色分为节点流和处理流
如图所示:
常见关键字
final关键字
修饰类:不能被继承
修饰方法:不能被重写
修饰变量:只能被赋值一次,不能修改<成为常量>
transient 关键字
当一个类中的某个属性不想被序列化时可以使用 transient关键字,transient 只能修饰变量
instanceof 关键字
判断一个对象是否为一个类(接口,父类)的实例
goto 关键字
暂未使用
自动装箱和拆箱
装箱:将普通类型用他们的包装类包装起来
拆箱:将包装类型转化为普通类型
Integer i = 10; //装箱
int n = i; //拆箱
包装类的大部分都使用了常量池技术:
Byte,Short,Integer,Long:包装类默认创建了数值[-128,127] 的相应类型的缓存数据
Character 创建了数值在[0,127]范围的缓存数据
Boolean 直接返回 True Or False
浮点类型没有使用缓存技术
Java中常用的包
java.lang:这个是系统的基础类;
java.io:这里面是所有输入输出有关的类,比如文件操作等;
java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
java.net:这里面是与网络有关的类;
java.util:这个是系统辅助类,特别是集合类;
java.sql:这个是数据库操作的类。