面试环境:还是很不错的地点、环境也很好,前台不爱笑,感觉有点冷啊
过程:前台领取信息表格、笔试题,找空座位做题
笔试没答好的第一题:
PrintSequence的main方法执行后会顺序打印哪些内容
public class A { static { System.out.println(" static A"); } public A() { System.out.println(" constructor A"); } } public class B extends A { public B() { System.out.println(" constructor B "); } public void printHello() { System.out.println(" Hello B"); } } public class PrintSequence { public static void main(String[] args) { B b = new B(); b.printHello(); } }
很显然,当时我答错了,我回答的是
static A
constructor B
Hello B
而实际答案是
static A
constructor A
constructor B
Hello B
这题考的是很基本的java类加载机制,在过去一年中我也是对该问题有所涉猎的,但只是看了一些文章,没有记住具体内容,大概的思路范围在双亲委派这个名词中即可找到答案,我喜欢简单一点白话一点,以后凡是遇到这类问题的重点在于凡是new子类的时候,该子类的所有父类、父类的父类一直到object都要先被加载,加载不是new,是虚拟机把class文件解析后放入到永久带(PermSpace 当jdk<1.8)或者元空间(Metaspace 当jdk>=1.8时),然后执行父类的cinit的方法和init方法详细参见https://blog.csdn.net/w425006762/article/details/50452469,然后才是把当前对象通过new放入到堆中,我答错的原因是大概了解会执行cinit,但没有了解所有父类的init也会执行,所说的init是默认初始化方法,B类中的public B(){}方法,如果自己不写则虚拟机将java文件编译成class时会替我们放一个init,cinit则是A类中 static{}块中的内容(本文范围)。
第二个题:
写出程序打印内容
public class PrintThreadNameSequence { public static void main(String[] args) { Thread.currentThread().setName("main-thread"); MyThread mt = new MyThread(); mt.start(); } } class MyThread extends Thread { MyThread() { this.setName("new-thread-name"); this.printThreadName(); } public void printThreadName() { System.out.println(this.getThreadName()); } public String getThreadName() { return Thread.currentThread().getName(); } @Override public void run() { this.printThreadName(); } }
我的回答是,new-thread-name new-thread-name,很显然我错了,面试官告诉我我错了我当时还不信,我说实在不知道哪里错了。。。后来面试官指出没调用.start()方法之前还是在main线程之中。。。嗯。。太tm有道理了!
第三个题:
有一座桥,从桥的一边到另一边,从桥上走的人有老中少,每个人过桥所用的时间不同,老年人10分钟,中年人5分钟,儿童2分钟,少年1分钟,由于过桥的时候是在黑天,过桥需要手电筒,只有一个手电筒,一次最多能过两个人,时间以按大的那个人计算,如何用最少的时间过桥。
我回答的是 1拿着手电筒来回跑,我当时想了好久没有觉得比这更快的时间了,但想着这题不能这么简单,但也没别的思路了。。。用时是1+10 = 10过去 +1返回,1+5=5过去+1返回,1+2过去完成总用时是 10+1+5+1+2=19分钟,回来我在百度查了一下,果然有牛逼的答案是
第一步:1、2过桥,用时2分钟;
第二步:1带电筒回来,用时1分钟;
第三步:5、10过桥,用时10分钟;
第四步:2带电筒回,用时2分钟;
第五步:1、2过桥,用时2分钟;
总共17分钟。 嗯。。。果然思路清奇,正如马爸爸说的,有些人因为看到才相信,有些人因为相信所以看到。又好像某些人投资,外人看起来好像是亏的,实际人家可能精明的很,花落谁家鹿死谁手真不一定。
第四个题:
单链表反转,给出下列方法结构,写出方法体
public Node reverse(Node node) { }
当时我用的是把所有node的子项加入到list中,然后从最后一个取到前一个。。。因为当时我考虑了一下java中对象都是引用,一旦写不好链表就会把链伤筋动骨的断掉,比如a-b-c-d这个链,我先取出a、b,然后直接setb的下一个是a,那么b的后边的链就全断掉了,这个当时没想明白怎么弄比较好,回来想了想写了如下代码,感觉答案好像对了。。。
public class ReverseOneWayLinked { class OneWayNode { //简单点不写get、set了 public OneWayNode next; public String name; OneWayNode() { } OneWayNode(OneWayNode next, String name) { this.next = next; this.name = name; } } private OneWayNode getLinked() { OneWayNode e = new OneWayNode(null, "e"); OneWayNode d = new OneWayNode(e, "d"); OneWayNode c = new OneWayNode(d, "c"); OneWayNode b = new OneWayNode(c, "b"); OneWayNode a = new OneWayNode(b, "a"); return a; } public OneWayNode reverse(OneWayNode node) { OneWayNode prve = null; for (;;) { if (node == null) { break; } OneWayNode next = null; if (prve != null) { //感觉有点绕 next = node.next; node.next = prve; prve = node; } else { //第一轮的时候 next = node.next; prve = node; prve.next = null; } node = next; } return prve; } public static void main(String[] args) { ReverseOneWayLinked oneWayLinked = new ReverseOneWayLinked(); OneWayNode e = oneWayLinked.reverse(oneWayLinked.getLinked()); while (true) { if (e == null) { break; } System.out.println(e.name); e = e.next; } } }