牛客错题集

持续更新中

1.对接口的描述正确的是()

A.一个类可以实现多个接口

B.接口可以有非静态的成员变量

C.在jdk8之前,接口可以实现方法

D.实现接口的任何类,都需要实现接口的方法

解析:
答案:A
A,一个类只能有一个直接父类,但是继承是有传递性的。一个类可以实现多的接口。一个接口可以继承多个类。
B,接口中没有普通变量(普通成员变量),接口中都是常量,默认修饰符:public static final
C,JDK8之前,接口中的方法都是默认public abstract的,JDK8之后,接口中可以有static、default的修饰的方法,一旦被修饰,方法必须有方法体(抽象方法是可以没有方法体的),接口中的方法都不能被private和protected修饰,同时外部接口、类只能被public修饰或者不写,但是内部接口、类可以被四个访问修饰符修饰。
D, 实现接口,其实就是需要重写接口中的abstract方法,一旦实现的类没有重写完,那么这个类必须是个抽象类(抽象类中可以没有抽象方法,但是有抽象方法的类必须是抽象类)。

2.在 applet 的方法中 , 可关闭小应用程序并释放其占用资源的是( )

A.stop()

B.paint()

C.init()

D.destroy()

解析:
答案:D
Applet 类是浏览器类库中最为重要的类,同时也是所有 JAVA 小应用程序的基本类。 一个 Applet 应用程序从开始运行到结束时所经历的过程被称为 Applet 的生命周期。 Applet 的生命周期涉及 init() 、 start() 、 stop() 和 destroy() 四种方法,这 4 种方法都是 Applet 类的成员,可以继承这些方法,也可以重写这些方法,覆盖原来定义的这些方法。除此之外,为了在 Applet 程序中实现输出功能,每个 Applet 程序中还需要重载 paint() 方法:
1、 public void init()
init()方法是 Applet 运行的起点。当启动 Applet 程序时,系统首先调用此方法,以执行初始化任务。
2、 public void start()
start()方法是表明 Applet 程序开始执行的方法。当含有此 Applet 程序的 Web 页被再次访问时调用此方法。因此,如果每次访问 Web 页都需要执行一些操作的话,就需要在 Applet 程序中重载该方法。在 Applet 程序中,系统总是先调用 init() 方法,后调用 start() 方法。
3、 public void stop()
stop()方法使 Applet 停止执行,当含有该 Applet 的 Web 页被其他页代替时也要调用该方法。
4、 public void destroy()
destroy()方法收回 Applet 程序的所有资源,即释放已分配给它的所有资源。在 Applet 程序中,系统总是先调用 stop() 方法,后调用 destroy() 方法。
5、 paint(Graphics g)
paint(Graphics g)方法可以使 Applet 程序在屏幕上显示某些信息,如文字、色彩、背景或图像等。参数 g 是 Graphics 类的一个对象实例,实际上可以把 g 理解为一个画笔。对象 g 中包含了许多绘制方法,如 drawstring() 方法就是输出字符串。

3.java语言的下面几种数组复制方法中,哪个效率最高?

A.for 循环逐一复制

B.System.arraycopy

C.Array.copyOf

D.使用clone方法

解析:
答案:B
复制的效率System.arraycopy>clone>Arrays.copyOf>for循环
这里面在System类源码中给出了arraycopy的方法,是native方法,也就是本地方法,肯定是最快的。而Arrays.copyOf(注意是Arrays类,不是Array)的实现,在源码中是调用System.copyOf的,多了一个步骤,肯定就不是最快的

4.有关会话跟踪技术描述正确的是()

A.Cookie是Web服务器发送给客户端的一小段信息,客户端请求时,可以读取该信息发送到服务器端

B.关闭浏览器意味着临时会话ID丢失,但所有与原会话关联的会话数据仍保留在服务器上,直至会话过期

C.在禁用Cookie时可以使用URL重写技术跟踪会话

D.隐藏表单域将字段添加到HTML表单并在客户端浏览器中显示

解析:
答案:A B C
1.session用来表示用户会话,session对象在服务端维护,一般tomcat设定session生命周期为30分钟,超时将失效,也可以主动设置无效;
2.cookie存放在客户端,可以分为内存cookie和磁盘cookie。内存cookie在浏览器关闭后消失,磁盘cookie超时后消失。当浏览器发送请求时,将自动发送对应cookie信息,前提是请求url满足cookie路径;
3.可以将sessionId存放在cookie中,也可以通过重写url将sessionId拼接在url。因此可以查看浏览器cookie或地址栏url看到sessionId;
4.请求到服务端时,将根据请求中的sessionId查找session,如果可以获取到则返回,否则返回null或者返回新构建的session,老的session依旧存在
5.隐藏域在页面中对于用户是不可见的,在表单中插入隐藏域的目的在于收集或发送信息,以利于被处理表单的程序所使用。浏览者单击发送按钮发送表单的时候,隐藏域的信息也被一起发送到服务器。

5.在使用super和this关键字时,以下描述错误的是()

A.在子类构造方法中使用super()显示调用父类的构造方法,super()必须写在子类构造方法的第一行,否则编译不通过

B.super()和this()不一定要放在构造方法内第一行

C.this()和super()可以同时出现在一个构造函数中

D.this()和super()可以在static环境中使用,包括static方法和static语句块

解析:
答案:B C D
1.super和this都只能位于构造器的第一行,而且不能同时使用,这是因为会造成初始化两次,this用于调用重载的构造器,super用于调用父类被子类重写的方法,由于super()和this()必须在构造函数第一行,所以这一点也表明他俩不能在一个构造函数中
2.super()表示调用父类构造函数、this()调用自己的构造函数,而自己的构造函数第一行要使用super()调用父类的构造函数,所以这俩不能在一个构造函数中会出现重复引用的情况
3.this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块(里面不能使用非static类型的)。因为static修饰的方法不能存在this指针

6.下面有关forward和redirect的描述,正确的是() ?

A.forward是服务器将控制权转交给另外一个内部服务器对象,由新的对象来全权负责响应用户的请求

B.执行forward时,浏览器不知道服务器发送的内容是从何处来,浏览器地址栏中还是原来的地址

C.执行redirect时,服务器端告诉浏览器重新去请求地址

D.forward是内部重定向,redirect是外部重定向

E.redirect默认将产生301 Permanently moved的HTTP响应

解析:
答案:B C D
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:高.
redirect:低.

7.下面有关forward和redirect的描述,正确的是() ?

A.forward是服务器将控制权转交给另外一个内部服务器对象,由新的对象来全权负责响应用户的请求

B.执行forward时,浏览器不知道服务器发送的内容是从何处来,浏览器地址栏中还是原来的地址

C.执行redirect时,服务器端告诉浏览器重新去请求地址

D.forward是内部重定向,redirect是外部重定向

E.redirect默认将产生301 Permanently moved的HTTP响应

解析:
答案:B C D
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:高.
redirect:低.

8.执行下列代码的输出结果是( )

public class Demo{
 public static void main(String args[]){
   int num = 10;
   System.out.println(test(num));
}
public static int test(int b){
   try
   {
    b += 10;
    return b;
   }
   catch(RuntimeException e)
   {
   }
   catch(Exception e2)
   {
   }
   finally
   {
    b += 10;
    return b;
   }
  }
}

A.10

B.20

C.30

D.40

解析:
答案:C
如果finally块中有return语句的话,它将覆盖掉函数中其他return语句。

9.若有定义语句: int a=10 ; double b=3.14 ; 则表达式 ‘A’+a+b 值的类型是()

A.char

B.int

C.double

D.float

解析:
答案:C
不同类型运算结果类型向右边靠齐。
char < short < int < float < double

10.下面论述正确的是()?

A.如果两个对象的hashcode相同,那么它们作为同一个HashMap的key时,必然返回同样的值

B.如果a,b的hashcode相同,那么a.equals(b)必须返回true

C.对于一个类,其所有对象的hashcode必须不同

D.如果a.equals(b)返回true,那么a,b两个对象的hashcode必须相同

解析:
答案:D
hashCode()方法和equals()方法的作用其实是一样的,在Java里都是用来对比两个对象是否相等一致。
那么equals()既然已经能实现对比的功能了,为什么还要hashCode()呢?因为重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
那么hashCode()既然效率这么高为什么还要equals()呢? 因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,
所以我们可以得出:
1.equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
所有对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equals(),如果equals()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!

11.下面程序的输出结果为()

public class Demo {
 public static String sRet = "";
 public static void func(int i)
 {
 try
 {
 if (i%2==0)
 {
 throw new Exception();
 }
 }
 catch (Exception e)
 {
 sRet += "0";
 return;
 } 
 finally
 {
 sRet += "1";
 }
 sRet += "2";
 }
 public static void main(String[] args)
 {
 func(1);
 func(2);
 System.out.println(sRet);
 }
 }

A.120

B.1201

C.12012

D.101

解析:
答案:B

  • 调用func(1),if不符合,直接进入finally,sRet=“1"
  • finally语句中没有返回值,故继续向下执行,sRet=“12”
  • 调用func(2),if符合,sRet=“120”,此时有返回值!!!
  • 调用finally语句,sRet=“1201”
  • 因为已经有返回值了,finally之后的语句也不再执行,sRet=“1201”。

12.在java7中,下列不能做switch()的参数类型是?

A.int型

B.枚举类型

C.字符串

D.浮点型

解析:
答案:D
switch语句后的控制表达式只能是short、char、int、String、long整数类型和枚举类型,不能是float,double和boolean类型。String类型是java7开始支持。

13.以下代码可以使用的修饰符是:()

A.final

B.static

C.abstract

D.public

解析:
答案:C

  • 接口中字段的修饰符:public static final(默认不写)
  • 接口中方法的修饰符:public abstract(默认不写)
    abstract只能修饰类和方法 不能修饰字段

14.下面有关java classloader说法错误的是?

A.Java默认提供的三个ClassLoader是BootStrap ClassLoader,Extension ClassLoader,App ClassLoader

B.ClassLoader使用的是双亲委托模型来搜索类的

C.JVM在判定两个class是否相同时,只用判断类名相同即可,和类加载器无关

D.ClassLoader就是用来动态加载class文件到内存当中用的

解析:
答案:C
在这里插入图片描述

一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:

  • Bootstrap ClassLoader 负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
  • Extension ClassLoader 负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
  • App ClassLoader负责加载当前java应用的classpath中的所有类。
    classloader 加载类用的是全盘负责委托机制。 所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入。
    所以,当我们自定义的classloader加载成功了 com.company.MyClass以后,MyClass里所有依赖的class都由这个classLoader来加载完成。

比较两个类是否相等,只有这两个类是由同一个类加载器加载才有意义。否则,即使这两个类是来源于同一个Class文件,只要加载它们的类加载器不同,那么这两个类必定不相等。

补充:

1. 什么是类加载器?

把类加载的过程放到Java虚拟机外部去实现,让应用程序决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。

2. 有哪些类加载器,分别加载哪些类

类加载器按照层次,从顶层到底层,分为以下三种:
(1)启动类加载器 : 它用来加载 Java 的核心库,比如String、System这些类
(2)扩展类加载器 : 它用来加载 Java 的扩展库。
(3) 应用程序类加载器 : 负责加载用户类路径上所指定的类库,一般来说,Java 应用的类都是由它来完成加载的。

3. 双亲委派模型

我们应用程序都是由以上三种类加载器互相配合进行加载的,还可以加入自己定义的类加载器。称为 类加载器的双亲委派模型 ,这里类加载器之间的父子关系一般不会以继承的关系来实现,而是都使用 组合关系 来复用父加载器的。

4. 双亲委托模型的工作原理

是当一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法加载这个加载请求的时候,子加载器才会尝试自己去加载。

5. 使用双亲委派模型好处?(原因)

第一:可以避免重复加载,当父亲已经加载了该类的时候,子类不需要再次加载。
第二:考虑到安全因素,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的类装载器。

15.以下程序执行的结果是:

class X{
	Y y=new Y();
	public X(){
		System.out.print("X");
	}
}
class Y{
	public Y(){
		System.out.print("Y");
	}
}
public class Z extends X{
	Y y=new Y();
	public Z(){
		System.out.print("Z");
	}
	public static void main(String[] args) {
		new Z();
	}
}

A.ZYXX

B.ZYXY

C.YXYZ

D.ClaXYZXssLoader就是用来动态加载class文件到内存当中用的

解析:
答案:C
初始化过程:

  • 初始化父类中的静态成员变量和静态代码块 ;
  • 初始化子类中的静态成员变量和静态代码块 ;
  • 初始化父类的普通成员变量和代码块,再执行父类的构造方法;
  • 初始化子类的普通成员变量和代码块,再执行子类的构造方法;

(1)初始化父类的普通成员变量和代码块,执行 Y y=new Y(); 输出Y
(2)再执行父类的构造方法;输出X
(3) 初始化子类的普通成员变量和代码块,执行 Y y=new Y(); 输出Y
(4)再执行子类的构造方法;输出Z
所以输出YXYZ

16.下列语句:int *p, a = 10; p = &a.

均表示地址的是()

A.a , p, &a

B.&*a,&a,*p

C.*&p, *p, &a

D.&a, p, &*p

解析:
答案:D

  • *p表示指针p
  • &a表示取a的内存地址
  • p = &a 表示p等于a的内存地址
  • &*p表示获取指针p的内存地址
  • *&p表示指向P内存地址的一个指针

17.ArrayList list = new ArrayList(20);中的list扩充几次

A.0

B.1

C.2

D.3

解析:
答案:A
Arraylist默认数组大小是10,扩容后的大小是扩容前的1.5倍,最大值小于Integer 的最大值减8,如果新创建的集合有带初始值,默认就是传入的大小,也就不会扩容,由于本地在创建数组时直接分配了内存大小,所以不会扩充

18.Thread. sleep()是否会抛出checked exception?

A.会

B.不会

解析:
答案:A
checked exception:指的是编译时异常,该类异常需要本函数必须处理的,用try和catch处理,或者用throws抛出异常,然后交给调用者去处理异常。
runtime exception:指的是运行时异常,该类异常不必须本函数必须处理,当然也可以处理。
Thread.sleep()抛出的InterruptException属于checked exception;IllegalArgumentException属于Runtime exception;

19.关于String、StringBuffer、StringBuilder以下说法错误的是

A.StringBuilder运行速度最快

B.StringBuffer是线程安全的

C.String的值是可变的

D.StringBuffer运行速度比String快

解析:
答案:C

  • String

String不可变!先来看看String的源码:

 public final class String implements Serializable, Comparable<String>, CharSequence {
    private final byte[] value;
    private final byte coder;
    private int hash;
    private static final long serialVersionUID = -6849794470754667710L;
    .......}

1、String由final修饰,说明final不能被继承,不能被修改
2、String用来存储数据的是字节数组 byte[] ,同样也是由final修饰的。
3、虽然字节数组value是由final修饰,但是我们要清楚一个原则就是:String是引用型变量,要清楚在String的数组是放在堆中的,然后将栈中放的是数组在堆中的引用地址,而我们通常所用的就是一个指向堆中真实数组数据的一个引用地址,所以也称String为引用型对象。简而言之:引用地址不可变,但是地址指向的堆中的数组数据是可以改变的。一旦创建了一个String对象,就在内存中申请一片固定的地址空间存放数据,不管怎么变,地址是不会变的,但是地址所指向的空间真实存放的数据是可以改变的。再通俗点就是:你家的门牌号不会变,但是你家要住几口人是你说了算。

  • StringBuffer

先来看下StringBuffer的源码:

   public synchronized StringBuffer append(String str) {
        this.toStringCache = null;
        super.append(str);
        return this;
    }

由于有关键字synchronize,所以线程安全。

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

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

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

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

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

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

解析:
答案:C

  • 基本数据类型包括byte,short,int,long,float,double,char,boolean
  • C语言当中String是以“\0”结尾的char类型的数组char[],java不是, String内部是用char[]数组实现的,不过结尾不用\0。
  • char存储的unicode码,不仅可以存储ascII码,汉字也可以。

21.如下的Java程序

public class Test { 
     public static void main(String[] args) { 
     System.out.println(args[0]); 
     } 
}

若采用命令行“java Test one two three”调用,则程序输出的结果为:

A.Test

B.one

C.two

D.java

解析:
答案:B
采用命令行“ java Test one two three ”调用
其中Test为调用的方法,而one two three则为Test方法里面main函数的参数;
System.out.println(args[0]);表示输出第一个元素,故为one;

22.从内存实现或者反射的角度来看,关于继承的说法正确的是()。

注:此处的继承不代表能调用

A.子类将继承父类的所有的数据域和方法

B.子类将继承父类的其可见的数据域和方法

C.子类只继承父类public方法和数据域

D.子类只继承父类的方法,而不继承数据域

解析:
答案:A
在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。所以所谓的继承使子类拥有父类所有的属性和方法其实可以这样理解,子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。就像有些东西你可能拥有,但是你并不能使用。所以子类对象是绝对大于父类对象的,所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。

23.java中 String str = "hello world"下列语句错误的是?

A.str+=’ a’

B.int strlen = str.length

C.str=100

D.str=str+100

解析:
答案:ABC

  • str += ‘a’ 和 str +="a"都是对的,但是如果a前面加一个空格,那么只能用双引号了。代表字符串
  • str += ‘a’ 和 str +="a"都是对的,但是如果a前面加一个空格,那么只能用双引号了。代表字符串
  • int 无法直接转成String类型

24.下列有关JAVA异常处理的叙述中正确的是()

A.finally是为确保一段代码不管是否捕获异常都会被执行的一段代码

B.throws是用来声明一个成员方法可能抛出的各种非运行异常情况

C.final用于可以声明属性和方法,分别表示属性的不可变及方法的不可继承

D.throw是用来明确地抛出一个异常情况

解析:
答案:ABD

  • throw 用于方法块里面的 代码,比throws的层次要低,比如try…catch …语句块,表示它抛出异常,但它不会处理它
final
  • 用于类 ---- 说明该类无法被继承,实例:String类
  • 用于方法-----说明该方法无法被覆盖,实例:final不能与abstract关键字同时使用
  • final用于变量-----说明属性不可变(可用于静态和非静态属性),但多和staic连用,表示常量

25.判断对错。List,Set,Map都继承自继承Collection接口。

A.对

B.错

解析:
答案:B
在这里插入图片描述

26.以下哪个命令用于查看tar(backup.tar)文件的内容而不提取它?()

A.tar -xvf backup.tar

B.tar -tvf backup.tar

C.tar -svf backup.tar

D.none of these

解析:
答案:B
把常用的tar解压命令总结下,当作备忘:

tar

-c: 建立压缩档案
-x:解压
-t:查看内容
-r:向压缩归档文件末尾追加文件
-u:更新原压缩包中的文件
这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。
-z:有gzip属性的
-j:有bz2属性的
-Z:有compress属性的
-v:显示所有过程
-O:将文件解开到标准输出
下面的参数-f是必须的
-f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名。

压缩
  • tar –cvf jpg.tar *.jpg 将目录里所有jpg文件打包成tar.jpg
  • tar –czf jpg.tar.gz *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz
  • tar –cjf jpg.tar.bz2 *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2
  • tar –cZf jpg.tar.Z *.jpg 将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z
  • rar a jpg.rar *.jpg rar格式的压缩,需要先下载rar for linux
  • zip jpg.zip *.jpg zip格式的压缩,需要先下载zip for linux
解压
  • tar –xvf file.tar 解压 tar包
  • tar -xzvf file.tar.gz 解压tar.gz
  • tar -xjvf file.tar.bz2 解压 tar.bz2
  • tar –xZvf file.tar.Z 解压tar.Z
  • unrar e file.rar 解压rar
  • unzip file.zip 解压zip
总结
  • *.tar 用 tar –xvf 解压
  • *.gz 用 gzip -d或者gunzip 解压
  • .tar.gz和.tgz 用 tar –xzf 解压
  • *.bz2 用 bzip2 -d或者用bunzip2 解压
  • *.tar.bz2用tar –xjf 解压
  • *.Z 用 uncompress 解压
  • *.tar.Z 用tar –xZf 解压
  • *.rar 用 unrar e解压
  • *.zip 用 unzip 解压

27.以下哪个类包含方法flush()?()

A.InputStream
B.OutputStream
C.A和B 选项都包含
D.A和B 选项都不包含
答案:B
解析:

flush()函数强制将缓冲区中的字符流、字节流等输出,目的是如果输出流输出到缓冲区完成后,缓冲区并没有填满,那么缓冲区将会一直等待被填满。所以在关闭输出流之前要调用flush()。

28.Java数据库连接库JDBC用到哪种设计模式?

A.生成器
B.桥接模式
C.抽象工厂
D.单例模式
答案:B
解析:
  • 桥接模式:
    定义 :将抽象部分与它的实现部分分离,使它们都可以独立地变化。
    意图 :将抽象与实现解耦。
    桥接模式所涉及的角色
  1. Abstraction :定义抽象接口,拥有一个Implementor类型的对象引用
  2. RefinedAbstraction :扩展Abstraction中的接口定义
  3. Implementor :是具体实现的接口,Implementor和RefinedAbstraction接口并不一定完全一致,实际上这两个接口可以完全不一样Implementor提供具体操作方法,而Abstraction提供更高层次的调用
  4. ConcreteImplementor :实现Implementor接口,给出具体实现
    Jdk中的桥接模式:JDBC
    JDBC连接 数据库 的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不动,原因就是JDBC提供了统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了
  • 抽象工厂
    抽象工厂模式包含了几个角色:
    AbstractFactory:用于声明生成抽象产品的方法
    ConcreteFactory:实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中;
    AbstractProduct:为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;
    Product:定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。
    这是它的通用类图:
    在这里插入图片描述

其中 AbstractProductA 和 AbstractProductB 就是两个产品族的抽象类 (或者接口),而 Product1 和 Product2 就是产品族下的具体产品类,AbstractCreator 就是工厂的抽象。

29.以下代码的输出结果是?

public class B
{
    public static B t1 = new B();
    public static B t2 = new B();
    {
        System.out.println("构造块");
    }
    static
    {
        System.out.println("静态块");
    }
    public static void main(String[] args)
    {
        B t = new B();
    }
}
A.静态块 构造块 构造块 构造块
B.构造块 静态块 构造块 构造块
C.构造块 构造块 静态块 构造块
D.构造块 构造块 构造块 静态块
答案:C
解析:

大致的执行过程如下:

  • 1.实例化t之后,先执行实例化t1,此时会默认执行构造函数,即执行
{
       System.out.println("构造块");
   }

所以控制台输出构造块,紧接着实例化t2,继续执行构造函数所以控制台接着打印构造块,现在控制台情况如下:
在这里插入图片描述

 public static B t1 = new B();
 public static B t2 = new B();

执行完成之后接着就会按照顺序执行静态代码块

static
   {
       System.out.println("静态块");
   }

此时输出静态块,最后会执行t的构造函数,即输出构造块
在这里插入图片描述

30.下面哪几个函数 public void example(){…} 的重载函数?()

A.public void example(int m){…}
B.public int example(){…}
C.public void example2(){…}
D.public int example(int m,float f){…}
答案:A,D
解析:

重载只要求参数列表不同,返回值无关。

31.Java 语言用以下哪个类来把基本类型数据封装为对象()

A.包装类
B.Class
C.Math
D.Object
答案:A
解析:

java的数据类型分为两大类:基本类型和引用类型;
基本类型只能保存一些常量数据,引用类型除了可以保存数据,还能提供操作这些数据的功能;
为了操作基本类型的数据,java也对它们进行了封装, 得到八个类,就是java中的基本类型的封装类;他们分别是:
八种基本类型: byte short int long float double char boolean
对应的包装类 : Byte Short Integer Long Float Double Character Boolean

32.有以下类定义:

abstract class Animal{
	abstract void say();
}
public class Cat extends Animal{
	public Cat(){
		System.out.printf("I am a cat");
	}
	public static void main(String[] args) {
		Cat cat=new Cat();
	}
}

运行后:

A.I am a cat
B.Animal能编译,Cat不能编译
C.Animal不能编译,Cat能编译
D.编译能通过,但是没有输出结果
答案:B
解析:

包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:
1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2)抽象类不能用来创建对象;
3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
在其他方面,抽象类和普通的类并没有区别。

33.有时为了避免某些未识别的异常抛给更高的上层应用,在某些接口实现中我们通常需要捕获编译运行期所有的异常, catch 下述哪个类的实例才能达到目的:()

A.Error
B.Exception
C.RuntimeException
D.Throwable
答案:B
解析:

在这里插入图片描述

因为error是系统出错,catch是无法处理的,难以修复的,RuntimeException不需要程序员进行捕获处理,error和exception都是throwable的子类,我们只需要对exception的实例进行捕获即可

34.关于abstract类的声明和描述

1、abstract类不能用来创建abstract类的对象;
2、final类不能用来派生子类,因为用final修饰的类不能被继承;
3、如2所述,final不能与abstract同时修饰一个类,abstract类就是被用来继承的;
4、类中有abstract方法必须用abstract修饰,但abstract类中可以没有抽象方法,接口中也可以有abstract方法。

35.下面有关java threadlocal说法正确的有?

A.ThreadLocal存放的值是线程封闭,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递
B.线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收
C.在Thread类中有一个Map,用于存储每一个线程的变量的副本。
D.对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式
答案:B
解析:
  • ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程的上下文。 可以总结为一句话:ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
    举个例子,我出门需要先坐公交再做地铁,这里的坐公交和坐地铁就好比是同一个线程内的两个函数,我就是一个线程,我要完成这两个函数都需要同一个东西:公交卡(北京公交和地铁都使用公交卡),那么我为了不向这两个函数都传递公交卡这个变量(相当于不是一直带着公交卡上路),我可以这么做:将公交卡事先交给一个机构,当我需要刷卡的时候再向这个机构要公交卡(当然每次拿的都是同一张公交卡)。这样就能达到只要是我(同一个线程)需要公交卡,何时何地都能向这个机构要的目的。 有人要说了:你可以将公交卡设置为全局变量啊,这样不是也能何时何地都能取公交卡吗?但是如果有很多个人(很多个线程)呢?大家可不能都使用同一张公交卡吧(我们假设公交卡是实名认证的),这样不就乱套了嘛。现在明白了吧?这就是ThreadLocal设计的初衷:提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程。
  • ThreadLocal类用于创建一个线程本地变量
    在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map,它的键是threadLocal,值为就是变量的副本。通过ThreadLocal的get()方法可以获取该线程变量的本地副本,在get方法之前要先set,否则就要重写initialValue()方法。
    ThreadLocal的使用场景:
    数据库连接:在多线程中,如果使用懒汉式的单例模式创建Connection对象,由于该对象是共享的,那么必须要使用同步方法保证线程安全,这样当一个线程在连接数据库时,那么另外一个线程只能等待。这样就造成性能降低。如果改为哪里要连接数据库就来进行连接,那么就会频繁的对数据库进行连接,性能还是不高。这时使用ThreadLocal就可以既可以保证线程安全又可以让性能不会太低。但是ThreadLocal的缺点时占用了较多的空间。

36.判断一块内存空间是否符合垃圾收集器收集的标准有哪些?

A.给对象赋予了空值null,以下再没有调用过
B.对象重新分配了内存空间
C.给对象赋予了空值null
D.给对象赋予了新值
答案:B
解析:

在java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个:
1.给对象赋值为null,以下没有调用过。
2.给对象赋了新的值,重新分配了内存空间。

37. 父类,子类的方法以及静态代码块执行的顺序

执行顺序为

  • 1.父类静态代码块、静态变量 ps:按声明顺序执行
  • 2.子类静态代码块、静态变量 ps:按声明顺序执行
  • 3.父类局部代码块、成员变量 ps:按声明顺序执行
  • 4.父类构造函数
  • 5.子类局部代码块、成员变量 ps:按声明顺序执行
  • 6.子类构造函数

38.

Integer a = 1;
Integer b = 1;
Integer c = 500;
Integer d = 500;
System.out.print(a == b);
System.out.print(c == d);
A.true、true
B.true、false
C.false、true
D.false、false
答案:B
解析:

Integer a = 1;是自动装箱会调用Interger.valueOf(int)方法;该方法注释如下:
This method will always *** values in the range -128 to > 127 inclusive, and may *** other values outside of this range.
也就是说IntegerCache类缓存了-128到127的Integer实例,在这个区间内调用valueOf不会创建新的实例。

39.访问权限控制从最大权限到最小权限依次为:public、 包访问权限、protected和private 。( )

A.正确
B.错误
答案:B
解析:

在这里插入图片描述

40.()运算符把其操作数中所有值为0和所有值为1的位分别在结果的相应中设置1和0

A.&
B.|
C.!
D.~
答案:D
解析:

~是位运算符,意义是 按位非(NOT)
按位非也叫做补,一元运算符NOT“~”是对其运算数的每一位取反。
仅用于整数值
反转位,即0位变为1位,1变成0
在所有情况下〜x等于(-x)- 1

例如:

~ 0111 (7) = 1000 (8)

41.在java中重写方法应遵循规则的包括()

A.访问修饰符的限制一定要大于被重写方法的访问修饰符
B.可以有不同的访问修饰符
C.参数列表必须完全与被重写的方法相同
D.必须具有不同的参数列表
答案:B C
解析:

方法的重写(override)两同两小一大原则:
方法名相同,参数类型相同
子类返回类型小于等于父类方法返回类型,
子类抛出异常小于等于父类方法抛出异常,
子类访问权限大于等于父类方法访问权限。

42.Java创建对象的方式

Java有5种方式来创建对象:

  • 1.使用 new 关键字(最常用)
ObjectName obj = new ObjectName();
  • 2.使用反射的Class类的newInstance()方法
ObjectName obj = ObjectName.class.newInstance();
  • 3.使用反射的Constructor类的newInstance()方法
 ObjectName obj = ObjectName.class.getConstructor.newInstance();
  • 4.使用对象克隆clone()方法:
ObjectName obj = obj.clone(); 
  • 5.使用反序列化(ObjectInputStream)的readObject()方法:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) { ObjectName obj = ois.readObject(); }

43.下列哪些操作会使线程释放锁资源?

A.sleep()
B.wait()
C.join()
D.yield()
答案:B C
解析:
  • 1.sleep()方法

在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。
sleep()使当前线程进入阻塞状态,在指定时间内不会执行。

  • 2.wait()方法

在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。
当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。
唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。
waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

  • 3.yield方法

暂停当前正在执行的线程对象。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
yield()只能使同优先级或更高优先级的线程有执行的机会。

  • 4.join方法

join()等待该线程终止。
等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测

44.以下程序运行的结果为 ( )

public class Example extends Thread{
@Override

    public void run(){

        try {

            Thread.sleep(1000);

        } catch (InterruptedException e){

            e.printStackTrace();

        }

        System. out .print( "run" );

    }

    public static void main(String[] args){

        Example example= new Example();

        example.run();

        System. out .print( "main" );

    }
}
A.run main
B.main run
C.main
D.run
E.不能确定
答案:A
解析:

为啥是runmain而不是mainrun呢?

  • 因为启动线程是调用start方法。
  • 把线程的run方法当普通方法,就直接用实例.run()执行就好了。
  • 没有看到start。所以是普通方法调用。

45.下面有关servlet service描述错误的是?

A.不管是post还是get方法提交过来的连接,都会在service中处理
B.doGet/doPost 则是在 javax.servlet.GenericServlet 中实现的
C. service()是在javax.servlet.Servlet接口中定义的
D.service判断请求类型,决定是调用doGet还是doPost方法
答案:B
解析:

在这里插入图片描述

doget/dopost与Http协议有关,是在 javax.servlet.http.HttpServlet 中实现的

46.java运行时内存分为“线程共享”和“线程私有”两部分,以下哪些属于“线程共享”部分

A.程序计算器
B.方法区
C.java虚拟机栈
D.java堆
答案:B D
解析:

共享的资源有:

  • 堆 由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的)
  • 全局变量 它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的
  • 静态变量 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的
  • 文件等公用资源 这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。
    独享的资源有
  • 栈 栈是独享的
  • 寄存器 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC

47.下面哪些描述是正确的:( )

public class Test {
public static class A {
private B ref;
public void setB(B b) {
ref = b;
}
}
public static Class B {
private A ref;
public void setA(A a) {
ref = a;
}
}
public static void main(String args[]) {start();.
}
public static void start() { 
    A a = new A();
    B b = new B();
    a.setB(b);
    b = null; //
    a = null;}
}
A.b = null执行后b可以被垃圾回收
B.a = null执行后b可以被垃圾回收
C.a = null执行后a可以被垃圾回收
D.a,b必须在整个程序结束后才能被垃圾回收
E.类A和类B在设计上有循环引用,会导致内存泄露
F.a, b 必须在start方法执行完毕才能被垃圾回收
答案:B C
解析:

在这里插入图片描述

  • 首先在栈中 创建A,B两个对象,假设A对象所在地址为address1,B对象地址为address2
  • 执行new A操作后会有一个指向address1的地址
  • 执行new B之后也会有一个指向address2的地址
  • 接下来执行a.setB(b) 此时会有b,以及ref两个变量指向address2
  • 执行b=null操作那么b就不在会指向address2,但是ref仍然指向address2,所以此时还无法回收b
  • 执行a=null操作,那么所有的变量都不在指向address2,且所有的变量也都不在指向address1,所以a,b所指向的地址均可被回收

48.局部内部类可以用哪些修饰符修饰?

A.public
B.private
C.abstract
D.final
答案:C D
解析:

在这里插入图片描述

局部内部类是放在代码块或方法中的,不能有访问控制修饰符,且不能用static修饰

49.Java.Thread的方法resume()负责重新开始被以下哪个方法中断的线程的执行()。

A.stop
B.sleep
C.wait
D.suspend
答案:D
解析:

线程的五大状态及其转换

  • resume与suspended一起使用 wait与notify(notifyAll)一起使用 sleep会让线程暂时不执行 suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume() 被调用,才能使得线程重新进入可执行状态。
  • 线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。
  • 1.新建状态(New): 当用new操作符创建一个线程时, 例如new Thread®,线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码
  • 2.就绪状态(Runnable)
  • 一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。
    当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,
    并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
    处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU
    时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能
    同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个
    线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度
    程序(thread scheduler)来调度的。
  • 3.运行状态(Running)
    当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
  • 4.阻塞状态(Blocked)
    线程运行过程中,可能由于各种原因进入阻塞状态: 1>线程通过调用sleep方法进入睡眠状态; 2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者; 3>线程试图得到一个锁,而该锁正被其他线程持有; 4>线程在等待某个触发条件; …
    所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间, 进入运行状态。
  • 5.死亡状态(Dead)
    有两个原因会导致线程死亡:
    run方法正常退出而自然死亡,
    一个未捕获的异常终止了run方法而使线程猝死。 为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是 可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了, 则返回false.

50.以下程序的运行结果是?

在这里插入图片描述

A.foobar
B.barfoo
C.foobar或者barfoo都有可能
D.Bar
E.Foo
F.程序无法正常运行
答案:A
解析:
  • 线程的启动方式只能通过start这种方式启动才能真正的实现多线程的效果
  • 如果是手动调用run方法和普通方法调用没有区别,所以这个还是按照顺序执行首先执行run方法之后,执行输出语句所以最终得到结果foobar.
  • 调用start()后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可动行状态。然后通过JVM,线程Thread会调用run()方法,执行本线程的线程体。

51.java8中,下面哪个类用到了解决哈希冲突的开放定址法

A.LinkedHashSet
B.HashMap
C.ThreadLocal
D.TreeMap
答案:C
解析:
  • ThreadLocalMap中使用开放地址法来处理散列冲突
  • HashMap中使用的是分离链表法
    之所以采用不同的方式主要是因为:在ThreadLocalMap中的散列值分散得十分均匀,很少会出现冲突。并且ThreadLocalMap经常需要清除无用的对象,使用纯数组更加方便。

52.关于抽象类与接口,下列说法正确的有?

A.优先选用接口,尽量少用抽象类
B.抽象类可以被声明使用,接口不可以被声明使用
C.抽象类和接口都不能被实例化。
D.以上说法都不对
答案:AC
解析:
抽象类:
  • 含有abstract修饰符的class即为抽象类,abstract类不能创建的实例对象。
  • 含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class
  • 类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法,如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口:

接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。

两者之间的联系和区别:

抽象类接口
可以有构造方法不能有构造方法
可以有普通成员变量没有普通成员变量
可以包含非抽象的普通方法所有方法必须都是抽象的,不能有非抽象的普通方法
访问类型可以是public,protected只能是public类型的,并且默认即为public abstract类型
可以包含静态方法不能包含静态方法
可以包含静态成员变量,静态成员变量的访问类型可以任意可以包含静态成员变量,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型

53.下面有关Java的说法正确的是( )

A.一个类可以实现多个接口
B.抽象类必须有抽象方法
C.protected成员在子类可见性可以修改
D.通过super可以调用父类构造函数
E.final的成员方法实现中只能读取类的成员变量
F.String是不可修改的,且java运行环境中对string对象有一个对象池保存
答案:A C D F
解析:

这里解释一下E和F选项
E:

final 的成员方法除了能读取类的成员变量,还能读取类变量

F:

String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象

54.下列说法错误的有( )

A.在类方法中可用this来调用本类的类方法
B.在类方法中调用本类的类方法时可直接调用
C.在类方法中只能调用本类中的类方法
D.在类方法中绝对不能调用实例方法
答案: A C D
解析:
成员方法

又称为实例方法,非静态成员函数, 暗含this指针

静态方法

又称为类方法,静态成员函数,由static修饰,与类对象无关,缺少this指针

  • this是对象,及有实例 故A错;
  • 静态成员函数可以直接引用该类的静态成员变量和函数,但不允许直接引用非静态成员变量(若要引用,则需 通过传递参数的方式得到对象名)故B对
  • 可以通过继承,来调用父类的 类方法。故C错;
  • 可以生成实例,然后通过this来调用实例方法,故D对

55.以下哪些jvm的垃圾回收方式采用的是复制算法回收()

A.新生代串行收集器
B.老年代串行收集器
C.并行收集器
D.新生代并行回收收集器
E.老年代并行回收收集器
F.cms收集器
答案:A D
解析:

两个最基本的java回收算法:复制算法和标记清理算法
复制算法:

两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法

标记清理算法:

一块区域,标记可达对象(可达性分析),然后回收不可达对象,会出现碎片,那么引出标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象

两个概念:新生代和年老代

  • 新生代:初始对象,生命周期短的
  • 永久代:长时间存在的对象
    整个java的垃圾回收是新生代和年老代的协作,这种叫做分代回收。
  • Serial New收集器是针对新生代的收集器,采用的是复制算法
  • Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理
  • Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法
  • Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理
  • Parallel Old(并行)收集器,针对老年代,标记整理
  • CMS收集器,基于标记清理
  • G1收集器:整体上是基于标记 整理 ,局部采用复制

56.以下定义一维数组的语句中,正确的是:()

A.int a [10]
B.int a []=new [10]
C.int a[] int a []=new int [10]
D.int a []={1,2,3,4,5}
答案:D
解析:

Java一维数组有两种初始化方法:

  • 1、静态初始化
int array[] = new int[]{1,2,3,4,5}

或者

int array[] = {1,2,3,4,5}

注意:写成一下形势也是错误的

int array[] = new int[5]{1,2,3,4,5}
  • 2、动态初始化
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;

静态与动态初始化的区别就在于,前者是声明的时候就初始化,后者是先声明,再动态初始化。

57.有关线程的叙述正确的是()

A.可以获得对任何对象的互斥锁定。
B.通过继承Thread类或实现Runnable接口,可以获得对类中方法的互斥锁定。
C.线程通过使用synchronized关键字可获得对象的互斥锁定。
D.线程的创建只能通过继承Thread类来实现。
答案:C
解析:
  • 互斥锁指的是只有一个线程可以访问该对象。
  • 如果变量用volatile修饰,则该变量是线程共享的,无法获得该变量的互斥锁
  • 采用synchronized修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。

58.Java的Daemon线程,setDaemon( )设置必须要?

A.在start之前
B.在start之后
C.前后都可以
答案:A
解析:

java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程.
首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程

  • 2:守护线程。
    守护线程是服务用户线程的线程,在它启动之前必须先set。
  • 1.用户线程
    通过Thread.setDaemon(false)设置为用户线程;
    用户线程可以简单的理解为用户定义的线程,当然包括main线程
  • 2.daemon线程
    通过Thread.setDaemon(true)设置为守护线程,如果不设置,默认用户线程
    daemon线程是为我们创建的用户线程提供服务的线程,比如说jvm的GC等等,这样的线程有一个非常明显的特征: 当用户线程运行结束的时候,daemon线程将会自动退出.(由此我们可以推出下面关于daemon线程的几条基本特点):
    • 守护线程创建的过程中需要先调用setDaemon方法进行设置,然后再启动线程.否则会报出IllegalThreadStateException异常.
    • 由于daemon线程的终止条件是当前是否存在用户线程,所以我们不能指派daemon线程来进行一些业务操作,而只能服务用户线程.
    • daemon线程创建的子线程任然是daemon线程.
      守护线程是服务用户线程的线程,在它启动之前必须先set。

59.下列说法正确的是

A.在类方法中可用this来调用本类的类方法
B.在类方法中调用本类的类方法可直接调用
C.在类方法中只能调用本类的类方法
D.在类方法中绝对不能调用实例方法
答案: B
解析:
  • 在类方法中调用本类的类方法可直接调用。
  • 实例方法也叫做对象方法。类方法是属于整个类的,而实例方法是属于类的某个对象的。
  • 由于类方法是属于整个类的,并不属于类的哪个对象,所以类方法的方法体中不能有与类的对象有关的内容。即类方法体有如下限制:
    • (1) 类方法中不能引用对象变量;
    • (2) 类方法中不能调用类的对象方法;
    • (3) 在类方法中不能使用super、this关键字。
    • (4)类方法不能被覆盖。 如果违反这些限制,就会导致程序编译错误。
  • 与类方法相比,对象方法几乎没有什么限制:
    • (1) 对象方法中可以引用对象变量,也可以引用类变量;
    • (2) 对象方法中可以调用类方法;
    • (3) 对象方法中可以使用super、this关键字。

60.What is displayed when the following is executed;

double d1=-0.5;
System.out.println("Ceil d1="+Math.ceil(d1));
System.out.println("floor d1="+Math.floor(d1));
A.

Ceil d1=-0.0
floor d1=-1.0

B.

Ceil d1=0.0
floor d1=-1.0

C.

Ceil d1=-0.0
floor d1=-0.0

D.

Ceil d1=0.0
floor d1=0.0

E.

Ceil d1=0
floor d1=-1

答案:A
解析:
  • ceil:天花板数,向上取整。
  • floor:地板数,向下取整
    ceil 和 floor 方法 上都有一句话:If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument,意思为:如果参数是 NaN、无穷、正 0、负 0,那么结果与参数相同,
    如果是 -0.0,那么其结果是 -0.0

61.下面代码的输出是什么?

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.null
B.sub
C.base
答案: A
解析:

这道题也是考察类加载顺序的题目.
首先,需要明白类的加载顺序:

  • (1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
  • (2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
  • (3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )
  • (4) 父类构造函数
  • (5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
  • (6) 子类构造函数
    其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)

其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类,我们可以简单理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性
当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。

62.关于volatile关键字,下列描述不正确的是?

A.用volatile修饰的变量,每次更新对其他线程都是立即可见的。
B.对volatile变量的操作是原子性的。
C.对volatile变量的操作不会造成阻塞。
D.不依赖其他锁机制,多线程环境下的计数器可用volatile实现。
答案: B D
解析:

所谓 volatile的措施,就是

  • 每次从内存中取值,不从缓存中什么的拿值。这就保证了用 volatile修饰的共享变量,每次的更新对于其他线程都是可见的。
  • volatile保证了其他线程的立即可见性,就没有保证原子性
  • 由于有些时候对 volatile的操作,不会被保存,说明不会造成阻塞。不可用与多线程环境下的计数器。

63.方法通常存储在进程中的哪一区()

A.堆区
B.栈区
C.全局区
D.方法区
答案:D
解析:

一条进程的栈区、堆区、数据区和代码区在内存中的映射:

  • 栈区:主要用来存放局部变量, 传递参数, 存放函数的返回地址。.esp 始终指向栈顶, 栈中的数据越多, esp的值越小。
  • 堆区:用于存放动态分配的对象, 当你使用 malloc和new 等进行分配时,所得到的空间就在堆中。动态分配得到的内存区域附带有分配信息, 所以能够 free和delete它们。
  • 数据区:全局,静态和常量是分配在数据区中的,数据区包括bss(未初始化数据区)和初始化数据区。
    注意:
    • 1)堆向高内存地址生长;
    • 2)栈向低内存地址生长;
    • 3)堆和栈相向而生,堆和栈之间有个临界点,称为stkbrk。
      在这里插入图片描述

64.下列关于Java并发的说法中正确的是()

A.CopyOnWriteArrayList适用于写多读少的并发场景
B.ReadWriteLock适用于读多写少的并发场景
C.ConcurrentHashMap的写操作不需要加锁,读操作需要加锁
D.只要在定义int类型的成员变量i的时候加上volatile关键字,那么多线程并发执行i++这样的操作的时候就是线程安全的了
答案:B
解析:
  • 1.CopyOnWriteArrayList的实现原理
    在使用CopyOnWriteArrayList之前,我们先阅读其源码了解下它是如何实现的。以下代码是向ArrayList里添加元素,可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。
      public boolean add(T e) {
          final ReentrantLock lock = this.lock;
          lock.lock();
          try {
    
              Object[] elements = getArray();
    
              int len = elements.length;
              // 复制出新数组
    
              Object[] newElements = Arrays.copyOf(elements, len + 1);
              // 把新元素添加到新数组里
    
              newElements[len] = e;
              // 把原数组引用指向新数组
    
              setArray(newElements);
    
              return true;
    
          } finally {
    
              lock.unlock();
    
          }
    
      }
    
      final void setArray(Object[] a) {
          array = a;
      }
    
    读的时候不需要加锁,如果读的时候有多个线程正在向ArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的ArrayList
      public E get(int index) {
          return get(getArray(), index);
      } 
    
    CopyOnWriteArrayList适用于读多写少的并发场景
  • 2.ConcurrentHashMap
    ConcurrentHashMap采用分段锁技术,写操作加锁,读操作一般不加锁,除非读到的锁是空的,才会加锁重读
  • 3.volatite
    volatite只保证线程在“加载数据阶段”加载的数据是最新的,并不能保证线程安全
    一个线程执行的过程有三个阶段:
    加载(复制)主存数据到操作栈 --> 对操作栈数据进行修改 --> 将操作栈数据写回主存
    volatite关键字,让编译器不去优化代码使用缓存等,以保证线程在“加载数据阶段”加载的数据都是最新的
    对于D选项,之所以volatile不能保证i++的线程安全,除了volatile只能保证可见性之外,与 i++ 不是原子操作也有关,如果换个场合,有些人可能就会把 i++ 误当成原子操作,其实不是的,因为i++做了三次指令操作:
    • 1.从内存中读取i 变量的值到CPU的寄存器;
    • 2.在寄存器中的i自增1;
    • 3.将寄存器中的值写入内存;

65.jre 判断程序是否执行结束的标准是()

A.所有的前台线程执行完毕
B.所有的后台线程执行完毕
C.所有的线程执行完毕
D.和以上都无关
答案:A
解析:
  • 后台线程:指为其他线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。
  • 前台线程:是指接受后台线程服务的线程
    其实前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。可以通过isDaemon()和setDaemon()方法来判断和设置一个线程是否为后台线程。

前台线程和后台线程的区别和联系:

  • 1、后台线程不会阻止进程的终止。属于某个进程的所有前台线程都终止后,该进程就会被终止。所有剩余的后台线程都会停止且不会完成。
  • 2、可以在任何时候将前台线程修改为后台线程,方式是设置Thread.IsBackground 属性。
  • 3、不管是前台线程还是后台线程,如果线程内出现了异常,都会导致进程的终止。
  • 4、托管线程池中的线程都是后台线程,使用new Thread方式创建的线程默认都是前台线程。

说明:
应用程序的主线程以及使用Thread构造的线程都默认为前台线程
使用Thread建立的线程默认情况下是前台线程,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序

66.下列关于系列化和反序列化描述正确的是:

A.序列化是将数据转为n个 byte序列的过程
B.反序列化是将n个 byte转换为数据的过程
C.将类型int转换为4 byte是反序列化过程
D.将8个字节转换为long类型的数据为序列化过程
答案:AB

76.在Java中,关于HashMap类的描述,以下正确的是 ()

A.HashMap使用键/值得形式保存数据
B.HashMap 能够保证其中元素的顺序
C.HashMap允许将null用作键
D.HashMap允许将null用作值
答案:A C D
解析:

在这里插入图片描述

67.下面哪些类实现或者继承了Collection接口?

A.HashMap
B.ArrayList
C.Vector
D.Iterator
答案:B C
解析:

在这里插入图片描述

68.关于Java内存区域下列说法不正确的有哪些

A.程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器,每个线程都需要一个独立的程序计数器.
B.Java虚拟机栈描述的是java方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表、类信息、动态链接等信息
C.Java堆是java虚拟机所管理的内存中最大的一块,每个线程都拥有一块内存区域,所有的对象实例以及数组都在这里分配内存。
D.方法区是各个线程共享的内存区域,它用于存储已经被虚拟机加载的常量、即时编译器编译后的代码、静态变量等数据。
答案:B C
解析:
  • A.程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器(偏移地址),Java编译过程中产生的字节码有点类似编译原理的指令,程序计数器的内存空间存储的是当前执行的字节码的偏移地址,每一个线程都有一个独立的程序计数器(程序计数器的内存空间是线程私有的),因为当执行语句时,改变的是程序计数器的内存空间,因此它不会发生内存溢出 ,并且程序计数器是jvm虚拟机规范中唯一一个没有规定 OutOfMemoryError 异常 的区域;
  • B.java虚拟机栈:线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。 没有类信息,类信息是在方法区中
  • C.java堆:对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组
  • D.方法区:属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

69.以下哪个不属于JVM堆内存中的区域()?

A.survivor区
B.常量池
C.eden区
D.old区
答案:B
解析:

jvm堆分为:新生代(一般是一个Eden区,两个Survivor区),老年代(old区)。
常量池属于 PermGen(方法区)

70.下面有关java hashmap的说法错误的是?

A.HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”
B.HashMap 的实现不是同步的,意味着它不是线程安全的
C.HashMap通过开放地址法解决哈希冲突
D.HashMap中的key-value都是存储在Entry数组中的
答案:C
解析:
  1. 关于HashMap的一些说法:
  • a) HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层结构是一个数组,数组中的每一项是一条链表。
  • b) HashMap的实例有俩个参数影响其性能: “初始容量” 和 装填因子。
  • c) HashMap实现不同步,线程不安全。 HashTable线程安全
  • d) HashMap中的key-value都是存储在Entry中的。
  • e) HashMap可以存null键和null值,不保证元素的顺序恒久不变,它的底层使用的是数组和链表,通过hashCode()方法和equals方法保证键的唯一性
  • f) 解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法解决哈希冲突的。
    注:
    * 链表法是将相同hash值的对象组成一个链表放在hash值对应的槽位;用开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。 沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。
    * 拉链法解决冲突的做法是: 将所有关键字为同义词的结点链接在同一个单链表中 。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0…m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。拉链法适合未规定元素的大小。
  1. Hashtable和HashMap的区别:
  • a) 继承不同。 public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map
  • b) Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
  • c) Hashtable 中, key 和 value 都不允许出现 null 值。 在 HashMap 中, null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null 。当 get() 方法返回 null 值时,即可以表示 HashMap 中没有该键,也可以表示该键所对应的值为 null 。因此,在 HashMap 中不能由 get() 方法来判断 HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断。
  • d) 两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
  • e) 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
  • f) Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
    注: HashSet子类依靠hashCode()和equal()方法来区分重复元素。
    HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值的,会去判断当前Map中是否含有该Key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。

71.Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持,下面关于Java反射的描述,哪些是错误的:( )

A.Java反射主要涉及的类如Class, Method, Filed,等,他们都在java.lang.reflet包下
B.通过反射可以动态的实现一个接口,形成一个新的类,并可以用这个类创建对象,调用对象方法
C.通过反射,可以突破Java语言提供的对象成员、类成员的保护机制,访问一般方式不能访问的成员
D.Java反射机制提供了字节码修改的技术,可以动态的修剪一个类
E.Java的反射机制会给内存带来额外的开销。例如对永生堆的要求比不通过反射要求的更多
F.Java反射机制一般会带来效率问题,效率问题主要发生在查找类的方法和字段对象,因此通过缓存需要反射类的字段和方法就能达到与之间调用类的方法和访问类的字段一样的效率
答案:A D F
解析:
  • A Class类在java.lang包
  • B 动态代理技术可以动态创建一个代理对象,反射不行
  • C 反射访问私有成员时,Field调用setAccessible可解除访问符限制
  • D CGLIB实现了字节码修改,反射不行
  • E 反射会动态创建额外的对象,比如每个成员方法只有一个Method对象作为root,他不胡直接暴露给用户。调用时会返回一个Method的包装类
  • F 反射带来的效率问题主要是动态解析类,JVM没法对反射代码优化。

72.关于身份证号,以下正确的正则表达式为( )

A.isIDCard=/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
B.isIDCard=/^[1-9]\d{7}((9\d)|(1[0-2]))(([0|1|2]\d)|3[9-1])\d{3}$/;
C.isIDCard=/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;
D.isIDCard=/^[1-9]\d{5}[1-9]\d{3}((9\d)|(1[9-2]))(([0|1|2]\d)|3[9-1])\d{4}$/;
答案: A C
解析:
  • ^:起始符号,^x表示以x开头
  • $:结束符号,x$表示以x结尾
  • [n-m]:表示从n到m的数字
  • \d:表示数字,等同于[0-9]
  • X{m}:表示由m个X字符构成,\d{4}表示4位数字
    15位身份证的构成:六位出生地区码+六位出身日期码+三位顺序码
    18位身份证的构成:六位出生地区码+八位出生日期码+三位顺序码+一位校验码

73.Java表达式"13 & 17"的结果是什么?()

A.30
B.13
C.17
D.1
答案:D
解析:

此处考察与运算,做这种题只需要2步
1.将数值转为二进制:13(01101),17(10001)
2.将二进制数值进行相与运算,只有都为1的情况下才为1
最终的运算结果为00001即对应的10进制为1

74.关于protected 修饰的成员变量,以下说法正确的是()

A.可以被该类自身、与它在同一个包中的其它类、在其它包中的该类的子类所访问
B.只能被该类本身和该类的所有的子类访问
C.只能被该类自身所访问
D.只能被同一个包中的类访问
答案:A
解析:
作用域名本类能不能访问访问同一个包(Package)下的其他类能不能访问不同包(Package),但是作为子类不同包,不是子类
public
protected×
default××
private×××

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

在这里插入图片描述

A.true,false,true
B.false,true,false
C.true,true,false
D.false,false,true
答案:D
解析:

首先我先解释一下String的地址引用

  • 1.String s = “abc”:通过字面量赋值创建字符串。则将栈中的引用直接指向该字符串,如不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串
  • 2.String s = “a”+“bc”:编译阶段会直接将“a”和“bc”结合成“abc”,这时如果方法区已存在“abc”,则将s的引用指向该字符串,如不存在,则在方法区中生成字符串“abc”对象,然后再将s的引用指向该字符串
  • 3.String s = “a” + new String(“bc”):栈中先创建一个"a"字符串常量,再创建一个"bc"字符串常量,编译阶段不会进行拼接,在运行阶段拼接成"abc"字符串常量并将s的引用指向它,效果相当于String s = new String(“abc”),只有’+'两边都是字符串常量才会在编译阶段优化。
    我们再回到题目,其中i3和i4分别属于1,3的情况,i3属于字符串常量,在栈中(常量池中),i4属于拼接,只有在编译阶段才能知道,所以在堆中,地址则肯定不同。

接下来我接着解释一下整型的地址引用
Integer i1=128 表示Integer i1=Integer.valueOf(128)
Interger 赋予的int数值在-128 - 127的时候,直接从*** 中获取,这些***引用对Integer对象地址是不变的,但是不在这个范围内的数字,则new Integer(i) 这个地址是新的地址,不可能一样的。

76.

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;

假定str0,…,str4后序代码都是只读引用。
Java 7中,以上述代码为基础,在发生过一次FullGC后,上述代码在Heap空间(不包括PermGen)保留的字符数为()

A.5
B.10
C.15
D.20
答案:C
解析:

我先说明一下关于java的垃圾回收机制
垃圾回收主要针对的是堆区的回收,因为栈区的内存是随着线程而释放的。
堆区分为三个区:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)。

  • 1.年轻代:由一个Eden区和俩个survivor区组成,对象被创建时(new)的对象通常被放在Young(除了一些占据内存比较大的对象),经过一定的Minor GC(针对年轻代的内存回收)还活着的对象会被移动到年老代(一些具体的移动细节省略),新创建的对象都在年轻代的Eden区,经过一次JC收集后,存活下来的会被复制到survivor区(一个满了,就全部移动到另外一个大的中,但要保证其中一个survivor为空),经过多次JC后,还存活的对象就被移到老年代了。
  • 2.年老代:就是上述年轻代移动过来的和一些比较大的对象。Minor GC(FullGC)是针对年老代的回收。
  • 3.永久代(持久代):存储的是类信息,final常量,static变量,常量池,方法等。

而static String str0=“0123456789”; static String str1=“0123456789”;是属于static的静态变量,所以在持久代,但是我们的fullGc是针对老年代的回收,所以GC之后,只会回收str2,str3,str4,所以为5+5+5=15

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

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
解析:

我先解释一下join函数的作用:等待该线程终止,简单来说也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
因为子线程的休眠时间太长,因此主线程很有可能在子线程之前结束也就是输出结果是12,但是子线程用了join函数,因此主线程必须等待子线程执行完毕才结束因此输出结果只能是21。

78.以下哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址( )

A.String a = “hello”; String b = “hello”;
B.Integer a; Integer b = a;
C.int a = 1; Integer b = new Integer(1);
D.int a = 1; Integer b = 1;
答案:AB
解析:

首先对于int和Integer类型

  • (1)int与Integer、new Integer()进行==比较时,结果永远为true
  • (2)Integer与new Integer()进行==比较时,结果永远为false
  • (3)Integer与Integer进行==比较时,看范围;在大于等于-128小于等于127的范围内为true,在此范围外为false。

我们来分析一下具体的原因:
1.Integer与int比较时,Integer会有拆箱的过程,我们可以看看拆箱的代码:

@Override
public int intValue(){
    return value;
}

直接返回的就是value,因此int与Integer以及new Integer()进行 ==比较时结果都是true。
3.Integer与Integer比较,需要看范围,如果在-128~127(包含-128,不包含127)范围内,会直接从IntegerCache中取,所以相等;若不在这个范围内,则都要去new一个对象,所以结果为false。
对于C选项:
int a =1会直接从常量池中取,只有值,没有引用地址,Integer b =new Integer(1);指向堆中地址为1的位置。所以C错
对于D选项:
原因和C一样,Integer b=1等价于Integer b=Integer.valueOf(1);
对于A选项:
String a = "hello"首先判断常量池中是否有hello,没有将会在常量池中创建,当String b="hello"时,此时常量池中已经有hello,无需重新创建,直接返回引用。

79.What is Static Method in Java()

A. It is a method which belongs to the class and not to the object(instance)
B.A static method can access only static data. It can not access non-static data (instance variables)
C.A static method can call only other static methods and can not call a non-static method from it.
D.A static method can not be accessed directly by the class name and doesn’t need any object
答案:ABC
解析:

A:静态方法是一个属于类而不属于对象(实例)的方法。(√)
B:静态方法只能访问静态数据。无法访问非静态数据(实例变量)。(√)
C:静态方法只能调用其他静态方法,不能从中调用非静态方法。(√)
D:静态方法不能通过类名直接访问,也不需要任何对象。(×) 静态方法可以直接用类名访问。
我系统的解释一下static关键字修饰的内容特性

  • Static 修饰的内容都在方法区
  • Static 修饰的属性、方法属于类。
  • Static 修饰的属性、方法属于类。那么对象是怎么访问的?本质:(查看反编译代码,系统自动转换为类名进行调用)
  • 类名、对象名.Static修饰的属性、方法进行访问。
  • Static 修饰的内容优先于对象存在(先有静态的方法、属性,后创建对象后才有 非静态的方法,属性)
  • Static 修饰的内容,被该类型的所有对象共享
  • 需要共享的才设置成static
  • 只有非private的static成员才能通过类名的 方式访问。
  • 非静态方法可以访问静态成员、非静态方法。
  • 静态方法不可以访问 非静态成员
  • 静态变量,当java虚拟机停止的时候才消失
  • 静态方法main方法开始执行,压如栈底,整个程序都调用结束才出栈。
  • 静态方法在没有创建对象时就已经存在,所有静态方法直接可以互相调用,非静态方法和变量是属于对象的,不能直接访问。

80.指出下列程序运行的结果:

public class Example{
    String str=new String("tarena");
    char[]ch={'a','b','c'};
    public static void main(String args[]){
        Example ex=new Example();
        ex.change(ex.str,ex.ch);
        System.out.print(ex.str+" and ");
        System.out.print(ex.ch);
    }
    public void change(String str,char ch[]){
   //引用类型变量,传递的是地址,属于引用传递。
        str="test ok";
        ch[0]='g';
    }
}
A. tarena and abc
B.tarena and gbc
C.test ok and abc
D.test ok and gbc
答案:B
解析:

这道题的唯一考点 就在String声明的对象不可变。
string和char数组都是引用类型,引用类型是传地址的,会影响原变量的值,但是string是特殊引用类型,为什么呢?
因为string类型的值是不可变的,为了考虑一些内存,安全等综合原因,把它设置成不可变的; 不可变是怎么实现的?Java在内存中专门为string开辟了一个字符串常量池,用来锁定数据不被篡改,所以题目中函数中的str变量和原来的str已经不是一个东西了,它是一个局部引用,指向一个testok的字符串,随着函数结束,它也就什么都没了,但是char数组是会改变原值的。

81. 当编译并运行下面程序时会发生什么结果()

public class Bground extends Thread{
    public static void main(String argv[]){
        Bground b = new Bground();
        b.run();
    }
    public void start(){
        for(int i=0;i<10;i++){
            System.out.println("Value of i = "+i);
        }
    }
}
A.编译错误,指明run方法没有定义
B.运行错误,只鞥呢run方法没有定义
C.编译通过并输出0到9
D.编译通过,但无输出
答案:D
解析:

对于线程而言,start是让线程从new变成runnable。
run方法才是执行体的入口。
但是在Thread中,run方法是个空方法,没有具体实现。
Bground继承了Thread,但是没有重写run方法,那么调用run方法时将会调用父类的run()方法,肯定是无输出。

82.下面叙述那个是正确的?()

A.java中的集合类(如Vector)可以用来存储任何类型的对象,且大小可以自动调整。但需要事先知道所存储对象的类型,才能正常使用。
B.在java中,我们可以用违例(Exception)来抛出一些并非错误的消息,但这样比直接从函数返回一个结果要更大的系统开销。
C.java接口包含函数声明和变量声明。
D.java中,子类不可以访问父类的私有成员和受保护的成员。
答案:B
解析:

对于A选项,vector是线程安全的ArrayList,在内存中占用连续的空间。初始时有一个初始大小,当数据条数大于这个初始大小后会重写分配一个更大的连续空间。如果我们将Vector的泛型定义为Object类型,则可以存放任意类型,所以这种情况下就无需知道所存储对象的类型。
对于B选项,try{}catch{}会增加额外的开销

try{
    int a=15;
    if(a>10){
        throw new RunTimeExcepton("a大于10");
    }
}catch(Exception e){
    
}

上面这串代码意思就是大于10,我们就通过抛出异常的方式提示我们a大于10。因为函数调用是入栈出栈,栈是在寄存器之下的速度最快,且占的空间少,而自定义异常是存在堆中,肯定异常的内存开销大。
对于C选项,接口中方法默认是 abstract public,所以在接口只写函数声明是符合语法规则。但是变量默认是用public final static 修饰的,意思它是静态常量,常量不管在接口中还是类中必须在声明时初始化!所以C的后半句是错的,必须在声明时并给出初始化!
对于D选项,子类可以访问父类受保护的成员(protect)
持续更新中

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZNineSun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值