简介:金航数码Java初级笔试题资源,适合正在准备Java技术面试的初级开发者和学生巩固基础。资源为1份doc文档,共98KB,包含11道典型选择题,覆盖循环控制、字符串连接、变量命名、抽象方法、继承、数组类型转换、异常处理等核心知识点。每道题均提供参考答案和详细解析,如do-while循环的执行流程、字符串拼接结果、变量名合法规则、抽象方法声明要求、父类子类关系等,并阐明易混淆的编译错误与输出顺序问题。通过这套题目,读者可以快速检验对Java语法和面向对象特性的掌握程度。已有395人学习,适合用来做考前自测或知识点查漏补缺。
1. 金航数码java笔试题:先弄懂失分点再刷题,不然容易翻车
金航数码java笔试题这套卷子,选择题前几道全是“看着简单、一选就错”的套路题。比如那道 do-while 循环,很多人选 2 或者 5,标准答案却是 -1——循环体先执行、条件再判断,i 被反复整除到自己减到负数,这就是初级笔试最典型的失分点。整套题覆盖循环控制、字符串拼接、变量命名、抽象类、继承初始化、异常匹配、线程基础,再加上字符串排序、递归、SQL 和单例四道上机题。考的是 Java 语法细节和面向对象基本功,不考框架不考源码,适合准备初级开发岗笔试的人拿来当自测卷。想拿分,不能只背结论,得把每个选项为什么错拆出来练。
2. 语法与循环陷阱:单选前几题的高频考点
这套笔试题的选择题前 7 道,几乎把 Java 基础语法里最容易挖坑的点都考了一遍:字符串拼接、标识符合法性、do-while 边界、for 循环作用域、数组强转。这些题的共同特点是:代码很短,答案很反直觉,错的人还特别多。下面按考点逐题拆。
2.1 字符串拼接与变量命名:两道送分题其实是送命题
第 2 题:String s = "Hello" + 9 + 1;输出什么?答案是 Hello91。很多人以为 Java 会像数学表达式一样先算9 + 1 = 10,再拼出 Hello10。实际上加号运算符从左到右结合,第一个加号左边是字符串,整个表达式就变成字符串拼接,后面的 9 和 1 都会被转成字符串依次拼上去。判断依据只有一条:只要有字符串参与+,结果就是字符串,除非加括号改变结合顺序。
第 3 题考查标识符命名规则,问#name、$age、_height、~temp里有几处编译错误。答案是 2 处,#name和~temp非法,$age和_height合法。Java 标识符只能以字母、$、_开头,后面可以跟数字;#和~都不是合法字符。这类题没有技巧,就记两条规则:开头是什么、中间能含什么。答题时把四个变量名逐个过一遍,别凭印象选“含下划线都错”。
第 7 题考的是数组与 Object 引用的转换。Object obj = new int[]{1,2,3};合法,因为数组本身就是对象;int[] someArray = (int[])obj;是向下强转,编译器允许;for (int i : someArray)遍历输出 1 2 3。这题容易误选“编译失败”,实际上从 int[] 转到 Object 是向上转型,转回来也是合法的,只有类型不匹配才会抛 ClassCastException。答这类题,先确认转型方向,再确认运行时类型是否一致。
2.2 do-while 与 for:循环边界是重灾区
第 1 题是整张卷子反直觉程度最高的一道:int i = 10; do { i = i / 2; } while (i-- > 1); System.out.println(i);。推演过程要写成表格才不容易错:i 初始 10,进循环体变成 5,条件5 > 1成立,i 自减成 4;再进循环体变成 2,条件2 > 1成立,i 自减成 1;第三次进循环体,1 / 2在整数除法下等于 0,条件0 > 1不成立,但 i 还要自减一次变成 -1,循环结束,打印 -1。关键点在最后一步:即使条件不成立,i--也会执行。
第 6 题是 for 循环加 break 的作用域陷阱。代码是for (int i = 0; i <= 10; i++) { if (i > 6) break; } System.out.println(i);,正确答案是 Compilation fails。i声明在 for 循环的初始化部分,作用域只在循环体内部,循环结束后println(i)根本访问不到它。如果把int i提到 for 外面,输出才是 7:i 从 0 加到 7,发现i > 6成立,break,此时 i 已经是 7。这题同时考 break 时机和作用域,答题时先找变量声明位置,再看 break 是跳出哪一层。
2.3 数组强转与字符串排序:选择题和上机题连起来看
第 7 题背后的知识点,在上机题第 21 题里会以另一种形式出现:对字符串"100,10,1,0,15,20"里的数字升序排列。这里的坑是,如果直接对字符串排序,"100"会排在"15"前面,因为字符串比较逐字符比,"1"小于"1"之外还得看下一位,结果完全不对。正确做法是先按逗号分隔,再转成 int,排序后重新拼接。核心代码如下:
public static String sort(String args) { String[] parts = args.split(","); int[] nums = new int[parts.length]; for (int i = 0; i < parts.length; i++) { nums[i] = Integer.parseInt(parts[i]); } Arrays.sort(nums); StringBuilder sb = new StringBuilder(); for (int i = 0; i < nums.length; i++) { if (i > 0) sb.append(","); sb.append(nums[i]); } return sb.toString(); }split(",")按逗号切分得到字符串数组,Integer.parseInt逐个转 int,这一步解决了字符串比较的错误顺序;Arrays.sort默认升序排序;最后用 StringBuilder 拼接,避免直接+造成多次创建对象。这道题的分值点不在排序本身,而在“是否记得先转 int”,直接对字符串排序是笔试里最常见翻车方式。
3. 面向对象高频考点:继承、抽象类与构造器
这套题从第 4 题到第 19 题,密集考查继承关系、抽象方法、构造器、静态成员初始化顺序,以及设计模式两大主题。这一章是整张卷子分值最重的部分,单选 20 题里有 9 题落在面向对象范围。这些题单看都简单,合在一起就考你有没有真正理解 Java 的类加载和实例化顺序。
3.1 继承关系与构造器执行顺序
第 5 题问子类和父类的数量关系,选 C:一个子类可以有一个父类,一个父类可以有多个子类。Java 单继承,一个类只能有一个直接父类,但一个父类可以派生多个子类。第 16 题考继承本质,错误的是 D:继承是白盒复用,父类的修改会影响子类,所以“对父类的修改不会影响到子类”本身就是错误表述。这两题属于纯概念,背熟就能拿分。
第 8 题考构造器调用顺序:class Base { Base() { System.out.print("Base"); } },Alpha 继承 Base,main 里依次new Alpha()和new Base()。创建子类对象时,JVM 会先调用父类构造器,再执行子类构造器,所以new Alpha()先输出 Base;new Base()再输出一个 Base,结果是 BaseBase。答题关键:子类构造器第一条语句默认是super(),即使不写也存在。
第 12 题是继承初始化顺序的综合题,考察静态成员、实例成员、构造器的执行先后。推演顺序是:类加载阶段先执行父类静态成员初始化,输出 Super1;main 方法里new Sub(2)时,先初始化父类实例成员,输出 Super3;再调用父类构造器super(2),输出 Super2;最后执行子类构造器剩余部分,输出 Sub2。完整结果是 Super1,Super3,Super2,Sub2。为什么静态成员先执行?因为静态属于类,在类加载时就完成初始化,而实例成员和构造器属于对象,只有 new 的时候才触发;构造器内部,父类实例变量初始化又在父类构造器调用之前,顺序是静态块、父类实例变量、父类构造器、子类实例变量、子类构造器。
3.2 抽象方法、抽象类与继承的边界
第 4 题是抽象方法的语法题,选 D:声明抽象方法不可写出大括号。抽象方法没有方法体,abstract void amethod();以分号结尾,不能带{}。B 和 C 都在说抽象方法可以有方法体,与定义矛盾。第 13 题进一步考抽象类的继承约束:MineBase 里声明了抽象方法amethod(),Sub 继承它却没有实现,编译直接报错。规则是:抽象类可以拥有未实现方法,非抽象子类必须实现所有抽象方法,否则子类也必须声明为 abstract。这道题很多人只看 main 方法里的循环逻辑,忽略了类声明本身不合法。
第 19 题考构造器返回类型,问错误的是哪一项,答案是 A。构造函数不能声明任何返回类型,包括 void。如果写了void 类名(),它就不再是构造器,而是一个普通方法,方法名恰好和类名相同,但不符合构造器语法。B、C、D 说的是构造器特征:方法名与类名相同、用于初始化对象、new 对象时自动调用,这些都对。
3.3 设计原则与设计模式:概念题也是分
第 14 题考开闭原则,选 A:对扩展开放,对修改关闭。这是软件设计里最基础的一条原则,意思是新增功能时优先通过扩展实现,而不是去改动已验证的旧代码。第 15 题考设计模式两大主题,选 B:对象组合与类的继承。设计模式的核心就是处理“复用”的两种方式——继承是白盒复用,组合是黑盒复用。这两题不需要背具体模式,但得把开闭原则和组合/继承的定位说清楚,面试追问时能举例:比如策略模式用组合替代继承来应对算法变化。
3.4 上机题 24:单例模式的两种写法
第 24 题要求手写单例,原题给出的懒汉式实现有一个明显的线程安全问题。多线程同时调用getInstance(),可能创建多个实例。笔试能写出基本版只能算及格,想拿高分要补上同步控制:
class Singleton { private static Singleton s; private Singleton() {} public static synchronized Singleton getInstance() { if (s == null) { s = new Singleton(); } return s; } }关键在于三件事:构造器私有,防止外部 new;静态变量保存唯一实例;静态方法提供全局访问点。synchronized加在方法上,保证同一时刻只有一个线程进入创建逻辑。初级笔试一般不要求写双重检查锁或枚举单例,但如果面试官追问“懒汉式缺点”,能答出“性能损耗大、需要加锁”“也可以改用饿汉式静态初始化”就能加印象分。这道题的评分重点是:私有构造器有没有写、静态变量有没有写、getInstance 是不是 static、是不是 public,缺一个都会扣分。
4. 异常、线程与程序行为:控制流题怎么答
第 10 题到第 20 题里,异常处理、异常继承匹配、线程执行体和同步锁是另一组高频考点。这类题的答题方式和语法题不同:语法题靠记忆规则,行为题必须手动模拟执行路径,从异常抛出点开始,把 catch 和 finally 的顺序一步步走完,不能只记“finally 一定执行”这一句话。
4.1 try-catch-finally:输出顺序不能靠猜
第 10 题是异常控制流的典型题:method1()里执行int i = 10 / 0,抛出 ArithmeticException。进入 catch 块打印 B,finally 块无条件执行打印 C,最后方法不中断,继续打印 D,结果是 BCD。容易错的地方有两个:一是漏掉 finally,以为异常后程序直接终止;二是漏掉 D,以为 catch 捕获异常后 main 方法就结束了。实际上 try-catch-finally 的常规路径是:try 抛异常、catch 捕获处理、finally 收尾、整个方法继续向下执行。还有一个隐藏考点:ArithmeticException 属于 RuntimeException,不需要显式声明 throws,所以代码可以编译通过,不会选到编译失败。
4.2 异常的继承匹配:catch 按就近类型
第 11 题考异常类型匹配:Exc1 extends Exc0,Exc0 extends Exception,代码里throw new Exc1(),catch 块第一个是catch (Exc0),第二个是catch (Exception)。结果输出 Ex0 caught。原因是异常匹配按 catch 块从上到下,找第一个能接收该异常类型的块。Exc1 是 Exc0 的子类,能被 Exc0 引用接收,所以直接命中第一个 catch。如果把两个 catch 顺序调换,Exception 在前,所有异常都会被它接住,Exc0 的 catch 永远执行不到,这就是“子类异常必须写在父类前面”的规则来源。答这题时,先画出异常类的继承树,再从 catch 列表头开始比对。
4.3 线程基础:run、synchronized、static 三个送分题
第 17 题问线程执行体定义方法,选 C:run()。start() 是启动线程的方法,真正在新线程里执行的代码写在 run() 里,直接调用 run() 不会启动新线程,只是普通方法调用。第 18 题问互斥锁关键字,选 D:synchronized。transient 用于序列化时跳过字段,static 表示类成员,serialize 不是关键字。第 20 题问通过类名直接调用的方法用哪个关键字修饰,选 A:static。static 方法属于类本身,不需要实例即可调用;final 只是不可重写,private 是私有,void 是返回类型。这三题如果错,多半是概念混淆:把 Thread 的 run 和 start 记反,或者把 synchronized 和 volatile 混在一起。初级笔试不要求写线程代码,但要求能准确说清“执行体是 run(),启动是 start(),互斥是 synchronized”。
4.4 递归上机题:先把终止条件写对
第 22 题是斐波那契数列:求第 30 位数,递归实现。原题给出的解法是典型的两行代码:
static int computeNum(int index) { return index <= 2 ? 1 : computeNum(index - 1) + computeNum(index - 2); }递归题拿分的核心是终止条件和递推关系。index <= 2返回 1,是前两个基准值;computeNum(index - 1) + computeNum(index - 2)是递推关系,把第 n 位拆成前两位之和。这道题要注意两点:一是在纸上手算时别真的展开到第 30 层,写出代码后用循环递推检查结果;二是如果面试官追问性能,能说出“递归有大量重复计算,第 30 位会有指数级调用,可以用数组存中间结果改成动态规划”。答案是 832040,笔试时写对递归形式就能拿到大部分分,数值算错只扣最后结果分。
5. 易错题专项:这套卷最容易丢分的 5 类题
把整套题过完一遍再看失分点。这 5 类题几乎覆盖了初级笔试的大部分扣分项,每一类都按“错在哪、为什么错、怎么答对”来复盘。
5.1 字符串拼接选错 Hello10
错在哪:看到"Hello" + 9 + 1,很多人想当然先算 9+1,选 Hello10。为什么错:Java 的加号从左到右结合,第一段"Hello" + 9已经是字符串拼接,结果还是字符串,再接+ 1继续拼接。只要表达式里出现字符串,后续所有加号都变成连接操作,不存在“先算数字”的机会。怎么答对:看到字符串加数字,立刻判断第一个操作数是不是字符串;如果是,整段都是拼接,答案 Hello91。想算数字必须写括号,比如"Hello" + (9 + 1)。
5.2 do-while 循环推到 -1
错在哪:这道题在循环条件上栽跟头,常见错选 0 或 2。为什么错:有人按 while 循环的习惯先判断后执行,有人忽略了i--这个后缀自减在条件不成立时也会执行。推进到第三次循环时,循环体内1 / 2整数除法得 0,条件0 > 1为 false,但i--仍然把 0 变成 -1。怎么答对:统一用表格推演,每一轮记录“进入循环体前 i 的值、循环体执行后 i 的值、条件判断使用的值、自减后 i 的值”四列,把三次循环完整走完,答案不会再错。
5.3 for 循环变量作用域导致编译失败
错在哪:看到for (int i = 0...)后面直接System.out.println(i),以为输出 7。为什么错:i 的作用域限定在 for 循环内部,循环结束后变量就消失了,编译器找不到名为 i 的变量,直接报编译失败。很多人只分析 break 的时机,忘了先检查变量是否可见。怎么答对:拿到代码先画变量作用域边界,for 初始化部分声明的变量只活在循环体里;如果变量在外层声明,再讨论 break 时的值——i加到 7 触发 break,输出 7,但本题的 i 并不在外层。作用域错误优先于逻辑分析。
5.4 抽象方法与构造器的大括号规则混淆
错在哪:抽象方法到底能不能有大括号、构造器返回类型能不能写 void,这两条经常记混。为什么错:抽象方法没有方法体,所以不能有{},题目第 4 题选 D;构造器不能声明返回类型,写了 void 反而不是构造器,题目第 19 题选 A。两个限制方向相反,放在一起考时最容易互相干扰。怎么答对:记死两句话——抽象方法是“不能有大括号的分号结尾”,构造器是“不能有任何返回类型”。看到选项里出现“void 类型”描述构造器,直接判定错误。
5.5 继承初始化顺序:静态先于实例,父类先于子类
错在哪:第 12 题很多人输出 Super1,Super2,Super3,Sub2,把父类实例变量和父类构造器顺序搞反。为什么错:实例化 Sub 时,JVM 先初始化父类实例成员,也就是Super s2 = new Super(3)这个字段,输出 Super3,然后才执行构造器里的super(i),输出 Super2。实例变量初始化发生在构造器调用之前,这一点容易被忽略。怎么答对:按三层顺序走——类加载阶段做静态初始化(Super1),new 对象阶段先父类实例变量、再父类构造器(Super3、Super2),最后子类构造器(Sub2)。遇到继承加静态的组合题,先拆层,再逐层补输出。
6. SQL 上机题答题模板与整卷收分习惯
上机题第 23 题是 SQL 三连问,考的是子查询、分组过滤和连表聚合,这是初级笔试上机题里最稳的得分点,也是最后一道需要完整手写的题。三个问题对应三个模板。
第一问“薪金比张平多的员工姓名”,用标量子查询:先查出张平的薪金,再查所有比它高的员工。第二问“最低薪金大于 2000 的职位”,必须先按 job 分组,再对 min(sal) 做条件过滤,注意不能写成WHERE sal > 2000,那是过滤员工业绩,不是过滤职位。第三问“每个部门的部门名称、员工数量和平均薪水”,用左连接,把没有员工的部门也保留下来,按部门编号分组,同时统计数量和平均薪水。
-- 第一问:子查询 SELECT Ename FROM EMP WHERE Sal > (SELECT Sal FROM EMP WHERE Ename = '张平'); -- 第二问:分组后过滤最低薪金 SELECT job FROM EMP GROUP BY job HAVING MIN(sal) > 2000; -- 第三问:左连接保留无员工部门 SELECT d.dname, COUNT(e.empno) AS 员工数量, AVG(e.sal) AS 平均薪水 FROM DEPT d LEFT JOIN EMP e ON d.deptno = e.deptno GROUP BY d.deptno, d.dname;第二问是最容易翻车的:用WHERE sal > 2000会查出所有薪金高于 2000 的员工职位,业务员孙小平薪金 2100 也会被算进来,但业务员的最低薪金是 1850,并不满足“最低薪金大于 2000”。HAVING 是对分组后的聚合结果做条件判断,这才是题干的真实含义。手写 SQL 时 GROUP BY 的列名要和 SELECT 里非聚合列保持一致,第三问里部门表用 LEFT JOIN 是为了让市场部这种没有员工的部门也能出现在结果里,如果只写 inner join 就会漏行,平均薪水字段记得取 e.sal 而不是 d.deptno,原题参考写法里把 avg 用在 deptno 上就是明显笔误。
这套卷子整体刷下来,我的习惯是拿到题先快速过一遍上机题:单例模式、递归、SQL 三问都是模板型题目,先写完保底分,再回头做选择题。选择题里凡是出现循环、继承、异常这三类,一律在草稿纸上画执行顺序表,不直接凭感觉选。从那以后我每次刷这种初级笔试题,都强制自己把流程走完整:先看作用域,再推执行顺序,最后检查异常路径。这套题的价值不在答案,而在把 Java 基础里最容易失分的角落挨个暴露一遍,提前踩过坑,面试场上就不会再犯。希望帮到你。
本文还有配套的精品资源,点击获取