美文网首页公司管理提高面试题程序猿
一道简单的Java笔试题,但……

一道简单的Java笔试题,但……

作者: 匿蟒 | 来源:发表于2016-04-30 12:03 被阅读4395次

    前言

    面试别人,对我来说是一件新奇事,以前都是别人面试我。

    我清楚地知道,我在的地域与公司,难以吸引到中国的一流软件人才。所以,我特地调低了期望,很少问什么深入的技术问题,只问一些广泛的、基础的。我只要最终给Leader一句“这个人技术还行/很好/非常好”,就行了。至于其它能力、综合水平,由别人把关。为此,在挑选唯一的一道笔试题时,我特别地上心。

    首先,我不敢用网上那些广为流传的,比如Leetcode、《程序员面试宝典》里的题——这些都太难了!正儿八经做,其实很少有人能在1小时内完美做出来,除非之前遇到过。我本人也并非什么思维敏捷的牛人,不然也不会混得这么惨。正所谓己所不欲,勿施于人,我也不希望以后别人考我特别麻烦的算法题,所以自创了一道特别简单的。

    其次,对(Android平台的)Java程序员来说,大多数情况下不需要写什么复杂的算法。相反,Java层主要做的是界面控制、业务逻辑、数据流之类的,更提倡代码的简单和可读,尽量用既有的公共类库,不惜损失一些运行效率。拿一道复杂的算法题,考一个Java程序员,多少有点刁难人。

    最后,还是那个薪资待遇和人才梯度问题。没有Google的工资,就别考Google的题;没有Google的向心力,就别期待有Google级别的人才来面试。

    亮题

    以下有一个static method,类外会调用它,一个个地插入一些元素进入一个List。可以改变这个List内容的,只有这一个method,要求任何时候这个List都是有序的。

    比如,依次插入3、2、1、2,我希望List的顺序是1、2、2、3。

    class Solution {
        private static List<Integer> sSorted = new LinkedList<>();
        public static void addElement(int e) {
            // TODO: Insert e to sSorted and make sure sSorted is always sorted.
        }
    }
    

    我会给出15分钟的时间,而其实往往会再多给10分钟。

    (有兴趣,你可以停在这试试。相信在看文章这种轻松的环境下,理清这道题的思路也就10~30秒。)

    (为什么下限是10秒呢?唉……一不小心暴露了我智商的峰值。我实际问过一些同事,他们通常在理解的同时,就立刻给出了正确的思路,过程不足5秒,其中甚至包括一个硬件工程师,和一个只负责沟通和文档的妹子。)

    提示

    在过程中,我会逐步给出一些提示,从接口到思路,都会主动提供,其它也基本有问必答。

    如果单纯考算法,C语言才是最合适的,因为它没有什么高级的工具类,什么复杂点的都得自己写。而Java,则有一些“基础”类库是难以记忆的。比如前面出现的java.util.List,就没有多少人能在纸上写出它的常用接口。

    我并不想考察什么死记硬背,在这个时代,断网后本来就没几个程序员能正常编程。所以我会主动提供一份List的不完全接口列表。

    public interface List<E> extends Collection<E> {
        public void add(int location, E object);
        public void add(E object);
        public void clear();
        public boolean contains(Object object);
        public boolean equals(Object object);
        public E get(int location);
        public int indexOf(Object object);
        public boolean isEmpty();
        public E remove(int location);
        public E set(int location, E object);
        public int size();
    }
    

    我没有给出完全的接口,因为给多了无疑是误导人。真正能用上的接口其实也就3个,但我也总不能只给3个,提示得太明显,也限制了对方的思路。所以,给出了可能用得上的这几个。我也没给出注释,因为有声明就已经够了。而且如果对方问起,我也会给出解释。

    一开始我想,考一个排序算了。但是转念一想,这也太不负责任了。对面要是背一道冒泡排序的解法上来,达不到考察技术水平的目的,Boss也不会认可。本着“放水不能太明显”的原则,我想考插入排序,并且把题目弄得没多少人见过。

    排序是一类基本算法,合格的程序员至少会一种。大多数人都只会入门级的冒泡排序,而我更喜欢插入排序,原因……你会明白的。

    插入排序,其实就是把数组或列表在逻辑上分成两部分,一部分是待排序的,一部分是有序的。一开始,有序的部分只有一个元素(或者一个都没有),然后从待排序的部分里一个个出来,入到有序的部分。等元素都插入到了有序的部分,排序过程也就完成了。

    你看,也就抽插N次的事。而我这道题,就是只考插入排序算法的一半,会插就行。

    在面试过程中,我甚至常常亲自解释插入排序是怎么回事——放水到这个份上,我都不忍心再退步了。

    真正的考察点

    这是一份Android平台的开发工作,Boss要求的是能干活、干好活。我给出的建议要求是:

    1. 熟悉Java。
    2. 有良好的沟通、表达能力。
    3. 学习能力强,喜欢不断拓展计算机领域的知识。
    4. 有良好的编码习惯,愿意为代码的简洁、优雅而反复修改。

    我建议Boss放弃学历和工作年限的要求,技术岗位就应该只考察技术(和其它基本能力),不应该考察技术的间接证明。

    Java是Android的基本功(我们不玩Kotlin、Scala、React Native等新花样),这门语言如果不扎实,那至少得带半年。

    我没有在Android岗明确地要求考察Android,是因为Android的那些东西相对来说容易学习。即便是毫无经验的新手,要搞清楚什么“四大组件”“五大布局”,也就一两天的事。而如果Java不够扎实,各种肉眼可见的大小bug就会层出不穷,知识盲点一两年都补不完。

    沟通是职场基本功。如果话都说不清,那么会显著降低团队的沟通效率。而且,我个人认为,话说不清的人,代码一定写不好。语言条理清晰,逻辑层次分明,体现到代码上,就是简洁、明朗。

    学习能力、求知欲,是作为一个程序员的基本素养。因为,大部分人的工作,类似于在一堆按钮中,找到合适的那个按下去;而程序员的工作,往往是闭着眼睛这么干。开发工程师通常是在一堆未知(没读过的代码、不知道的接口)中,把一小部分变成已知(读懂了的代码或接口),进行一些增删改,最后达成外界(产品经理、设计师、测试工程师)赋予的业务目标。

    一些职业卖口水,一些职业卖口才。一些职业卖青春,一些职业卖肉体(咳咳,我说的是空姐和搬砖,想歪的去面壁)。一些职业卖知识,一些职业卖能力。

    程序员,或者说软件开发工程师,卖的是学习能力(其实也包括青春和肉体),快速学会各种知识,找到那些藏在屏幕外的按钮,并且正确的按下去。

    比如,像Bash这类Command line工具,就是自己敲命令出来执行,而不是去界面上找功能对应的按钮;而程序设计、实现,就是去发现、或者创造一种解决问题的办法,然后用代码表达出来——你看,都是在干一些反UI、UX设计的事。唯有不断地学习,才能提高效率,把自己从加班中解脱出来,把项目从bug中拯救出来。

    所以,厌学的人当不了好程序员,也干不长。

    编码习惯,相对次之。部分观点认为,这东西伴随一生,如果一开始没有好习惯,这辈子都没办法改了。Boss就是这么认为的,我倒是不这么认为。我相信编码习惯的可塑性是很高的——你不按规范写,我不给你merge,改不改?

    但是,编码习惯作为程序员的软技能,还是可以一定程度上看出其技术素养、代码质量的。至于优雅什么的,我其实没有真的敢这么期待。

    所以,我这道题其实是考察这四点。

    1. 能写出来,并且无明显问题,代表Java基本功扎实。
    2. 理解我对题目的描述,和我确认清楚题目的细节,这是看沟通能力。
    3. List接口不知道,我给你啊;插入排序不会,我教你啊;其它还有什么不会,你问啊——这是在考察学习能力。
    4. 代码的字里行间,可以明显看出编码习惯。

    面试结果

    总体来说,我很伤心。

    第一位就让我很伤心,当我看了他前两行代码,就不忍心接着往下看:

        private static List<Integer> sSorted = new LinkedList<>();
        public static void addElement(int e) {
            if (null == sorted) {
                sorted.add(e);
            }
            // I couldn't read more!
    

    第一行就编译不过。如果他对Java的一些命名规范有一定的了解,就绝不会把sSorted写成sorted。(当然,sSorted也许并不是合适的命名方式,因为s和m这类前缀有些冗余。我通常遵守Android源码的通用规范,它是有这类前缀的。)

    第二行必然抛出NullPointerException,而不知道是该庆幸还是悲伤的是,它永远执行不到。根据我已经给出的一个接口addElement,和可以猜到或者问出来的读取接口,都是不会把sSorted变成null的。这体现了沟通、理解能力的一点问题。

    此外,即使sSorted因为什么bug而变成null,这里也不应该做处理,而是任其抛出NullPointerException,或者转义一下,主动抛出IllegalStateException。否则,此处将变成一个不会crash的隐藏bug。不能用正常处理,代替异常处理;当然,也不能用异常处理,代替流程控制。


    另外,更令我失望的是,有一位是这么写的:

            for (int i = 0; i < sSorted.size(); i++) {
                if (e == sSorted.get(i)) {
                    sSorted.add(i, e);
                }
            }
    

    我问他,如果这个元素不在这个List里存在怎么办?如果这个List是空的怎么办?他顿时一囧,我也一起囧,心想自己是不是太坏了。


    还有一位,仿佛听见了我这几个问题,他竟然一一作答:

            if (sSorted.size == 0) {
                sSorted.add(e);
                return;
            }
            if (e >= sSorted.get(sSorted.size - 1)) {
                sSorted.add(e);
                return;
            }
            if (e <= sSorted.get(0)) {
                sSorted.add(0, e);
                return;
            }
            if (sSorted.contains(e)) {
                sSorted.add(sSorted.indexOf(e), e);
                return;
            }
            // more...
    

    他想干什么呢?也许是优化性能吧,只能这么帮腔了。另外,他对size的理解,和数组的length相同。

    这位算是经验比较丰富(30岁),对Java的理解比较深入的了。他说排序不需要手写,Java里有现成的接口。我说,是这样没错,但接口我没给出,如果你记得,那就写出来吧。

    于是他在刚才那一大段“优化”的后面,这么写了:

            sSorted.add(e);
            sSorted.sort(new Comp...able() {
                public boolean ?(left, right) {
                    return right >= left;
                }
            });
    

    思路上,插入后再排序,我先不吐槽。我明明说了“记得”再写,这Comparable及其接口int compareTo(T another)如果记不清,我就当看lambda表达式了。可是,他这个?分明是Comparatorint compare(T lhs, T rhs)接口呀!

    不过,其实这些我都可以捏着鼻子认了,因为我也手写不出来。但List是没有sort方法的呀!

    ArraysCollections才有各自的sort方法,它俩算是银弹型工具类,而ArrayCollection是没有的。这个细节,谁用谁知道,知道了就绝不会记错,尽管就差一个s


    还有一位,他先插入、再冒泡排序,是这么写的:

            sSorted.add(e);
            for (int i = 0, sSorted.size(i) > sSorted.get(e), i++) {
                temp = sSorted.get(e);
                sSorted.get(e) = sSorted.size(i);
                sSorted.size(i) = temp;
            }
    
    1. 你没看错,for()里面是,分隔的。
    2. 你没看错,temp是从石头缝里蹦出来的。
    3. 你没看错,List.get(e)是可以对其赋值的。
    4. 你没看错,List.size(i)是可以传参数进去的。

    还有两位,直接交白卷放弃了。

    其中一位还比较认真,思考了一会儿,说“我不想浪费时间”。

    我没乱用词,他确实“比较认真”。另一位在我递过去后,直接看两眼就递回来,“排序我不会”,然后看手机去了。

    o(╯□╰)o

    参考答案

    我自己在纸上写的时候,花了大概5分钟去思考细节,再花5分钟写出来。(唉……一不小心,又暴露了自己奇慢无比的思维,以及奇慢无比的写字速度。)这比我此前预计的时间多了好几倍!

    不过,以我给的15~25分钟,应该不算太难为人……吧?

    class Solution {
        private static List<Integer> sSorted = new LinkedList<>();
    
        public static void addElement(int e) {
            int i;
            for (i = 0; i < sSorted.size(); ++i) {
                if (e <= sSorted.get(i)) {
                    break;
                }
            }
            sSorted.add(i, e);
        }
    }
    

    这是我自己在纸上写的答案。

    (如果有兴趣,可以停在此处,考虑下这是否是最优算法。)


        @Override
        public E get(int location) {
            if (location >= 0 && location < size) {
                Link<E> link = voidLink;
                if (location < (size / 2)) {
                    for (int i = 0; i <= location; i++) {
                        link = link.next;
                    }
                } else {
                    for (int i = size; i > location; i--) {
                        link = link.previous;
                    }
                }
                return link.data;
            }
            throw new IndexOutOfBoundsException();
        }
    

    这是java.util.LinkedList在Android(API 23)上的实现,而反编译Oracle JDK 1.8的实现也大同小异。

    也就是说,我写的答案虽然看似简洁,但其最坏时间复杂度与先插入再排序也没太大区别,都是O(n2)。

    终日打燕,反而被燕啄了眼!(暴露了真实水平。)


    我后来又写了一个参考答案,算是勉强在脸上摸了些防晒霜。

    (大家有兴趣可以想想为什么这是一个改进。当然,一定还有更好的方案。)

    class Solution {
        private static List<Integer> sSorted = new LinkedList<>();
    
        public static void addElement(int e) {
            int i = 0;
            for (int j : sSorted) {
                if (e <= j) {
                    break;
                }
                ++i;
            }
            sSorted.add(i, e);
        }
    }
    

    (我没有在提示列表中给出迭代器,结果自己也被晃过去了。)

    隐藏的杀手锏

    面试官在出题考察应聘者时,应聘者也在通过这道题考察这家公司。

    为了避免让人觉得这家公司考题太简单、工作内容太无趣、里面的员工(我)水平太低,我还准备了一些后续问题,由浅入深,作为杀手锏。

    1. 为什么LinkedList可以赋值给List
      考察多态(polymorphism)。
    2. 为什么List<Integer>要写<>内的内容,而LinkedList<>()可以不写?
      考察泛型(generic)。
    3. 为什么List里面是Integer,但放进去和拿出来的都是int?
      (此处有坑,其实拿出来的还是Integer。)
      考察基本数据类型的自动装箱、拆箱(auto boxing/unboxing)。
    4. 如何在外面有多线程调用时,保证这个唯一的List的正确性?
      考察synchronizedvolatile
    5. 如何在多线程状态下的每一个线程,各保持一个独立的List
      考察ThreadLocal

    (当然,还有一些和Android相关的问题。)

    我真心是没想考算法,所以连算法复杂度的评估都没打算问。

    实际情况是,我往往没有机会问这些问题,因为没几个人写出来。

    吐槽与建议

    首先,喷一下大学扩招……算了,不扯这么远了。

    那两位放弃做题的,一个是计算机学院的,一个是软件工程学院的。排序写不出来,竟然也是能毕业的!

    有两位是某App的开发者。我把他们的App下载下来,发现了一堆bug后,本来想忍忍、就当没看见、码农何苦为难码农,然后手机发热、卡顿、灭屏后几乎点亮不了(内存泄露吃光了RAM,导致系统进程没有内存可用)。过了一阵最终好了,我查看耗电排行,运行10分钟就高居榜首,耗了17%的电——我吓得立刻卸载了。一个第三方App能把系统给卡成这样,一般人还真做不到。

    还有两位是“相关专业”的,非计算机、软件工程专业,反而表现最佳,虽然还是没写出来。

    他们无一例外,都是在大学以外,又参加过某些Java、Android培训的。这些培训班的水平,可见一斑。问题倒不一定是培训班的教学质量,而是这种大规模提供人才转型服务的形式本身——这个世界上,本来就不是谁,都能当一个好码农,哪怕工作要求只是复制粘贴。

    现在,很多码农都戏称自己是在“搬砖”、复制粘贴,但实际上程序员的工作不可能仅止于此。使用别人写好的基本算法,参考别人的实现代码,只是为了集中精力去解决抽象层次更高的业务问题。

    我们不写代码,我们只做代码的搬运工。”——万万不可把这句话当做信条。

    还有很多人,在没有Demo的情况下,无论给多么详细的API或其它资料,仍然无法写代码。他们只能在既有的基础上,修修补补,无法凭空创作。


    我推荐三本Java的基础书:

    • 《Java编程思想》(Think in Java)
      这本是最合适的Java语言入门书。其它很多语法书都是从C/C++的角度来讲Java的变化,或者从C++的思路来讨论Java怎么用,而这本书的英文名则直接告诉你,请用Java来思考、解决问题。
    • 《Effective Java》
      Java中有很多坑,Java中也有很多糖。如果没有看过这本书,那么不知不觉就会犯很多大忌。
    • 《代码整洁之道》(Clean Code)
      我是在独立写一个小项目的时候开始看的。看到一半时项目也写到一半,顿时连代码都不会写了!每天都在写自己看不下去的代码,而不知道怎么写能看得过眼的。加速看完后,重新开始会写代码。最终,项目后半部分的代码,和前半部分完全不同,不像一个人写的,我后来又重构了一遍。

    (为什么我不多推荐点书呢?一来,是我本人也没看过多少,囧;二来,三本是极限,根据我的经验,推荐三本可以让人看一本,推荐三本以上,受众一本也不会看。)

    我有一个朋友,也是一个前同事,好学如好色。他周末都在找一个大学教室看书,甚至有时请年假去教室看书。一本《Java编程思想》,逐行精读三遍以上。工作经验不足两年,跳槽三次,现在在一家百亿级上市公司,年薪三十万,统率十人。

    究其原因,无非基础知识扎实,口水喷死面试官尔。

    后记

    我作为一个面试别人的初哥,一心只想着自己喜欢的抽插……呃不,插入排序算法,给别人造成了不必要的麻烦,只能说抱歉了。

    和我一起面试的,还有一个负责文档和规范的妹子(前面提到过的那个)。她也是有一票否决权的,而且用得比我更频繁!

    我最多只给交白卷的,和那个耗电超恐怖的App,这几个人直接否决。而这个妹子,考察对方的其它综合能力。

    在实际工作中,她是需求的接口人,我们需要和她沟通,实现各方对我们团队的需求。所以,只要她说一句“我和这个人难以沟通”,那么Boss基本上就直接拒绝了。

    下次我还是换一道更简单的吧,码农何苦为难码农。

    相关文章

      网友评论

      • mrwangyong:Java编程思想其实并不适合小白入门
      • artshell:"另外,他对size的理解,和数组的length相同", size本来就和数组length相同
        artshell:@匿蟒 没注意他的括号
        匿蟒:@artshell 你用数组的length时加括号吗?
      • ca9f36b7f5be:首先感谢博主分享,题目确实有意思。但即使使用了foreach/Iterator来查找,效率依然不是最高的,因为一共遍历了两次集合(foreach查找一次,add方法一次)。但事实上,抛开api,从数据结构上考虑,因为用的是链表,所以完成这件事遍历一次就足够了:逐个节点比较,找到合适的位置,把新节点链接到合适的位置即可。至于实现,使用List接口提供的listIterator()方法,获得 ListIterator ,找到合适的位置时,调用 ListIterator的add方法插入即可 :smile:
      • 81109e71e187:也许我做后台的吧,使用的都是插入无序,取用时先集合工具类sort下,性能提升很多。
      • Twinkle_______:感觉这个问题跟插入排序也没多大关系,就是比较大小,找到index,然后add进去,其实
        void add(int index, E element); 已经做了大部分事情。
      • fc00ff4762b5:看完觉得有必要重新重视java 了
      • Avalon1:做了半年Android,发现我自己常用的容器就只用过arraylist,hashmap。:sob:。平时下班也有积极学习一些东西,不过基本都是熟悉一些API,和事件分发,自定义View只能弄个很简单的。也回看一些MVP呀,retorfit,rxjava,okhttp之类的结合用法,不过自己公司用的是之前的asynchttp,以前的代码基本也是除了抽离网络请求之外都放activity的:sweat:,想优化下感觉好无力π_π
        匿蟒:@Avalon1 你如果觉得基础不足,的确应该优先去补。
        基础,影响的是进步的速度。

        不得不“进步”时,就只能“进步”。有时工作需要就是如此,必须快速掌握新的东西,立即变成劳动成果。少有时间去看已经大概掌握的东西。

        但你若有闲暇,回头过一遍Java基础,研究下1.6、1.7、1.8各增加了什么新功能,以后学新的东西就会更快,也能少加点班。
        Avalon1:@匿蟒 我在想是不是有点太早了,毕竟说实话感觉自己能力一般般。像你说的那些面试题估计一开始看到也要懵比,感觉JAVA基础不是很好,以前认真学过c,不过仅仅课堂内容的,不够,JAVA我以为和c之类的差不多基本没咋学,就过了2遍吧就开始自学Android了。后面慢慢在工作中也回头补充了一些用到的知识,但是还是先有空继续深入一点研究下基础比较好对吧?
        匿蟒:@Avalon1 要优化代码架构,看《设计模式》;要优化代码质量,看《代码整洁之道》。
      • 孤诣:表示搬砖久了,排序也不会了😂
      • 1114329096b0:我好方😭
      • 向日葵的笑:你们公司要会python的吗。我四年后去你们公司现在大一。因为不是计科专业的感觉挺难受的。你们招聘会介意专业吗
        向日葵的笑:@匿蟒 嗯嗯。
        匿蟒:@抹茶与橙汁 不会太介意专业,实际上我就不是。关键看技术能力。

        Python,我们倒是用得比较少,也就写monkey测试,或其它小脚本时会用到。毕竟,Android上层是Java,下层是C/C++。
        不过,Python在很多领域广泛使用,也的确是一门值得掌握的语言。
      • biubiutoo:看的我慌的不行,大学学的热动,毕业后去电厂工作4个月,然后辞职了来到深圳报了个培训班学android,java基础实在烂,android也停留在能copy,改改代码,实现些功能上。不想去坑一些公司,但自己也要活着,贷款18000不是小数目,所以尽量多学一些东西,少坑一点...
        4d8b5e9eb887:@biubiutoo 是不是达内啊
        biubiutoo:@匿蟒 :grin:自然的,毕竟选择了这条路。已经在开始找工作了,还是得抱着学习的态度,,,我这上的培训班现在都是教你如何包装自己的简历,建立在欺骗的性质上,着实是破坏了这行的生态
        匿蟒:@biubiutoo 公司什么的,随便坑,但是不能坑自己。既然选择入这一行,就要夯实基础、充分准备,博取更好的进身之阶;不能得过且过、差不多就行,不然与之前何异?

        培训,自有其道理和价值,但最终还得靠自己。
        系统地自学,未必赢不过科班出身。
      • 5e617a504f6d:怎么感觉好像在写JavaScript… (逃
      • e9a44a336dfe:我的反应时间几乎是瞬间,也就是5秒内。另外代码上基本看不下去了,还有,你自己提供的代码也没考虑基本的并发。
      • fhammer:不知楼主是不是真的比较过LinkedList的遍历时迭代器快,还是foreach快啊
        匿蟒:@fhammer 你的了解比我深入。
        二者在高数量级的数据下,差距很可能在JVM那一层,远远超出了我的能力范畴。
        也许,你可以研究一下二者的字节码差异。
        fhammer:@匿蟒 感谢楼主热心,我也是最近正好看集合部分源码,比较了下各集合遍历效率,在linked list中虽然foreache实现是迭代器,但是我在十万数量级的数据二者遍历效率还是会相差百分之二十左右的,这只是我个人的实验结果可能和环境有关系,还没弄清楚,所以正好疑问,冒昧问出此问题,望见谅!谢谢回答
        匿蟒:@fhammer 看到这个问题,我且囧且疑惑。

        囧,是因为我确实没比过。疑惑,是因为for each难道不是用迭代器吗?
        如果for each使用错误,javac的提示是:
        > 要求: 数组或 java.lang.Iterable

        当然,此后我蛋疼地比较了下。在插入1000个随机int的情况下:
        for get: 81 ms (这就是我之前那坑爹的for循环里套get)
        for each: 7 ms
        Iterator: 7 ms

        增加到10000个,结果:
        (由于电脑的抗议,我那坑爹算法就注释掉了。)
        for each: 298 ms
        Iterator: 295 ms

        50000个,结果:
        for each: 12939 ms
        Iterator: 12867 ms

        总之,for each对Iterable,就是用Iterator来实现遍历的,二者的结果是同一量级。
      • 小阳撒:一点也不夸张。能在面的时候一般能做出来的都要了
      • ddf9b131c554:有意思。
      • 鲁大喵:至于吗……我一个转行的都看不下去了
      • 14cc0d315b86:现在想找个基础扎实的科班生 如此困难。。 楼主面的是985 211的吗?
        14cc0d315b86:@匿蟒 我是一所非985 211的学生 估计我身边的人也是90%写不出来。。大部分基础很差劲 确实是优秀概率的问题
        ZJ_Lavender:@20131301 985的不咋样,都那样的,主要靠自学
        匿蟒:@20131301 985必然没有,而211好像有两个吧(我一般不怎么看学历那一栏)。
        好学校的学生,确实优秀的概率高些,这一点毋庸置疑。不过嘛,概率……
      • VermoutHMC:我觉得《Thinking in Java》不适合做入门书籍。作者在书的第一章Introduction to Objects中也说过:This chapter, and this book, assumes that you have some programming experience, although not necessary in C.
        VermoutHMC:@袁志健 我是在高一的时候看的这本书,之前就看过一本java入门书,没有其他编程语言经验,当时的体验就是书中好多内容都是似懂非懂,现在上大学了,重新拿起这本书,才显得不那么吃力。如您所说,基础确实很重要。
        袁志健:@RoxyVermouth 一遍读不懂就多读几遍,我的大学和我的魔兽度过了4年什么也没学到。大四后半年因为找工作压力开始捧起thinking in Java 这本书让我在以后的工作中如鱼得水我甚至没有看过任何其他的Java书籍语言基础很重要
        匿蟒:@RoxyVermouth 有道理,很可能你才是对的。

        我是从C、C++、C#、再到Java,这条路爬上去的,所以觉得看这本书更高效、透彻。而自从“误入”Vim后,已经习惯了Learn sth in hard way。
        至于它是否真的适合没有编程经验的初学者,很惭愧,这辈子没机会亲身实践了。
      • 谷青_vm:楼主你好 我也是大三的在校生,android的话 网络基础问的多不多呢,因为我面试几次都没问到我网络方面的,大公司小公司都没有,但别人面经有些会写到,网络在android开发中重要吗
        谷青_vm:@匿蟒 了解了 谢谢啦
        匿蟒:@Enzo_dm 多不多其实不好说。

        Android的工作,做网络编程一般分两大类。一是用别人开发好的jar,比如其它公司的SDK(高德地图、百度翻译之类的),或自己公司包装好的jar;二是自己去写与服务器交互,比如你就是给自己公司包装jar的。
        如果面试官务实一点,做第一类的是不会问的(比如我、自己都说不清网络那些事),做第二类的才会。

        问的时候往往由浅入深。至于问多深,往往因人而异,也取决于你的工作需要做多深。
        我一个朋友就被某互联网公司问过:常用网络协议有哪些?它们有什么区别?如果我必须用不可靠协议,但一定要实现可靠的稳定传输,怎么办?
      • Irooie:大三在校生,看完博主的论文体会很深。
      • 088bceee8087:Java编程思想,并不适合入门
        ea0e4faf77c5:@匿蟒 我写了3年java 代码之后 才开始对设计 和对象思想有一定的操作能力和感悟,
        这还是github一堆开源和安卓源码的帮助下.顺带一提.我并不认为自己是傻瓜
        088bceee8087: @匿蟒 个人感觉就里面的内容而言更像进阶类的书籍,里面涉及到的内容很多不是一个编程新手就能理解的
        匿蟒:@如影相随 为什么呢?
      • 末无:我的一个同学想学编程,是学c/c++,还是让他和我一起学Java,(我一个朋友告诉我说c和c++入门简单)
      • 5a3c5b6ebe74:刚在培训班培训三周,Android的,有一定的基础,面试题以及后面的杀手锏没有觉着有什么难度(说实话,只说不写的话,这些问题问出来马上就能给出来答案,并发那块除外,还没有学到→_→),当然了,很可能是我刚学还没有忘记。。。。个人感觉吧,目前这个阶段,你要是问我内部类方面的东西,在里面绕几圈,百分之百要懵逼。顺带问一下,面试的时候要是问递归以及设计模式(就学明白了个单例,其他的呵呵。。。),怎么办,额,会问这个不。。。。
        匿蟒:@青青枫 是否考察设计模式,这因人而异。我不考,是因为不敢作太多要求。

        不过客观地说,做Android的人最好还是看过《设计模式》比较好,因为Android平台基本都是按照设计模式设计出来的。了解设计模式,至少会非常容易理解Android源码。
      • 8579b384877e:用二分查到位置再插入好一些,线性结构,单次logn。
        8579b384877e:@匿蟒 咦。。再问个问题啊。要是一个定长的arraylist做插入排序,查找用二分,那总复杂度是不是到nlogn了。。
        8579b384877e:@匿蟒 噢。对。。我傻了
        匿蟒:@Atlandis 这里其实有个小陷阱。
        LinkedList的插入复杂度是1,而查找复杂度则是n。它是无法实现二分查找的。
        ArrayList可以实现log(n)的二分查找,但是插入复杂度却是n,因为后面的都得依次往后挪。
        所以这道题,我没有用ArrayList,也没用二分查找。
      • e2e8e05822a5:虽然不用Java,俺还是看完了😔就算法的话,我宁愿多写几行代码维护一个堆;就教育的话,难道不知道现在随便弄一个demo就能毕业了么;就语言的话(这里没用任何语言鄙视的意思)大多数做Java相关工作的同学无非是JavaWeb和Android这些他们接受4个月培训就能“上岗”的
        justZero:@Angelas 我想过4个月秒上岗的人到底是什么原因来培训,可能大家心里都清楚。但是内功就是内功,有个能办事的壳而没有内在本事,时间一长肯定会垮的。进的快,死的也快~真不知培训机构的出现利弊谁大啊。
        匿蟒:@Angelas 没错,正是因为准入门槛太低,所以Java才良莠不齐。其实,即使是Java,也仍然需要逻辑清晰、基础扎实的人才能写好。

        至于堆,虽然保证了遍历的有序和插入的简单,查找复杂度log(n),非常适合这道题的意图。但是由于Heap不是java.util下的标准库,所以对C经验较少的Java程序员来说难于登天。
        (所以,从某些方面来说,俺们Java程序员被鄙视是有道理的。)

        鉴于去年HomeBrew作者在Google面试时写不出反转二叉树这件事,我根本不敢考非线性数据结构。
        (人人交白卷,Boss会杀了我的!)
      • 35e9c866b079:不理解,插入排序是很难的算法?
        匿蟒:@大秦谪仙 难者不会,会者不难。
        插入排序,在排序类算法里算简单的,也就比冒泡排序的认知难度高一点点。
        我这道题,其实只是插入排序的一半。

        我后来分析,难点有三:
        1. Android从业者,很多原先不是做Java的,甚至不是写代码的。他们入门就是Android,Java只是能大概认识。知道`onCreae`怎么复写,但不知道`@Override`是什么东西。
        2. 写代码太少,或没有接受过系统的训练,也缺乏创造力。给一段代码,可以修改、重构,但是给一张白纸,什么也写不出来。
        3. 部分应聘者年纪过大。他们没学过、或已经忘了这个基本算法,而且也失去了在15分钟内重新实现的能力。(现在我可能也体会不了,但可能五年、十年后,我的脑子也会这么笨吧。)

        归根结底,程序员的天梯是层级分明的,而我这家公司提供的条件,吸引不了一个能写出插入排序的程序员。(似乎黑得有点过头,心中惴惴。 :smirk:

        其实,你也可以给自己计时,看看能否在白纸上凭空写一个归并排序出来。
      • 末无:我还是个学Java的新手,Java是不是很难啊?
        末无:@匿蟒 谢谢
        匿蟒:@末无 相对Python、Ruby、PHP之类的,确实难多了;但相对C/C++,却非常简单。
        用《Java编程思想》入门,此后独立做点小项目;再看《Effective Java》,重新再优化一下;要到达“精通”不难。
      • ZJ_Lavender:额,大学学了Java和C++,然后现在大三,搞过两个月的ACM算法集训,然后大二一年因为失恋基本上荒废了,大三后来专业课知识都学了,都不精通~前两天面试腾讯刚挂,生无可恋,老老实实呆自习室复习准备考研
        8a515b588ff7:@ZJ_Lavender 😳同大三,目测你名校,我校acm培训都还是自己讲课,不过本身都是渣渣就不敢多讲,默默搞了两年acm
        谷青_vm:@匿蟒 大三也不早了,
        匿蟒:@ZJ_Lavender 面腾讯挂了就生无可恋,那千千万万像我这种去不了硅谷、进不了BAT的IT人,还怎么好好地过下半辈子?

        再面也好,考研也罢,如果想清楚了以后一定要吃这碗饭,那就趁早去GitHub报道。
        已经入职的要多看书,还在学校的要多实践。不管你用什么语言,去写一堆自用的软件吧。
        大三,不是还早吗?

      本文标题:一道简单的Java笔试题,但……

      本文链接:https://www.haomeiwen.com/subject/arkilttx.html