整理了今年几家面试过的知名互联网公司的题目(腾讯、百度、大疆、优酷等),基础的重要性是一如既往地重要。本文将以系列的形式来进行,整理在面试过程中比较与代表性的内容,以下是java基础知识部分。
自动装箱:
Integer i = 1;
其实编译器为你自动实现了:
Integer i = Integer.valueOf(1);
自动拆箱:
Integer i = 1;
int a = i;
实际上执行了:
int a = i.intValue();
包括byte、short、char、int 和 enum ,及包装类型Character、Byte、Short和Integer,
java7后又加入了对String的支持。
阐述下支持String的原理:
使用字符串的hash值作为表达式的值,而由于相同哈希值的情况下仍存在冲突的可能,
所有在case语句块时仍需要通过equals方法来判断相等。
== : 比较引用地址的相等或基本数据类型/枚举类型的相等
Equal:对象看情况的相等
hashCode:对象信息的散列值
关系:
两对象比较:euqals返回true时,hashCode叶也相等。
hashCode相等时,equals返回不一定相等。
instanceof: 判断对象类型5是否相等,当父、子类判断时存在单向情况。
对象判断equals方法:
1、 == 判断引用地址 2、instanceof 判断类型 3、属性匹配
4、自反性、对称性、传递性、一致性 5、重写hashcode
主要有以下四种对象创建方式:
1、new 2、反射 (这俩要调用构造函数) 3、clone 4、 反序列化
其中:
克隆:通过实现Cloneable、Serializable(序列化、反序列化实现)来实现对象的克隆
反射:
该方式的表现主要有:
1、运行时取得字段与方法和修改(包括常量)
2、创建对象
原理:jvm通过字节码文件生成相应的对象或获取其信息
优缺点:增加了程序设计的灵活性;性能消耗较大
重载:同一类中,同名函数不同的参数形式,基于对象实际的类型来选择所调用的方法,达到动态绑定的目的。
重写:父类、子类中,同名同参方法,重新定义方法实现。
区别: 前者编译时多态性、后者运行时多态性
(静态方法除外,多态是针对实例方法)
抽象类:区别与普通的类,不能直接被实例化,可以有构造函数,并且子类可不实现其抽象方法。
接口:修饰符为public、变量为final,没有实际的方法,可实现多继承。
强引用:java对象拥有最强的引用,虚拟机在一般情况下不会轻易该引用的对象;
软引用:当内存不足时,如果一个java对象仅含有软引用时,则该对象会被虚拟机回收;
弱引用:当虚拟机发现java对象仅含有弱引用时,就会将其进行回收;
虚引用:同引用队列一起用,跟踪回收活动;
public作用范围:当前类、同一个包、子类、其他包;
protected作用范围:当前类、同一个包、子类;
default作用范围:当前类、同一个包;
private作用范围:当前类;
1、直接通过new thread 的方式;
2、实现runnable接口;
3、通过接口callable (callable能拿到返回值和抛出异常);
4、通过线程池来生成线程;
sleep和yield区别:
sleep 给予线程的运行机会 不考虑优先级,then 阻塞
yield:给优先级高的线程执行,然后进入就绪状态
wait和sleep区别:
wait:释放对象锁 object的方法 —> notify
sleep:不释放锁 thread的方法
两者都可通过interrupted 打断暂
notify和notifyall区别:
notify:唤醒的某一线程去得到锁
notifyall:唤醒所有等待线程去竞争锁
wait/notify/notifyall : 它们都需在同步块中调用 ,均可释放对象锁;
wait:立即释放控制权 然阻塞(需notify) notify:执行完再释放
synchronized:关键字
Lock:对象 可控制获取锁的时间与获取锁的信息
手动释放锁、让线程响应中断、可知获得锁与否
多线程竞争较激烈时,Lock较优
上下文切换:cpu控制权由一个正在运行的线程切换到另一个就绪状态的线程
Error、Exception:
父类:Throwable :含异常出现时的log
Error:系统级错误,如OOM
Exception:
需程序捕捉和处理的程序设计性错误
被检查异常(throw、try catch)、运行时异常
Throw:方法中抛出异常
Throws:申明异常
try catch finally:
try中有return 会记录返回值 待finally执行完 返回值不变
如finally中有return 则值会变
finally:释放外部资源
JVM的内存模型主要可以分为线程共享区和线程私有区,
线程共享区:java堆(放对象和数组、GC)、方法区(类信息、常量、静态变量等,永久代);
线程私有区:程序计数器(指示代码执行、无oom)、Java虚拟机栈(java方法调用)、native方法栈;
而每个线程都有自己的栈内存, 堆是共享的,线程会缓存对象到栈中使用,而volatile则可要求线程从内存中读取
判断对象内存是否该被回收:JVM根据可达性分析(引用计数会出现互相引用的情况)
java内存回收算法大概可分为:
分年代回收:年轻代(创建)、老年代(呆的久)、永久代
标记-复制算法:区域分两块 一块使用另一块回收 交替使用
空闲区满时 就被复制到老年代区
标记-清除、标记-整理算法
类生命周期大致包括:加载、验证、准备、解析、初始化、使用和卸载这7个阶段,而前5个阶段为类的加载过程。
加载:获取类的为进制字节流,并转换为运行时的 数据结构,在java堆中生成Class对象;
验证:验证class文件的字节流信息是否符合当前虚拟机的要求;
准备:为类的静态变量分配内存并将其初始化为默认值;
解析:常量池的符号替换为直接引用的过程;
初始化:执行 < clinit >() 方法的过程。