以下是本人在以往的后端面试中遇到的一些题目的小整理,答案和分析仅供参考,未必正确,如果发现有错误的地方,欢迎指出。
1、有8个球,其中有1个重一点,其它的球都一样重,现在只有1个天平,怎么只称2次就找出那个重一点的球?
答:
称第一次:随机取6个球出来,两边3个球放到天平上称。
称第二次:若称第一次时天平显示两边一样重,那称剩下的2个球就能找出那个重一点的球了;若天平显示一边重,那就从天平重的那边的3个球中随机取2个球放到天平上称,如果天平显示一边重,那重的那边的那个球就是那个重一点的球,如果天平显示两边一样重,那剩下的没称的那个球就是那个重一点的球。
2、输出1-100之间的素数。
答:
import java.lang.Math;
/**
* 输出1-100之间的素数
*/
public class PrimeNumber {
public static void main(String[] args) {
boolean flag = true;
for (int i = 2; i <= 100; ++i) {
flag = true;
for (int j = 2; j <= Math.sqrt(i); ++j) {
// 若发现有被整除的,就是不是素数,马上标记为false,并且中断循环
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
System.out.println(i);
}
}
}
}
运行结果:
1-100素数
3、输入1个整数,输出该数二进制表示中1的个数。
答:
import java.util.Scanner;
/**
* 输入一个整数,输出该数二进制表示中1的个数
*/
public class StatisticsOne {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("please input an integer:");
int n = scanner.nextInt();
scanner.close();
// 若是负数,就转换为正数
if (n < 0) {
n = n / (-1);
}
int m = 0;
// 通过“除2取余,逆序排列法”算出整数对应的二进制数
// 每求出一个位数的数字就判断是否为1
// 求出的二进制数是倒过来的,但这里只需统计二进制数中1的个数,倒过来没影响
do {
// 对2求余一次就得到一个二进制位数的数字
int rem = n % 2;
if (rem == 1) {
++m;
}
// 不断地除2,直到除2到商为0
n = n / 2;
} while (n > 0);
System.out.println("this integer contains " + m + " integer one");
}
}
运行结果:
统计整数二进制中1的个数
用计算器验证下84516645,
验证整数二进制中1的个数 验证整数二进制中1的个数2
刚好13个1,正确。
4、写出题目中的运行结果。
public class HelloB extends HelloA {
public HelloB() {
System.out.println("HelloB");
}
{
System.out.println("I'm B class");
}
static {
System.out.println("static B");
}
public static void main(String[] args) {
System.out.println("-------main start-------");
new HelloB();
new HelloB();
System.out.println("-------main end-------");
}
}
class HelloA {
public HelloA() {
System.out.println("HelloA");
}
{
System.out.println("I'm A class");
}
static {
System.out.println("static A");
}
}
答:
HelloB输出
分析:
1)首先加载两个类的静态代码块,先加载父类HelloA的静态代码块,再加载子类HelloB的静态代码块。
2)执行System.out.println("-------main start-------")。
3)执行new HelloB(),会先加载HelloB的父类HelloA,所以会先加载HelloA的代码块System.out.println("I'm A class"),然后加载HelloA的构造方法System.out.println("HelloA");之后才是加载HelloB的代码块System.out.println("I'm B class"),然后加载HelloB的构造方法System.out.println("HelloB")。
4)再次执行new HelloB(),同3)。
5)执行System.out.println("-------main end-------")。
5、写出题目中的运行结果。
public class Test {
static {
int x = 5;
}
static int x, y;
public static void main(String[] args) {
x--;
myMethod();
System.out.println(x + y++ + x);
System.out.println(y);
}
public static void myMethod() {
y = x++ + ++x;
}
}
答:
Test输出
分析:
1)首先加载Test类的静态块int x = 5,然后加载静态变量static int x, y,这时x的值被重置为0,y的值被初始化为0。
2)然后执行x--,x的值为-1。
3)再执行myMethod方法,第一个加数x++是后置自增的,自增是后执行的,先确定第一个加数的值为-1,然后x的值再自增为0;第二个加数++x是前置自增的,自增是先执行的,先自增x的值为1,然后确定第二个加数的值为1;所以经过myMethod方法后,y的值是-1+1=0,x的值是1。
4)执行System.out.println(x + y++ + x),第一个加数和第三个加数的值都为x=1;第二个加数y++是后置自增的,自增是后执行的,先确定第二个加数的值为0,然后y的值再自增为1;所以是1+0+1=2,输出2,但这时的y的值是1了。
5)执行System.out.println(y),输出1。
6、写出题目中的运行结果。
第一小题:
public class TestString {
public static void test(String str) {
str = "World";
}
public static void main(String[] args) {
String string = "Hello";
test(string);
System.out.println(string);
}
}
第二小题:
public class TestStringBuffer {
public static void test(StringBuffer str) {
str.append(", World!");
}
public static void main(String[] args) {
StringBuffer string = new StringBuffer("Hello");
test(string);
System.out.println(string);
}
}
答:
第一小题:
TestString输出
分析:没有改变原来的值,因为String是final对象,值被赋予后就不能变的了,当执行String string = "Hello"时,常量池生成字符串"Hello",并且string指向字符串"Hello";当执行test(string)方法时,通过引用传递传递对象的引用给函数参数,函数参数得到一份对象引用的备份,也就是String str = string,一开始时str还是指向字符串"Hello",但执行了str = "World"后,常量池就生成新字符串"World"并且str指向了新字符串"World";当执行System.out.println(string)时,jvm会去寻找string指向的字符串对象,string指向的字符串还是原来的"Hello",所以输出的是"Hello"。
第二小题:
TestStringBuilder输出
分析:改变了原来的值,因为string指向的还是同一个对象,只是这个对象的内容被添加了新的内容。这里和上一题的区别就是,上一题因为执行了str = "World"故函数里的引用指向了另一个对象,而这里执行str.append(", World!")操作的还是同一个对象。
7、用两个栈来实现队列的功能offer(入队)和poll(出队)。
答:
import java.util.Stack;
/**
* 用两个栈实现一个队列
*/
public class StackQueue<T> {
Stack<T> stack1 = new Stack<>();
Stack<T> stack2 = new Stack<>();
public static void main(String[] args) {
StackQueue<Integer> stackQueue = new StackQueue<>();
stackQueue.offer(1);
stackQueue.offer(2);
stackQueue.offer(3);
System.out.println(stackQueue.poll());
System.out.println(stackQueue.poll());
stackQueue.offer(4);
stackQueue.offer(5);
System.out.println(stackQueue.poll());
System.out.println(stackQueue.poll());
System.out.println(stackQueue.poll());
}
/**
* 插入元素
*/
public boolean offer(T element) {
stack1.push(element);
return true;
}
/**
* 取出元素
*/
public T poll() {
// 若stack2为空,把stack1的元素全部pop出,stack1每pop出一个就push一个到stack2,直到stack1为空
if (stack2.isEmpty()) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
// 若stack2不为空,直接pop出元素
return stack2.pop();
}
}
运行结果:
StackQueue输出
分析:第一个stack存入队的元素,因为只能用栈来解决,这样顺序就反了,所以就要引入第二个stack。若要出队元素,就从第二个stack取出(pop);若发现第二个stack没有元素,就从第一个stack取元素出来放到第二个stack,每从第一个stack取出(pop)一个元素就放进(push)第二个stack,直到第一个stack的元素被取完,再从第二个stack取出(pop)元素。
8、单例模式怎么写?
答:
懒汉模式:
/**
* 单例模式(懒汉模式),即内部对象一开始是null
*/
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {
}
public synchronized static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
饿汉模式:
/**
* 单例模式(饿汉模式),即内部对象一开始就实例化了
*/
public class SingletonHungary {
private static SingletonHungary instance = new SingletonHungary();
private SingletonHungary() {
}
public synchronized static SingletonHungary getInstance() {
return instance;
}
}
运行测试:
单例模式测试
分析:懒汉模式是懒加载实例,初始化时实例引用还是null,等到需要时实例引用才指向实例;饿汉模式是预加载实例,初始化时实例引用就指向了实例。
9、请用1条sql语句通过下表查出以下结果。
game表:
time result
2018-07-27 负
2018-07-27 胜
2018-07-27 胜
2018-07-28 胜
2018-07-28 负
查询结果如下:
时间 胜 负
2018-07-27 2 1
2018-07-28 1 1
答:
方法一(sum函数法):
select time as '时间', sum(case result when '胜' then 1 else 0 end) as ' 胜', sum(case result when '负' then 1 else 0 end) as '负' from game group by time;
运行结果:
查game表的胜负次数(sum函数法)
分析:先以time为条件对game表分组,再用sum函数对每组结果进行一定的统计,sum(case result when '胜' then 1 else 0 end)即以result为条件,当result的值为'胜'时就是1,否则就是0,通过这样的方式就能统计出每组中胜的次数,同样地sum(case result when '负' then 1 else 0 end)统计出每组中负的次数。
方法二(子查询法):
select time as '时间', (select count(*) from game where time = t.time and result = '胜') as '胜', (select count(*) from game where time = t.time and result = '负') as '负' from game as t group by time;
运行结果:
查game表的胜负次数(子查询法)
分析:先以time为条件对game表分组,并且给game表命名为t表,'胜'这一列通过一个子查询决定,子查询再查一次game表,result的值要等于'胜',time的值要等于t表的time,当t.time=2018-07-27时,就是select count() from game where time = '2018-07-27' and result = '胜',正好是2018-07-27的胜的次数;当t.time=2018-07-28时,就是select count() from game where time = '2018-07-28' and result = '胜',正好是2018-07-28的胜的次数;'负'这一列同样这样查询出来。
方法三(联表法):
select a.time as '时间', a.胜, b.负 from (select time, count(*) as '胜' from game where result = '胜' group by time) a join (select time, count(*) as '负' from game where result = '负' group by time) b on a.time = b.time;
运行结果:
查game表的胜负次数(联表法)
分析:其实这里就是把结果拆成两块,最后再横向合并在一起。select time, count() as '胜' from game where result = '胜' group by time这句先筛选出game表中所有'胜'的结果,再以time为条件分组,统计出来就是每组中胜的次数;select time, count() as '负' from game where result = '负' group by time这句先筛选出game表中所有'负'的结果,再以time为条件分组,统计出来就是每组中负的次数;最后通过join on以time为条件把两表合并在一起,这样每组中胜的次数和每组中负的次数都有了。
以下做法是错误的:
select time as '时间', count(result = '胜') as '胜', count(result = '负') as '负' from game group by time;
运行结果:
查game表的胜负次数(错误做法)
分析:因为count只能统计某一列的个数,还不能用列的值作为条件,这里的count(result = '胜')估计会被解释成count(result)。
10、Java中List和Array是怎样相互转换的?
答:
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/**
* List和Array的互相转换
*/
public class ListAndArray {
public static void main(String[] args) {
listToArray();
arrayToList();
arrayToList2();
arrayToList3();
}
/**
* List转Array(利用List的toArray方法实现List转Array)
*/
private static void listToArray() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Integer[] array = list.toArray(new Integer[list.size()]);
for (int i = 0; i < array.length; ++i) {
System.out.print(array[i] + " ");
}
System.out.println();
}
/**
* Array转List方法1(直接使用Arrays的asList方法实现Array转List)
* 该方法存在一定的弊端,返回的list是Arrays里面的一个静态内部类
* 该类并未实现add、remove方法,因此在使用时存在局限性
* 该ArrayList并非java.util.ArrayList
*/
private static void arrayToList() {
Integer[] array = {4, 5, 6};
List<Integer> list = Arrays.asList(array);
System.out.println(list);
}
/**
* Array转List方法2(利用ArrayList的构造方法来实现Array转List)
* (最简洁的方法)
*/
private static void arrayToList2() {
Integer[] array = {7, 8, 9};
List<Integer> list = new ArrayList<>(Arrays.asList(array));
System.out.println(list);
}
/**
* Array转List方法3(利用Collections的addAll方法实现Array转List)
*/
private static void arrayToList3() {
Integer[] array = {10, 11, 12};
List<Integer> list = new ArrayList<>(array.length);
Collections.addAll(list, array);
System.out.println(list);
}
}
运行结果:
List和Array的相互转换输出
网友评论