面试题真题解析(2)BJ Subway
北京地铁 Beijing Subway JAVA 开发面试题
简答题
一、请简述接口与抽象类的区别
相同:
1.不能够实例化(即不能new新对象)
2.可以将抽象类和接口类型作为引用类型
3.一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类
不同:
构造器: 抽象类中可以定义构造器。 接口中不能定义构造器
方法: 抽象类可以有抽象方法和具体方法。
接口中方法全部都是抽象方法,方法定义默认为public abstract修饰。
修饰词: 抽象类中的成员可以由 private、默认、 protected、public来修饰。
接口中的成员全都是 public 的。
成员变量: 抽象类中可以定义成员变量。
接口中定义的成员变量实际上都是常量,默认为 public static final修饰
抽象方法: 有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。
接口中全是抽象方法。(JDK8后可以有普通方法,但是必须由default修饰)
静态方法: 抽象类中可以包含静态方法。接口中不能有静态方法 。
继承与实现: 一个类只能继承一个抽象类。一个类可以实现多个接口。
二、请简述方法重载(overload)与重写(override)的区别
重载(Overload) 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
重写(Override) 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
三、请按顺序写下判断输出结果
1 Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.println(i==j);
2 Integer i2 = new Integer(199);
int j2 = 199;
System.out.println(i2==j2);
3 Integer i3 = new Integer(100);
Integer j3 = 100;
System.out.println(i3 == j3);
4 Integer i4 = 100;
Integer j4 = 100;
System.out.println(i4 == j4);
5 Integer i5 = 299;
Integer j5 = 299;
System.out.println(i5 == j5);
正确答案:false、true、false、true、false
Integer、new Integer() 和 int 的比较:
1、两个 new Integer() 变量比较,永远是 false。
原因:因为new生成的是两个对象,其内存地址不同。
2、Integer 变量 和 new Integer() 变量比较,永远为 false。
原因:因为 Integer 变量 指向的是 java 常量池 中的对象,而 new Integer() 的变量指向 堆中 新建的对象,两者在内存中的地址不同。
3、两个 Integer 变量比较,如果两个变量的值在区间 -128 到 127 之间,则比较结果为 true,如果两个变量的值不在此区间,则比较结果为 false 。
原因:java 对于 -128 到 127 之间的数,会直接从缓存中取,不会 new了。
4、int 变量 与 Integer、 new Integer() 比较时,只要两个的值是相等,则为true。
原因:因为包装类 Integer 和 基本数据类型 int 比较时,java会自动拆包装为 int ,然后进行比较,实际上就变为两个 int 变量的比较。
四、一下代码可以正确运行么,如果可以,运行结果是什么,如果不可以,为什么?
public static final class Person{
private String name;
private String sex;
public Person(String name, String sex) {
this.name = name;
this.sex = sex;
}
}
public static class Man extends Person{
private String name;
private String sex;
public Man(String name, String sex) {
super(name, sex);
}
}
public static void main(String[] args) {
Person person = new Man("zhangsan","nan");
System.out.println(person.getName());
}
正确答案:
能否运行? 不能
1、static final 修饰的类不能被继承:Man 类无法继承 Person 类。
2、上面 Person 类中没有 get 方法。
五、以下代码可能输出的结果是什么?
private static volatile int count = 0;
private static class AddCount extends Thread {
@Override
public void run(){
for (int i = 0; i<10000; i++){
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
AddCount addCount1 = new AddCount();
AddCount addCount2 = new AddCount();
addCount1.start();
addCount2.start();
Thread.sleep(2000);
System.out.println(count);
}
正确答案:
可能输出的结果:20000
两个线程同步运行,每个线程各加10000次,所以结果20000。
六、以下代码中,spring 应用定义了一个 init 函数,请问这里有必要加锁么,为什么?
/**
* 用户信息缓存
* @author dali
*/
@Service
public class AdminUserStorage{
/**
* 缓存系统管理员用户信息,key:userId,value:User
*/
private Map<String,User> adminUserMapCache = new ConcurrentHashMap<>();
@PostConstruct
public void init(){
synchronized(this){
getAdminUserFromDbAndCacheIt();
}
}......
}
正确答案:不懂
七、请写出以下代码运行后输出内容
public class ParentBean {
static {
System.out.println("父类静态块");
}
{
System.out.println("父类非静态块");
}
}
public class ChildBean extends ParentBean {
static {
System.out.println("子类静态块");
}
{
System.out.println("子类非静态块");
}
public ChildBean () {
System.out.println("子类构造方法");
}
public static void main(String[] args) {
ChildBean childBean = new ChildBean();
}
}
正确答案:
“父类静态块”
“子类静态块”
“父类非静态块”
“子类非静态块”
“子类构造方法”
八、假设这是基于 mysql 数据库的一条建表语句,数据表中已有大量数据
CREATE TABLE `user` (
`id` int(11) DEFAULT NULL COMMENT '姓名',
`name` varchar(2) DEFAULT NULL COMMENT '性别',
`sex` varchar(3) DEFAULT NULL COMMENT '年龄',
`id_card_num` varchar(20) DEFAULT NULL COMMENT '身份证号',
`password` varchar(20) DEFAULT NULL COMMENT '密码',
`nick_name` varchar(20) DEFAULT NULL COMMENT '昵称',
KEY `index_id_card` (`id_card_num`,`name`) USING BTREE,
KEY `index_age` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
请问,下面的查询语句,会走索引么,为什么?
1.
select * from `user` where `name` = '张三';
2.
select * from `user` where id_card_num = '123123199911019283';
3.
select * from `user` where age > 10;
正确答案:
1、不会,没有创建 name 的索引
2、会,根据最左特性 index_id_card 索引中默认加载了 id_card_num
3、会,已加载 age 索引
九、反转一个单链表
示例:
输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
答案参考:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode newHead = null;
ListNode prev = null;
while (cur!=null) {
ListNode curNext = cur.next;
if (curNext==null) {
newHead = cur;
}
cur.next = prev;
prev = cur;
cur = curNext;
}
return newHead;
}
}
十、给定两个字符串 s 和 t,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入:s = "abcd" , t = "dcba"
输出:true
示例 2:
输入:s = "rat" , t = "car"
输出:false
字母异位词就是说,两个字符串 s,t 中所包含的字母与字母出现的次数完全一样,
就像示例 1 中,s 与 t 中出现的字母都只有 abcd ,且这些字母都只出现了 1 次。
你可以假设字符串只包含小写字母。
思路:
-
首先用户输入要比较的字符 s 和 t。
-
我们设定一个 int 数组,大小为 26,对应英文中的 26 个英文字母。
-
将 s 和 t 字符串转成 char 数组,之后分别遍历两个数组。
-
遍历 s 时,每当一个英文字母出现时就在该字母在 int 数组所对应的值 +1。
-
遍历 t 时,每当一个英文字母出现时就在该字母在 int 数组所对应的值 -1。
-
这样判断以后,遍历 int 数组判断是否有非 0 数字:
若有,则证明存在没有被正负抵消的字母,即 s,t 不是字母异位词。
若没有,则证明所有字母都被正负抵消,即 s,t 是字母异位词。
答案示例:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("s:");
String s = scanner.nextLine();
System.out.println("t:");
String t = scanner.nextLine();
int[]arr = new int[26];
char[]sChar = s.toCharArray();
char[]tChar = t.toCharArray();
for (int i=0;i<s.length();i++){
arr[sChar[i]-97] += 1;
}
for (int j=0;j<t.length();j++){
arr[tChar[j]-97] -= 1;
}
for (int k=0;k<arr.length;k++){
if (arr[k]!=0){
System.out.println("不不不是字母异位词!");
return;
}
}
System.out.println("是是是是字母异位词!");
}
吐槽:(不愧是北京地铁,真勾八难啊)