真实的面试题总结

编程题

30人数到9就跳河(耶稣门徒)

题目大意:在一条船上,有30个人分成2队,站成一圈,从1开始报数,数到9的那个人就跳河,下一个接着重新从1开始报数,依次类推,求最后活下来是全是一队人的站位编号。
解题思路:定义1个boolean数据,用来标记30个占位是否还有人,定义一个list用来记录跳河人的编号
题目难点:怎么循环?循环中怎么记录该跳下去的人员的编号。
代码如下:

    public void fun1() {
        boolean[] persons = new boolean[30]; //标记位置是否还有人
        ArrayList arr = new ArrayList();//记录跳下去人员的编号(索引)
        int count = 0; //报数
        while (arr.size() < 15) { //结束条件:小与15个人
            for (int i = 0; i < persons.length; i++) {
                if (persons[i] == false) { //如果该位置有人,有效报数+1
                    count += 1;
                }
                if (count == 9) {//报数9,则该人员跳下去
                    arr.add(i + 1); 
                    persons[i] = true; //标记该位置已经有人了
                    count = 0; //报数归零
                }
            }
        }
        Object[] array = arr.toArray();
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }

程序运行结果:
跳河:[5, 6, 7, 8, 9, 12, 16, 18, 19, 22, 23, 24, 26, 27, 30]
未跳:[1, 2, 3, 4, 10, 11, 13, 14, 15, 17, 20, 21, 25, 28, 29]

上面的思路,其实很麻烦,后来讨论别人的想法之后,下面代码我觉得更加巧妙

public void fun2() {
        java.util.List person = new ArrayList();
        for (int i = 1; i <= 30; i++) {
            person.add(i);
        }

        int count = 0;
        while (person.size() != 15) {
            Iterator it = person.iterator();
            while (it.hasNext()) {
                count++;
                it.next();
                if (count == 9) {
                    it.remove(); //移除跳河的人
                    count = 0;
                }
            }
        }
        System.out.println(Arrays.toString(person.toArray()));

    }

方法传参相关

有如下代码,person有a,b两个默认的值,我们使用swap方法交换之后,再置空swap中的person。 请问执行的结果是:?

public class OO {

    public static void main(String[] args) {
        OO oo = new OO();
        Person person = new OO.Person();
        oo.swap(person);
        System.out.println(person.a + "," + person.b);
    }

    public void swap(Person person) {
        int temp = person.a;
        person.a = person.b;
        person.b = temp;
        person = null;
    }

    static class Person {
        int a = 1;
        int b = 30;
    }
}

正确答案是:30,1,我以为会抛出空指针异常呢
书上是这样解释的:

java的方法传参只有一种,就是传值,引用类型就就是传递引用地址
以上程序在内存中的分布大概如下:真实的面试题总结_第1张图片
所以,在swap中置空person变量的对堆内存的引用之后,并没有影响到main方法区中的person变量。

设计模式相关

单列模式几种实现的区分

懒汉:
        以时间换空间的做法【只有在使用的时候才实例化对象】、线程不安全的
public class Singleton {
    //4:定义一个变量来存储创建好的类实例
    //5:因为这个变量要在静态方法中使用,所以需要加上static修饰
    private static Singleton instance = null;
    //1:私有化构造方法,好在内部控制创建实例的数目
    private Singleton(){
    }
    //2:定义一个方法来为客户端提供类实例
    //3:这个方法需要定义成类方法,也就是要加static
    public static  Singleton getInstance(){
        //6:判断存储实例的变量是否有值
        if(instance == null){
            //6.1:如果没有,就创建一个类实例,并把值赋值给存储类实例的变量
            instance = new Singleton();
        }
        //6.2:如果有值,那就直接使用
        return instance;
    }
}

    恶汉式:
        以空间换时间的做法【类加载的时候就实例化了对象】、线程是安全的
    public class Singleton {
    //4:定义一个静态变量来存储创建好的类实例
    //直接在这里创建类实例,只会创建一次
    private static Singleton instance = new Singleton();
    //1:私有化构造方法,好在内部控制创建实例的数目
    private Singleton(){        
    }
    //2:定义一个方法来为客户端提供类实例
    //3:这个方法需要定义成类方法,也就是要加static
    public static Singleton getInstance(){
        //5:直接使用已经创建好的实例
        return instance;
    }
        }

我习惯使用的一种单列写法:
Lazy initialization holder class模式,这个模式综合使用了java的类级内部类和多线程缺省同步锁的知识,很巧妙的同时实现了延迟加载和线程安全

public class Singleton {
    /**
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
     * 而且只有被调用到才会装载,从而实现了延迟加载
     */
    private static class SingletonHolder{  //内部类只有在有调用的时候,该内部类才会初始化,达到了延迟加载
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private static Singleton instance = new Singleton();
    }
    /**
     * 私有化构造方法
     */
    private Singleton(){
    }

    public static  Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

今天面试被问道饿汉和懒汉,懒汉的线程安全问题,自己嘴贱,说喜欢用Lazy initialization holder class模式来实现加载,大概说了下实现方式,本来是说对了的,对方问了一句话:
使用静态内部类的话类一加载就初始化了,那我直接在类中声明静态变量(懒汉式)有啥区别? 我当时一听,顿时就懵了。回到家,看了下以前的笔记才从圈里走出来:下面是测试

public class Demo {
    private static class DemoHoder {
        static {
            System.out.println("1:内部类被初始化了");
        }
        private static Demo instance = new Demo();
    }

    private Demo() {
        System.out.println("2:本类初始化了");
    }

    Demo(String str) {
        System.out.println("3:有参数的构造初始化了");
    }

    public static Demo getInstance() {
        return DemoHoder.instance;
    }
}

直接使用 Demo.getInstance(); 打印的是
1:内部类被初始化了
2:本类初始化了
直接new Demo(“sss”);打印的是
3:有参数的构造初始化了

从这里可以看出,如果你在Demo中声明一个静态变量Demo demo = new Demo; 那么再执行new Demo(“sss”),那么这个静态变量也会随着一起被实例化,而使用静态内部类来实现单例的话,只有静态内部类被调用的时候才会实例化,也就是说:
类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
而且只有被调用到才会装载,从而实现了延迟加载

String相关

String字符串是数字,排序

题目:String tem = “3456231”; 只许使用jdk的api把这个按升序排列

        String tem = "3456231";
        char[] arr = tem.toCharArray();
        Arrays.sort(arr);
        tem = new String(arr);
        System.out.println(tem);

线程相关

线程启动方式

实现Runnable接口,或者继承Thread类

        new Thread().start();
        new Thread(new Runnable() {
            public void run() {
            }
        }).start();

你可能感兴趣的:(面试题,面试题)