牛客网Java练习6
1.在一个基于分布式的游戏服务器系统中,不同的服务器之间,哪种通信方式是不可行的()?
A 管道
B 消息队列
C 高速缓存数据库
D 套接字
答案 A
管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
既然是不同的服务器之间进行通信,怎么可能会是具有亲缘关系的进程呢?
2.Test.main() 函数执行后的输出是()
public class Test {
public static void main(String [] args){
System.out.println(new B().getValue());
}
static class A{
protected int value;
public A(int v) {
setValue(v);
}
public void setValue(int value){
this.value = value;
}
public int getValue(){
try{
value++;
return value;
} catch(Exception e){
System.out.println(e.toString());
} finally {
this.setValue(value);
System.out.println(value);
}
return value;
}
}
static class B extends A{
public B() {
super(5);
setValue(getValue() - 3);
}
public void setValue(int value){
super.setValue(2 * value);
}
}
}
A 11 17 34
B 22 74 74
C 6 7 7
D 22 34 17
答案 D
3.考虑下面这个简单的例子,让我们看看reflection是如何工作的。
import java.lang.reflect.*;
public class DumpMethods{
public static void main(String[] args) {
try {
Class c=Class.forName(args[0]);
Method m[]=c.getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
System.out.println(m[i].toString());
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
其中"c.getDeclaredMethods"的作用是:
A 取得类的公有方法对象
B 取得类的所有公有方法名称
C 取得类的所有方法对象
D 以上选项都不正确
答案 D
public Method[] getDeclaredMethods()返回类或接口声明的所有方法,包括public, protected, default (package) 访问和private方法的Method对象,但不包括继承的方法。当然也包括它所实现接口的方法。
public Method[] getMethods()返回类的所有public方法,包括其继承类的公用方法,当然也包括它所实现接口的方法。
4.下面有关java threadlocal说法正确的有?
A ThreadLocal存放的值是线程封闭,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递
B 线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收
C 在Thread类中有一个Map,用于存储每一个线程的变量的副本。
D 对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式
答案ABCD
ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程的上下文。 可以总结为一句话:ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。 举个例子,我出门需要先坐公交再做地铁,这里的坐公交和坐地铁就好比是同一个线程内的两个函数,我就是一个线程,我要完成这两个函数都需要同一个东西:公交卡(北京公交和地铁都使用公交卡),那么我为了不向这两个函数都传递公交卡这个变量(相当于不是一直带着公交卡上路),我可以这么做:将公交卡事先交给一个机构,当我需要刷卡的时候再向这个机构要公交卡(当然每次拿的都是同一张公交卡)。这样就能达到只要是我(同一个线程)需要公交卡,何时何地都能向这个机构要的目的。 有人要说了:你可以将公交卡设置为全局变量啊,这样不是也能何时何地都能取公交卡吗?但是如果有很多个人(很多个线程)呢?大家可不能都使用同一张公交卡吧(我们假设公交卡是实名认证的),这样不就乱套了嘛。现在明白了吧?这就是ThreadLocal设计的初衷:提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程。
4.如何放掉一个指定占据的内存空间?()
A 调用free()方法
B 代用system.gc()方法
C 赋值给该项对象的引用为null
D 程序员无法明确强制垃圾回收器运行
答案 D
在《java虚拟机》一书中明确讲了,释放掉占据的内存空间是由gc完成,但是程序员无法明确强制其运行,该空间在不被引用的时候不一定会立即被释放,这取决于GC本身,无法由程序员通过代码控制。
5.下面有关maven和ant的描述,描述错误的是?
A Ant 没有正式的约定如一个一般项目的目录结构,你必须明确的告诉 Ant 哪里去找源代码
B Maven 拥有约定,因为你遵循了约定,它已经知道你的源代码在哪里
C maven和ant都有“生命周期”的概念,当你输入一个命令后,maven或者ant会执行一系列的有序的步骤,直到到达你指定的生命周期
D Ant构建文件默认命名为build.xml,Maven默认构建文件为pom.xml
答案C
Ant和Maven都是基于Java的构建(build)工具。理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷。Ant是软件构建工具,Maven的定位是软件项目管理和理解工具。
Ant特点 �
没有一个约定的目录结构 �必须明确让ant做什么,什么时候做,然后编译,打包 �没有生命周期,必须定义目标及其实现的任务序列 �没有集成依赖管理
Maven特点
�拥有约定,知道你的代码在哪里,放到哪里去 �拥有一个生命周期,例如执行 mvn install 就可以自动执行编译,测试,打包等构建过程 �只需要定义一个pom.xml,然后把源码放到默认的目录,Maven帮你处理其他事情 �拥有依赖管理,仓库管理
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
A null
B sub
C base
new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null
1.首先,需要明白类的加载顺序。
(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
(3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )
(4) 父类构造函数
(5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
(6) 子类构造函数
其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)
2.其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。
当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。
由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。
7.在Java中,对于不再使用的内存资源,如调用完成的方法,“垃圾回收器”会自动将其释放。( )
A 正确
B 错误
答案 B
方法调用时,会创建栈帧在栈中,调用完是程序自动出栈释放,而不是gc释放
JVM 内存可简单分为三个区:
1、堆区(heap):用于存放所有对象,是线程共享的(注:数组也属于对象)
2、栈区(stack):用于存放基本数据类型的数据和对象的引用,是线程私有的(分为:虚拟机栈和本地方法栈)
3、方法区(method):用于存放类信息、常量、静态变量、编译后的字节码等,是线程共享的(也被称为非堆,即 None-Heap)
Java 的垃圾回收器(GC)主要针对堆区
8.下面哪些类实现或继承了 Collection 接口?
A HashMap
B ArrayList
C Vector
D Iterator
答案 BCD
9.jdk1.8中,下面有关java 抽象类和接口的区别,说法错误的是?
A 抽象类可以有构造方法,接口中不能有构造方法
B 抽象类中可以包含非抽象的普通方法,接口中的方法必须是抽象的,不能有非抽象的普通方法
C 一个类可以实现多个接口,但只能继承一个抽象类
D 接口中可以有普通成员变量,抽象类中没有普通成员变量
答案B D
interface A {
abstract void a();
static void s() {
}
default void d(){
}
void b();//默认用abstract修饰
int a = 0;//默认用static final 修饰
}
9.假定str0,...,str4后序代码都是只读引用。Java 7中,以上述代码为基础,在发生过一次FullGC后,下列代码在Heap空间(不包括PermGen)保留的字符数为()
static String str0="0123456789";
static String str1="0123456789";
String str2=str1.substring(5);
String str3=new String(str2);
String str4=new String(str3.toCharArray());
str0=null;
A 5
B 10
C 15
D 20
答案 C
substring实际是new,5字符
str3和4也都是new,每个5字符
分别都会创建新的对象
常量池是PermGen的
因此应该是一共15字符
这是一个关于java的垃圾回收机制的题目。垃圾回收主要针对的是堆区的回收,因为栈区的内存是随着线程而释放的。堆区分为三个区:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)。
年轻代:对象被创建时(new)的对象通常被放在Young(除了一些占据内存比较大的对象),经过一定的Minor GC(针对年轻代的内存回收)还活着的对象会被移动到年老代(一些具体的移动细节省略)。
年老代:就是上述年轻代移动过来的和一些比较大的对象。Minor GC(FullGC)是针对年老代的回收
永久代:存储的是final常量,static变量,常量池。
str3,str4都是直接new的对象,而substring的源代码其实也是new一个string对象返回,如下图:
经过fullgc之后,年老区的内存回收,则年轻区的占了15个,不算PermGen。所以答案选C
10.存根(Stub)与以下哪种技术有关
A 交换
B 动态链接
C 动态加载
D 磁盘调度
答案 B
存根类是一个类,它实现了一个接口,它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法。但是一个类从业务来说,可能只需要其中一两个方法。如果直接去实现这个接口,除了实现所需的方法,还要实现其他所有的无关方法。而如果通过继承存根类就实现接口,就免去了这种麻烦。
RMI 采用stubs 和 skeletons 来进行远程对象(remote object)的通讯。stub 充当远程对象的客户端代理,有着和远程对象相同的远程接口,远程对象的调用实际是通过调用该对象的客户端代理对象stub来完成的。
每个远程对象都包含一个代理对象stub,当运行在本地Java虚拟机上的程序调用运行在远程Java虚拟机上的对象方法时,它首先在本地创建该对象的代理对象stub, 然后调用代理对象上匹配的方法。每一个远程对象同时也包含一个skeleton对象,skeleton运行在远程对象所在的虚拟机上,接受来自stub对象的调用。这种方式符合等到程序要运行时将目标文件动态进行链接的思想
11.Given the following code:
import EnclosingOne.InsideOne
1.class Enclosingone
2.{
3. public class InsideOne {}
4.
5.}
6.public class inertest
7.{
8. public static void main(string[]args)
9. {
10. EnclosingOne eo = new EnclosingOne();
11. //insert code here
12. }
13.
14.}
Which statement at line 11 constructs an instance of the inner class?
A InsideOne ei=eo.new InsideOne();
B eo.InsideOne ei=eo.new InsideOne();
C InsideOne ei=EnclosingOne.new InsideOne();
D EnclosingOne.InsideOne ei=eo.new InsideOne();
答案 A D
11.装箱、拆箱操作发生在: ()
A 类与对象之间
B 对象与对象之间
C 引用类型与值类型之间
D 引用类型与引用类型之间
答案 C
通俗的讲,就是基本数据类型和包装类之间的转换。如: int 类型和 Integer 类的转换
基本数据类型转化成包装类是装箱 (如: int --> Integer)。
包装类转化成基本数据类型就是拆箱 (如:Integer --> int)。
包装类就是引用类型,基本数据类型就是值类型。所以选C
12.下列哪种异常是检查型异常,需要在编写程序时声明?
A NullPointerException
B ClassCastException
C FileNotFoundException
D IndexOutOfBoundsException
13.假设 a 是一个由线程 1 和线程 2 共享的初始值为 0 的全局变量,则线程 1 和线程 2 同时执行下面的代码,最终 a 的结果不可能是()
boolean isOdd = false;
for(int i=1;i<=2;++i)
{
if(i%2==1)isOdd = true;
else isOdd = false;
a+=i*(isOdd?1:-1);
}
A -1
B -2
C 0
D 1
答案 D
首先,每个线程对a做的操作都是+1或者-2
其次,线程对a做的操作有可见不可见的问题.
- 如果线程A 做了+1,-2,结果是-1,此时如果该结果对于线程B 可见,那么再执行+1,-2,结果是-2;
- 如果线程A做了+1,-2,结果是-1,但是该结果对线程B并没有见到,那么线程B 最后依然以a==0开始计算,结果是0+1-2=-1,之前线程A 的结果也是-1,此时无论A和B谁的计算结果被最后刷新到公共内存,最后a的值都是-1;
- 如果线程A做了+1,该结果立即被B看到,B开始进行+1,-2,结果是0,如果该结果被刷新到内存的时机晚于线程A的计算结果,那么结果就是0.
14.线程安全的map在JDK 1.5及其更高版本环境 有哪几种方法可以实现?
A Map map = new HashMap()
B Map map = new TreeMap()
C Map map = new ConcurrentHashMap();
D Map map = Collections.synchronizedMap(new HashMap());
答案 C D
15.以下哪些jvm的垃圾回收方式采用的是复制算法回收
A 新生代串行收集器
B 老年代串行收集器
C 并行收集器
D 新生代并行回收收集器
E 老年代并行回收收集器
F cms收集器
答案 A D
两个最基本的java回收算法:复制算法和标记清理算法
复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法
标记清理:一块区域,标记可达对象(可达性分析),然后回收不可达对象,会出现碎片,那么引出
标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象
两个概念:新生代和年老代
新生代:初始对象,生命周期短的
永久代:长时间存在的对象
整个java的垃圾回收是新生代和年老代的协作,这种叫做分代回收。
P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法
Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理
Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法
Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理
Parallel Old(并行)收集器,针对老年代,标记整理
CMS收集器,基于标记清理
G1收集器:整体上是基于标记 整理 ,局部采用复制
综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理。
16.下列有关Thread的描述,哪个是正确的?
A 启动一个线程的方法是:thread. run()
B 结束一个线程的通常做法是:thread. stop()
C 将一个线程标记成daemon线程,意味着当主线程结束,并且没有其它正在运行的非daemon线程时,该daemon线程也会自动结束。
D 让一个线程等待另一个线程的通知的方法是:thread. sleep()
答案 C
1.启动一个线程的方法是 start()
2.结束线程用的是interrupt()方法,而stop()是强制结束线程,并不推荐使用,同时stop()方法已被弃用
3.daemon线程是守护线程,当主线程结束时,守护线程会自动结束
4.一个线程等待另外一个线程的方法是wait()方法
17.以下哪项陈述是正确的?
A 垃圾回收线程的优先级很高,以保证不再 使用的内存将被及时回收
B 垃圾收集允许程序开发者明确指定释放 哪一个对象
C 垃圾回收机制保证了JAVA程序不会出现 内存溢出
D 进入”Dead”状态的线程将被垃圾回收器回收
E 以上都不对
答案 E
A: 垃圾回收在jvm中优先级相当相当低。
B:垃圾收集器(GC)程序开发者只能推荐JVM进行回收,但何时回收,回收哪些,程序员不能控制。
C:垃圾回收机制只是回收不再使用的JVM内存,如果程序有严重BUG,照样内存溢出。
D:进入DEAD的线程,它还可以恢复,GC不会回收
18.下列哪个说法是正确的()
A ConcurrentHashMap使用synchronized关键字保证线程安全
B HashMap实现了Collction接口
C Array.asList方法返回java.util.ArrayList对象
D SimpleDateFormat是线程不安全的
答案 D
A、ConcurrentHashMap实际上时 HashTable的升级版,使用segment来分段和管理锁,并不是synchronized;
B、 HashMap实现的接口有:Serializable, Cloneable, Map<K,V> ,没有实现Cllectio
C、Arrays.asList()方法返回的列表是Arrays.ArrayList类型的,并不是java.util.ArrayList;
D、正确
19.以下代码在编译和运行过程中会出现什么情况
public class TestDemo{
private int count;
public static void main(String[] args) {
TestDemo test=new TestDemo(88);
System.out.println(test.count);
}
TestDemo(int a) {
count=a;
}
}
A 编译运行通过,输出结果是88
B 编译时错误,count变量定义的是私有变量
C 编译时错误,System.out.println方法被调用时test没有被初始化
D 编译和执行时没有输出结果
答案 A
private是私有变量,只能用于当前类中,题目中的main方法也位于当前类,所以可以正确输出
20.下列方法中哪个是线程执行的方法? ()
A run()
B start()
C sleep()
D suspend()
答案 A
run()方法用来执行线程体中具体的内容
start()方法用来启动线程对象,使其进入就绪状态
sleep()方法用来使线程进入睡眠状态
suspend()方法用来使线程挂起,要通过resume()方法使其重新启动