牛客选择题错题集

2019-04-26

1. 以下代码执行的结果显示是多少( )?

 

A.true,false,true

B.false,true,false

C.true,true,false

D.false,false,true

正确答案: D   你的答案: A (错误)

解答:

当我们在为Integer赋值的时候,java编译器会将其翻译成调用valueOf()方法。比如Integer i=127翻译为Integer i=Integer.valueOf(127)
然后我们来看看valueOf()函数的源码:
1 public static Integer valueOf(int i)
2     {
3         //high为127
4         if(i >= -128 && i <= IntegerCache.high)
5             return IntegerCache.cache[i + 128];
6         else
7             return new Integer(i);
8     }
可以看出,对于-128到127之间的数,Java会对其进行缓存。而超出这个范围则新建一个对象。
所以现在回到这道问题
i1和i2为128,超出范围,所以都需要新建对象,对象比较为false;
i5和i6为100,在范围之内,在执行Integer i5=100时,就会直接缓存到内存中,但执行执行Integer i6=100时,就直接从缓存里取,而不需要新建对象,所以为true。
IntegerCache的源码
/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */
 
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
 
// 省略
}

可以看到可以通过设置虚拟机参数:XX:AutoBoxCacheMax=<size>或 -Djava.lang.Integer.IntegerCache.high=<high>

来设置缓存范围的最大值(包含)

这归结于java对于Integer与int的自动装箱与拆箱的设计,是一种模式:享元模式(flyweight)

为了加大对简单数字的重利用,java定义:在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象。

而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象;以上的现象是由于使用了自动装箱所引起的,如果你没有使用自动装箱,而是跟一般类一样,用new来进行实例化,就会每次new就都一个新的对象。

享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式,换句话说就是共享对象,在某些对象需要重复创建,且最终只需要得到单一结果的情况下使用。因为此种模式是利用先前创建的已有对象,通过某种规则去判断当前所需对象是否可以利用原有对象做相应修改后得到想要的效果,如以上教程的实例,创建了20个不同效果的圆,但相同颜色的圆只需要创建一次便可,相同颜色的只需要引用原有对象,改变其坐标值便可。此种模式下,同一颜色的圆虽然位置不同,但其地址都是同一个,所以说此模式适用于结果注重单一结果的情况。

举一个简单例子,一个游戏中有不同的英雄角色,同一类型的角色也有不同属性的英雄,如刺客类型的英雄有很多个,按此种模式设计,利用英雄所属类型去引用原有同一类型的英雄实例,然后对其相应属性进行修改,便可得到最终想得到的最新英雄;比如说你创建了第一个刺客型英雄,然后需要设计第二个刺客型英雄,你利用第一个英雄改变属性得到第二个刺客英雄,最新的刺客英雄是诞生了,但第一个刺客英雄的属性也随之变得与第二个相同,这种情况显然是不可以的。

扩展:下面代码的输出为什么?

public class Demo{
    public static void main(String[] args){
        String s1 = "100"; 
        String s2 = "100";
        System. out. print((s1==s2)+",");

        String s3 = new String("100"); 
        System. out. print((s2==s3)+",");

        String s4 = new String("100");
        System. out. print((s3==s4)+",");
        }
}      
输出:
true,false,false,

VM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间——字符串实例池

String赋值的两种方式。

1、String str = "test";

以这种方式赋值时,JVM会先从字符串实例池中查询是否存在"test"这个对象,

如果存在,直接把实例池中"test"的地址返回给str。如果不存在,则会在实例池中创建"test"对象,并把该对象的地址返回给str。

2、String str = new String("test");

以这种方式赋值时,JVM会先从字符串实例池中查询是否存在"test"这个对象,

若不存在则会在实例池中创建"test"对象,同时在堆中创建"test"这个对象,然后将堆中的这个对象的地址返回赋给引用str。

若实例池存在则直接在堆中创建"test"这个对象,然后将堆中的这个对象的地址返回赋给引用str。

上面代码中的s3和s4分别指向堆中不同的地址,所以返回false

 2.下列代码执行结果为()

public static void main(String args[])throws InterruptedException{
            Thread t=new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.print("2");
                }
            });
            t.start();
             
            t.join();
            System.out.print("1");
        }
A. 21
B. 12
C. 可能为12,也可能为21
D. 以上答案都不对

正确答案: A   你的答案: 空 (错误)

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join();      //使调用线程 t 在此之前执行完毕。 
t.join(1000);  //等待 t 线程,等待时间是1000毫秒

本题在主线程中调用了子线程的join函数,因此主线程必须等待子线程执行完毕才结束因此输出结果只能是21。

3. jdk1.8中,下面有关java 抽象类和接口的区别,说法错误的是?

A. 抽象类可以有构造方法,接口中不能有构造方法

B. 抽象类中可以包含非抽象的普通方法,接口中的方法必须是抽象的,不能有非抽象的普通方法

C. 一个类可以实现多个接口,但只能继承一个抽象类

D. 接口中可以有普通成员变量,抽象类中没有普通成员变量

我们知道,抽象类是不能被实例化的。但抽象类是否可以有构造函数?答案是可以有。抽象类的构造函数用来初始化抽象类的一些字段,而这一切都在抽象类的派生类实例化之前发生。不仅如此,抽象类的构造函数还有一种巧妙应用:就是在其内部实现子类必须执行的代码。

2019-04-27

static 修饰符
静态变量:

static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

静态方法:

static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

对类变量和方法的访问可以直接使用 classname.variablename 和 classname.methodname 的方式访问。

1. 下列程序执行后结果为( )

 1 class A {
 2     public int func1(int a, int b) {
 3         return a - b;
 4     }
 5 }
 6 class B extends A {
 7     public int func1(int a, int b) {
 8         return a + b;
 9     }
10 }
11 public class ChildClass {
12     public static void main(String[] args) {
13     A a = new B();
14     B b = new B();
15     System.out.println("Result=" + a.func1(100, 50));
16     System.out.println("Result=" + b.func1(100, 50));
17     }
18 }

正确答案: A   你的答案: C (错误)

A. Result=150Result=150

B. Result=100Result=100

C. Result=100Result=150

D. Result=150Result=100

此题考查的是多态。
  对于多态,可以总结它为:       

     一、使用父类类型的引用指向子类的对象;

    二、该引用只能调用父类中定义的方法和变量;

    三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)

    四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。

多态的3个必要条件:

        1.继承   2.重写   3.父类引用指向子类对象。
向上转型: Person p = new Man() ; //向上转型不需要强制类型转化
向下转型: Man man = (Man)new Person() ; //必须强制类型转化

2. BufferedReader的父类是以下哪个?

正确答案: D   你的答案: D (正确)

A. FilterReader

B. InputStreamReader

C. PipedReader

D. Reader

 

3. 下面代码将输出什么内容:()

1 public class SystemUtil{
2     public static boolean isAdmin(String userId){
3         return userId.toLowerCase()=="admin";
4     }
5     public static void main(String[] args){
6         System.out.println(isAdmin("Admin"));
7     }
8 }

正确答案: B   你的答案: B (正确)

A. true

B. false

C. 1

D. 编译错误

在Java中,String 、Math、还有Integer、Double。。。。等这些封装类重写了Object中的equals()方法,让它不再比较其对象在内存中的地址,而是比较对象中实际包含的整数的值,即比较的是内容。

=="equals方法:

==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符;

如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如Objet obj = newObject();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。

equals方法是用于比较两个独立对象的内容是否相同,它比较的两个对象是独立的。

如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:

boolean equals(Object o){

return this==o;

}

 

这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。

 

4. 代码片段: 

byte b1=1,b2=2,b3,b6; 
final byte b4=4,b5=6; 
b6=b4+b5; 
b3=(b1+b2); 
System.out.println(b3+b6);
关于上面代码片段叙述正确的是()

正确答案: C   你的答案: A (错误)

A. 输出结果:13

B.语句:b6=b4+b5编译出错

C.语句:b3=b1+b2编译出错

D. 运行期抛出异常

被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了
而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。
Java中的byte,short,char进行计算时都会提升为int类型

5. 阅读如下代码。 请问,对语句行 test.hello(). 描述正确的有()

package NowCoder;
class Test {
    public static void hello() {
        System.out.println("hello");
    }
}
public class MyApplication {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test test=null;
        test.hello();
    }
}

正确答案: A   你的答案: A (正确)

A.能编译通过,并正确运行

B.因为使用了未初始化的变量,所以不能编译通过

C.以错误的方式访问了静态方法

D.能编译通过,但因变量为null,不能正常运行

因为Test类的hello方法是静态的,所以是属于类的,当实例化该类的时候,静态会被优先加载而且只加载一次,所以不受实例化new Test();影响,只要是使用到了Test类,都会加载静态hello方法!
另外,在其他类的静态方法中也是可以调用公开的静态方法,此题hello方法是使用public修饰的所以在MyApplication中调用hello也是可以的。
总结:即使Test test=null;这里也会加载静态方法,所以test数据中包含Test类的初始化数据。(静态的,构造的,成员属性)
        因此test.hello是会调用到hello方法的。

6. 假设 a 是一个由线程 1 和线程 2 共享的初始值为 0 的全局变量,则线程 1 和线程 2 同时执行下面的代码,最终 a 的结果不可能是()

boolean isOdd = false;
 
for(int i=1;i<=2;++i)
{
    if(i%2==1)isOdd = trueelse isOdd = false;
    a+=i*(isOdd?1:-1);
}

 

正确答案: D   你的答案: C (错误)

A. -1

B. -2

C. 0

D. 1

易知:每个线程对a 均做了两次读写操作,分别是 “ +1 ” 和 “ -2 ”
而题目问了是最终a 的结果,所以 a 的结果取决于各自线程对 a 的先后读写的顺序
结论:a的可能取值为-1、0、-2
如图:

 2019-05-11

 

1. 以下程序的输出结果是

public class Print{
    static boolean out(char c){
        System.out.println(c);
        return true;
    }
    public static void main(String[] argv){
        int i = 0;
        for(out('A');out('B') && (i<2);out('C')){
            i++;
            out('D');
        }
    }
}

正确答案: A   你的答案: A (正确)

A. ABDCBDCB

B. BCDABCD

C. 编译错误

D. 运行错误

其实这题考察的是for(int i=0;i<10;i++){}循环的执行顺序:
1.int i=0;初始化这一步只执行一次;
2.i<10;进行条件判断;条件达成返回true 否则false不往下执行,跳出for循环圈
3.i++ ;  是最后执行的,当循环体内的代码执行完它才进行赋值。

 

2. 如果int x=20, y=5,则语句System.out.println(x+y +""+(x+y)+y);  的输出结果是()

正确答案: D   你的答案: A (错误)

A. 2530

B. 55

C. 2052055

D. 25255

1)不论有什么运算,小括号的优先级都是最高的,先计算小括号中的运算,得到x+y +""+25+y
2)任何字符与字符串相加都是字符串,但是是有顺序的,字符串前面的按原来的格式相加,字符串后面的都按字符串相加,得到25+“”+25+5。
x+y+""+(x+y)+y,
先算括号: x+y+""+25+y, 
再按字符串分开看,符串前面的按原来的格式相加,字符串后面的都按字符串相加,x+y+""+25+y
得到  25+""+255
整个再连成字符串 25255
3)上面的结果按字符串相加得到25255

3. 下列哪个说法是正确的()

正确答案: D   你的答案: A (错误)

A. ConcurrentHashMap使用synchronized关键字保证线程安全

B. HashMap实现了Collction接口

C. Array.asList方法返回java.util.ArrayList对象

D. SimpleDateFormat是线程不安全的

A. JDK1.8 的 ConcurrentHashMap 采用CAS+Synchronized保证线程安全。 JDK1.7 及以前采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock,因此采用Lock锁来保证线程安全。
B. 
C. Arrays.asList()  返回  java.util.Arrays.ArrayList 对象,这里的 ArrayList 是 Arrays 私有的内部类
D. 

4. 类Parent和Child定义如下, 将以下哪种方法插入行5是不合法的(    )

1 class  Parent{
2    public  float  aFun(float a, float b) { }
3 }
4 class  Child  extends  Parent{
5 }

正确答案: A   你的答案: C (错误)

A. float aFun(float a, float b){ }

B. public int aFun(int a, int b) { }

C. public float aFun(float p, float q){ }

D. private int aFun(int a, int b){ }

A.方法重写(覆盖)。子类方法不能缩小父类方法的访问权限,错误。
B.方法重载。参数列表不同,满足重载条件,正确。
C.方法重写(覆盖)。方法声明和父类相同,满足重写条件,正确。
D.方法重载。参数列表不同,满足重载条件,正确
 
 方法重写(Override)应遵循“两小一大一相同”原则:
  1. “两小”:子类异常小于等于父类,子类返回值小于等于父类;
  2. “一大”:子类方法的访问修饰符大于等于父类;
  3. “一相同”:方法签名相同。

5. list是一个ArrayList的对象,哪个选项的代码填到//todo delete处,可以在Iterator遍历的过程中正确并安全的删除一个list中保存的对象?()

Iterator it = list.iterator();
int index = 0;
while (it.hasNext())
{
    Object obj = it.next();
    if (needDelete(obj))  //needDelete返回boolean,决定是否要删除
    {
        //todo delete
    }
    index ++;
}

正确答案: A   你的答案: B (错误)

A. it.remove();

B. list.remove(obj);

C. list.remove(index);

D. list.remove(obj,index);

Iterator  支持从源集合中安全地删除对象,只需在 Iterator 上调用 remove() 即可。这样做的好处是可以避免 ConcurrentModifiedException ,当打开 Iterator 迭代集合时,同时又在对集合进行修改。有些集合不允许在迭代时删除或添加元素,但是调用 Iterator 的remove() 方法是个安全的做法。 

6. 面有关 JAVA 异常类的描述,说法正确的有()

正确答案: A B C   你的答案: A B C (正确)

A. 异常的继承结构:基类为 Throwable,Error 和 Exception 实现 Throwable,RuntimeException 和 IOException 等继承 Exception

B. 非 RuntimeException 一般是外部错误(不考虑Error的情况下),其必须在当前类被 try{}catch 语句块所捕获

C. Error 类体系描述了 Java 运行系统中的内部错误以及资源耗尽的情形,Error 不需要捕捉

D. RuntimeException 体系包括错误的类型转换、数组越界访问和试图访问空指针等等,必须 被 try{}catch 语句块所捕获

ABC

都是Throwable的子类: 
1.Exception(异常) :是程序本身可以处理的异常。 
2.Error(错误): 是程序无法处理的错误。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,一般不需要程序处理。

3.检查异常(编译器要求必须处置的异常) :  除了Error,RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

4.非检查异常(编译器不要求处置的异常): 包括运行时异常(RuntimeException与其子类)和错误(Error)。

14:41:14

1. 下列关于Java语言中String和char的说法,正确的是()

正确答案: C   你的答案: C (正确)

  A. String是Java定义的一种基本数据类型。

  B. String是以“\0”结尾的char类型的数组char[]。

  C. 使用equals()方法比较两个String是否内容一样(即字符串中的各个字符都一样)。

  D. Char类型在Java语言里面存储的是ASCII码。

A 基本数据类型包括byte,short,int,long,float,double,char,boolean,所以A错。
B,C语言当中是这样,java不是, String内部是用char[]数组实现的,不过结尾不用\0
C 对,字符串内容比较用equals方法。
D char存储的unicode码,不仅可以存储ascII码,汉字也可以。

2. 在java中,无论在何处调用,使用静态属性必须以类名做前缀。

正确答案: B   你的答案: A (错误)

  A. 正确

  B. 错误

1如果是本类使用,可以直接就用静态变量名。2如果是其他类使用,可以使用类名来调用,也可以创建一个实例对象来调用。3如果静态变量所在的类是静态类(即静态内部类,外部类没有静态的),那么不管在本类里或者在其他外部类,都可以直接使用静态变量名

 

3. 下列外部类定义中,不正确的是:( )

正确答案: C   你的答案: D (错误)

A. class x { .... }

B. class x extends y { .... }

C. static class x implements y1,y2 { .... }

D. public class x extends Applet { .... }

只有静态内部类,没有静态外部类。static不能用来修饰外部类
4. Math.round(11.5) 等于多少 (). Math.round(-11.5) 等于多少 (  ).

正确答案: C   你的答案: D (错误)

A. 11 ,-11

B. 11 ,-12

C. 12 ,-11

D. 12 ,-12

Math类中提供了三个与取整有关的方法:ceil,floor,round 。 ceil 向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.6)的结果为-11;

                          floor向下取整,Math.floor(11.6)的结果是11,Math.floor(-11.4)的结果-12;

round方法,表示“四舍五入”,算法为Math.floor(x+0.5),  即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果是12,Math.round(-11.5)的结果为-11.

5. 如下代码,执行test()函数后,屏幕打印结果为()

public class Test2
{
    public void add(Byte b)
    {
        b = b++;
    }
    public void test()
    {
        Byte a = 127;
        Byte b = 127;
        add(++a);
        System.out.print(a + " ");
        add(b);
        System.out.print(b + "");
    }
}

正确答案: D   你的答案: B (错误)

A. 127 127

B. 128 127

C. 129 128

D. 以上都不对

public void add(Byte b){ b=b++; } 这里涉及java的自动装包/自动拆包(AutoBoxing/UnBoxing) Byte的首字母为大写,是类,看似是引用传递,但是在add函数内实现++操作,会自动拆包成byte值传递类型,所以add函数还是不能实现自增功能。也就是说add函数只是个摆设,没有任何作用。 Byte类型值大小为-128~127之间。 add(++a);这里++a会越界,a的值变为-128 add(b); 前面说了,add不起任何作用,b还是127
6. 下面代码的输出是什么?
public class Base
{
    private String baseName = "base";
    public Base()
    {
        callName();
    }
 
    public void callName()
    {
        System. out. println(baseName);
    }
 
    static class Sub extends Base
    {
        private String baseName = "sub";
        public void callName()
        {
            System. out. println (baseName) ;
        }
    }
    public static void main(String[] args)
    {
        Base b = new Sub();
    }
}

正确答案: A   你的答案: B (错误)

A. null

B. sub

C. base

 new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null

7. 对 Map 的用法,正确的有:

正确答案: C D   你的答案: B D (错误)

A. new java.util.Map().put("key" , "value") ;

B. new java.util.SortedMap().put("key" , "value") ;

C. new java.util.HashMap().put( null , null ) ;

D. new java.util.TreeMap().put( 0 , null ) ;

选C、D。考察的是Map接口实现类的创建对象以及对象类型包含的方法。
A选项Map属于接口类型,不可以new的方式创建对象。所以A错误。
B选项SortedMap属于接口类型,不可以new的方式创建对象。所以B错误。
C选项HashMap基于哈希表实现Map接口的类,并允许null的值和null键。
D选项TreeMap通过红黑树实现Map接口的类,key不可以为null,会报NullPointerException异常,value可以为null。
public static void main(String[] args) {
        TreeMap<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("0",null);
        System.out.println(treeMap.get("0"));//结果为:null
    }

  

posted @ 2019-04-26 20:56  lllunaticer  阅读(591)  评论(0编辑  收藏  举报