美文网首页牛客题集
牛客错题集(一)

牛客错题集(一)

作者: 菊地尤里 | 来源:发表于2018-06-03 15:48 被阅读0次

    1.有如下4条语句:()
    1、Integer i01=59;
    2、int i02=59;
    3、Integer i03=Integer.valueOf(59);
    4、Integer i04=new Integer(59);
    以下输出结果为false的是:
    正确答案: C 你的答案: D (错误)
    System.out.println(i01==i02);
    System.out.println(i01==i03);
    System.out.println(i03==i04);
    System.out.println(i02==i04);

    首先常量池这个概念,原来以为只要是一个整型,都会放进到常量池,比如,0,1,12222222等。查找后发现,Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127并且大于等于-128时才可使用常量池,因为他们至占用一个字节(-128~127);

    再者Integer.valueOf方法中也有判断,如果传递的整型变量>= -128并且小于127时会返回IntegerCache类中一个静态数组中的某一个对象, 否则会返回一个新的Integer对象,代码如下

    public static Integer valueOf(int i) {
            assert IntegerCache.high >= 127;
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    

    所以如果你测试如下代码

    public static void main(String[] args) {
             
            Integer a = 127;
            Integer b = 127;
             
            Integer c = 128;
            Integer d = 128;
             
            System.out.println(a == b);
            System.out.println(c == d);
        }
    

    结合自动封装、常量池以及Integer.valueOf方法就不难得出,答案时true和false;

    ①无论如何,Integer与new Integer不会相等。不会经历拆箱过程,
    ②两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
    java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存
    ③两个都是new出来的,都为false
    ④int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

    2.Object中的equals方法是对象的比较,由于String类重写了该方法实现了内容的比较。

    3.void waitForSignal()
    {
    Object obj = new Object();
    synchronized(Thread.currentThread())
    {
    obj.wait();
    obj.notify();
    }
    }
    正确答案: A 你的答案: D (错误)
    Which statement is true?
    This code may throw an InterruptedException
    This code may throw an IllegalStateException
    This code may throw a TimeOutException after ten minutes
    This code will not compile unless”obj.wait()”is replaced with”(Thread)obj).wait()”
    Reversing the order of obj.wait()and obj.notify()may cause this method to complete normally
    这题有两个错误的地方,第一个错误是 wait() 方法要以 try/catch 包覆,或是掷出 InterruptedException 才行
    因此答案就是因为缺少例外捕捉的 InterruptedException

    第二个错误的地方是, synchronized 的目标与 wait() 方法的物件不相同,会有 IllegalMonitorStateException ,不过 InterruptedException 会先出现,所以这不是答案

    最后正确的程式码应该是这样:

     void waitForSignal() {
    Object obj = new Object();
             synchronized (obj) {
                 try {
    obj.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    obj.notify();
    }
    }
    

    3.静态成员变量或静态代码块>mian方法>非静态成员变量或非静态代码块>构造方法

    4.Which lines of the following will produce an error?

    1. byte a1 = 2, a2 = 4, a3;
    2. short s = 16;
    3. a2 = s;
    4. a3 = a1 * a2;

    正确答案: A 你的答案: B (错误)
    Line 3 and Line 4
    Line 1 only
    Line 3 only
    Line 4 only

    short类型转为byte类型出错
    a1*a2结果为int类型,转为byte类型出错(java中如果碰到char、byte和short参与运算时,会自动将这些值转换为int类型然后再进行运算)

    5.成员变量有初始值,而局部变量没有初始值

    6.JDK1.8 接口可以有default、static方法

    interface A {
    abstract void a();
    static void s() {
    }
    default void d(){

    }
    void b();//默认用abstract修饰
    int a = 0;//默认用static final 修饰 
    

    }

    7.以下程序的输出结果为

    class Base{
        public Base(String s){
            System.out.print("B");
        }
    }
    public class Derived extends Base{
        public Derived (String s) {
            System.out.print("D");
        }
        public static void main(String[] args){
            new Derived("C");
        }
    }
    

    正确答案: D 你的答案: A (错误)
    BD
    DB
    C
    编译错误

    子类构造方法在调用时必须先调用父类的,由于父类没有无参构造,必须在子类中显式调用,修改子类构造方法如下即可:
    public Derived(String s){
    super("s");
    System.out.print("D");
    }

    8.finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源的回收,例如关闭文件等。 错
    可以覆盖此方法提供垃圾收集时的其他资源的回收,但是不是关闭文件这种操作而是一些通过调用了native方法产生的资源的释放.

    深入理解java虚拟机中说到:
    当对象不可达后,仍需要两次标记才会被回收,首先垃圾收集器会先执行对象的finalize方法,但不保证会执行完毕(死循环或执行很缓慢的情况会被强行终止),此为第一次标记。第二次检查时,如果对象仍然不可达,才会执行回收。

    9.依然是JVM
    jvm中垃圾回收分为scanvenge gc和full GC,其中full GC触发的条件可能有哪些
    正确答案: C D E 你的答案: B D E (错误)
    栈空间满
    年轻代空间满
    老年代满
    持久代满
    System.gc()

    1,新生代:(1)所有对象创建在新生代的Eden区,当Eden区满后触发新生代的Minor GC,将Eden区和非空闲Survivor区存活的对象复制到另外一个空闲的Survivor区中。(2)保证一个Survivor区是空的,新生代Minor GC就是在两个Survivor区之间相互复制存活对象,直到Survivor区满为止。
    2,老年代:当Survivor区也满了之后就通过Minor GC将对象复制到老年代。老年代也满了的话,就将触发Full GC,针对整个堆(包括新生代、老年代、持久代)进行垃圾回收。
    3,持久代:持久代如果满了,将触发Full GC。

    简单来说
    年轻代的GC 叫 young GC ,有时候也叫 minor GC 。年老代或者永久代的 GC ,叫 full GC ,也叫 major GC 。
    持久代为方法区,方法区又叫永久代,用于存放静态文件,满了以后也会触发负full GC

    10.以下哪几种方式可用来实现线程间通知和唤醒:( )
    正确答案: A C 你的答案: B D (错误)
    Object.wait/notify/notifyAll
    ReentrantLock.wait/notify/notifyAll
    Condition.await/signal/signalAll
    Thread.wait/notify/notifyAll

    wait()、notify()和notifyAll()是 Object类 中的方法
    从这三个方法的文字描述可以知道以下几点信息:
    1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
    2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
    3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
    4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
    有朋友可能会有疑问:为何这三个不是Thread类声明中的方法,而是Object类中声明的方法
    (当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问
    题很简单,由于每个对象都拥有monitor(即锁),所以让当前线程等待某个对象的锁,当然
    应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程
    的锁,如果通过线程来操作,就非常复杂了。
    上面已经提到,如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即
    锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者
    synchronized方法)。
    调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态,
    等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从
    而让其他线程有机会继续执行,但它并不释放对象锁);
    notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象
    的monitor的话,则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。
    同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,因此调用
    notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
    nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
    Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,在阻塞队列那一篇博文中就讲述到了,阻塞队列实际上是使用了Condition来模拟线程间协作。
    Condition是个接口,基本的方法就是await()和signal()方法;
    Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
    调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用Conditon中的await()对应Object的wait(); Condition中的signal()对应Object的notify(); Condition中的signalAll()对应Object的notifyAll()

    相关文章

      网友评论

        本文标题:牛客错题集(一)

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