背面试题很枯燥,加入一些戏剧场景故事人物来加深记忆。PS:点击文章目录可直接跳转到文章指定位置。 |
【门卫甲,门卫乙,面试者老王,路人等】
门卫甲:来者何人?报上名来。
老王:隔壁老王前来面试
门卫乙:现在面试Java的人很多,如果谁都放进去,恐怕总裁会责怪我们,你先说说1.Java的跨平台原理
,回答对了再进去面试吧。
老王:这个公司倒是有意思,门卫当起了面试官。Java实现跨平台是JVM(Java虚拟机)起的作用,编译好了一份Java字节码,换到不同的平台上时,并不需要重新编译,前提是这些平台上都安装了相应平台的JVM,JVM不是跨平台的。
门卫甲:我也有个问题,2.说一下Java的垃圾回收机制
,对了我去买个冰棍,老乙给你也带一根。
老王:给我也带一根钟薛高我就给你说垃圾回收机制;
垃圾回收器通常是作为一个单独的低级别的线程运行,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。垃圾回收器不可以马上回收内存,可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。 回收机制包括:
①分代复制垃圾回收
不同生命周期的对象可以采取不同的收集方式,生命周期比较长的如Http请求中的 Session对象、线程、Socket连接。生命周期比较短的如:String对象。分代回收是把不同生命周期的对象放在不同代上,包括年轻代、年老代,和持久代,因此垃圾回收区域、时间也不一样。
②标记垃圾回收
使用标记清除算法,内存耗尽时,程序将会被挂起,垃圾回收开始执行.当所有的未引用对象被清理完毕时,程序才会继续执行。标记清除算法由两个阶段组成:
标记阶段,标记所有的可访问对象。
收集阶段,垃圾收集算法扫描堆并回收所有的未标记对象。
③增量垃圾回收
解决标记清除的长停顿问题。增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成较小的应用程序中断。
门卫乙:其实我也不知道你说的对不对,不过你照着手机读是不是有点过分了。手机收起来问你一个简单的。3.JVM加载class文件的原理机制?
老王:不知道
门卫乙:让你手机收起,你就不知道是吧,我来告诉你经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件,JVM会确保这个类被加载、连接(验证、准备和解析)和初始化。
①类的加载:是由类加载器和它的子类在运行时查找和装入类文件中的类,把.class文件中的数据读入到内存中。
②连接阶段:加载完成后,进入连接阶段,包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。
③最后JVM对类进行初始化,包括:如果类有父类先初始化父类,类中存在初始化语句,就依次执行这些初始化语句
门卫乙:我话说完,你赞成还是反对。
老王:赞成。一直都是你问我,我也问你一个:4.门卫大哥,你对Java内存了解多少?
门卫乙:一般我不轻易显露自己的学识,但是你既然诚心诚意的发问了我就露一手:
①Java内存分为堆与栈,java中一个线程就会相应有一个线程栈与之对应,Main函数就是栈的起始点,也是程序的起始点即程序执行的入口。
②栈是运行时的单位,存储基本数据类型和堆中对象的引用以及当前程序相关的信息(局部变量、程序运行状态、方法、方法返回值)等, 而堆是存储的单元,存储对象信息如对象的属性。
③栈解决程序的运行问题,即程序如何执行(运行逻辑),或者说如何处理数据,堆解决的是数据存储的问题,即数据怎么放,放在哪儿。
④堆与栈的分离,使得堆中的内容可以被多个栈共享,提供了有效的数据交互方式,节省了空间。
⑤由于栈只能向上增长,就会限制住栈存储内容的能力,而堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
门卫甲:你回来了。
门卫乙:是我回来了,不是你回来了。在上班时间能吃冰棍吗?老王你说说5.为什么不把基本类型放在堆中
门卫甲:抢答:因为基本类型占用的空间一般是1~8个字节,不会出现动态增长的情况—长度固定,因此栈中存储就够了,如果把它存在堆中是没有什么意义的
门卫乙;问你了吗,显眼包。老王回答一下6. java中的参数传递是传值呢?还是传引用?
门卫甲: 抢答: 对象传递是引用值传递(传递的是引用的地址值),基本数据类型传递是值传递
老王:我可以进去了吗?过度的饱食有伤胃口,毫无节制的门卫面试,结果只会让我错过面试的时间。— —对了把冰棍给我。
门卫甲/乙:要糕没有,要进去你就进去吧。
【老王,保洁公司老板,保洁阿姨】
老板:关于公司保洁方面你已经做的很好了。但是其他种种事项还需要阿姨你单独来办公室单独讨论拟定。我知道你在这方面的阅历尚浅,先问你一个问题:7.你对面向对象思想的理解
保洁阿姨:想炒鱿鱼直接说,何必整这出。亏我昨天背了面试题:面向对象编程简称OOP技术,使用许多代码模块,每个模块都只提供特定的功能,它们是彼此独立的,可以增加代码重用的几率,更加有利于软件的开发、维护和升级。另外OOP的三大核心特性:继承、封装、多态的特性,使得在面对象编上能够设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低,所以这一编程思想是目前一种应用最为普遍的软件设计思想。
老板:看来你还是有点功底:8.说说面向对象的三大特性
老王:我抢答:
①封装
封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。
②继承
继承是子类共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。在定义或实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。
③多态
多态指的同一个对象,在程序不同时刻的多种运行状态。指的就是父类引用指向子类对象,调用方法时会调用子类的实现而不是父类的实现。不同子类继承了同一个父类。当我们统一用父类引用变量去调用这些不同的子类对象中的方法时,我们称为多态。
为使多态能运行,存在着继承或者实现关系
可以将子类的对象赋给父类/接口,以多态的形式来传递参数,增强了参数类型的灵活性。
多态的好处和弊端:
好处:多态的存在提高了程序的扩展性和后期可维护性
弊端:虽然可以预先使用,但是只能访问父类中已有的功能,运行的是后期子类的功能内容。不能预先使用子类中定义的特有功能。
多态应用场景:当接口已经确定,但同一个接口在不同环境需要不同实现的时候。如:工厂模式
老板:你是谁,还抢答,不过看起来答得不错,来保洁公司上班吧。
老王:口出狂言。
保洁阿姨:老板我要辞职去面试Java。
【保洁阿姨,老王】
保洁阿姨:“对潇潇暮雨洒江天,一番洗清秋。渐霜风凄紧,关河冷落,残照当楼。是处红衰翠减,苒苒物华休。惟有长江水,无语东流。不忍登高临远,望故乡渺邈,归思难收。叹年来踪迹,何事苦淹留。想佳人、妆楼颙望,误几回、天际识归舟。争知我、倚栏杆处,正恁凝愁。”请问:9.有几种方法倒序输出这首词
老王:这话题过弯速度太快了吧。我百度了一下有四种方法:
①利用String类的toCharArray(),再倒序输出数组的方法。
/*
* 利用String类的toCharArray(),再倒序输出数组的方法
*/
private static void reverseString1(String str) {
char[] chr = str.toCharArray();
for (int i = chr.length-1 ; i >= 0; i--) {
System.out.print(chr[i]);
}
System.out.println("\t");
}
②利用String类提供的subString()方法,利用递归的办法输出倒序字符串。
/*
* 利用String类提供的subString()方法,利用递归的办法输出倒序字符串。
*/
private static void reverseString2(String str) {
if (str.length() == 1)
System.out.println(str);
else {
String subString1 = str.substring(0, str.length() - 1);
String subString2 = str.substring(str.length() - 1);
System.out.print(subString2);
reverseString2(subString1);
}
}
③定义一个StringBuffer类,用StringBuffer类中的reverse()方法直接倒序字符串。
/*
* string倒序输出
* 定义成一个StringBuffer类,用StringBuffer类中的reverse()方法直接倒序字符串。
* 2018-5-18 13:22:10
*/
private static void reverseString3(String str) {
StringBuffer buffer = new StringBuffer(str);
System.out.println(buffer.reverse());
}
④利用字符串串联符号"+"特性
public class MyTest {
public static void main(String[] args) {
String s = "对潇潇暮雨洒江天";
String s2 = "";
for (int i = s.length() - 1; i >= 0; i--) {
s2 += s.charAt(i);
}
System.out.println(s2);
}
}
}
保洁阿姨:你有对象吗?我看你Java基础知识很扎实啊。不如介绍一下10.Java对象初始化顺序
老王:有那么一秒我认为我要脱单了。Java对象初始化顺序如下:
①第一种是本类的初始化
静态变量、静态初始化块、变量、初始化块、构造函数
②第二种是含有父类的初始化顺序。
父类静态变量、父类静态初始化块、子类静态变量、子类静态初始块、父类变量、父类初始化块、父类构造函数、子类变量、子类初始化块、子类构造函数。
老王:礼尚往来我也问你一个问题吧。Java类都有一个共同的祖先类,就是Object,请问11.Object中有哪些方法:
保洁阿姨:我当然知道:
protected Object clone() 创建并返回此对象的一个副本。
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。
Class> getClass() 返回此 Object 的运行时类。
int hashCode() 返回该对象的哈希码值。
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
String toString() 返回该对象的字符串表示。
void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
老王:12.方法重载和重写的区别?Overload的方法是否可以改变返回值的类型?
保洁阿姨:
Overload是重载,Override是覆盖,也就是重写。
①重载Overload
表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。是否可以改变返回值类型,在重载的定义中,与方法是什么类型返回值无关
②重写Override
表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给重写了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,子类方法的访问权限只能比父类的更大,不能更小。
保洁阿姨:面试的真谛在于:那就是认清了面试的真相后,依然热爱面试。发觉了工作的残酷后,依然过着美丽人生。祝你好运。