当前位置:   article > 正文

java笔试_java要求编程者管理内存这句话对还是错

java要求编程者管理内存这句话对还是错

java笔试

1、下列描述中,错误的是( )

答案:C. java要求编程者管理内存
解析:java与C***很大的一点区别就是java是不需要使用者关注内存分配以及管理的,Java的内存管理由Java虚拟机来完成对内存的管理。

2、执行下面的程序段,语句3的执行次数为()
for (i = 0; i <= n-1; i++)   // (1)
    for (j = n; j > i; j--// (2)
        state;               // (3)
  • 1
  • 2
  • 3

答案:C. n(n+1)/2
解析:假设代入法:
n=3,外层循环i的取值为0,1,2
当i=0时,内部循环j的取值为3,2,1,所以state执行3次;当i=1时,内部循环j的取值3,2,所以state执行2次;当i=2时,内部循环j的取值为3,所以 state执行1次。
综上所述:3+2+1=6次。将n=3带入选项中的出C符合结果。

3、在java中,下列对继承的说法,正确的是( )

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

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

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

答案:A C D
解析:HashMap 不按插入顺序排序,按照哈希值排序。所以无序。但是不增删改键的情况下,输出是按照一定顺序不变的image-20220311154132297

5、以下关于对象序列化描述正确的是

A、使用FileOutputStream可以将对象进行传输
B、使用PrintWriter可以将对象进行传输
C、使用transient修饰的变量不会被序列化
D、对象序列化的所属类需要实现Serializable接口

答案:C D
解析:使用ObjectOutputStream和ObjectInputStream可以将对象进行传输.
声明为static和transient类型的成员数据不能被串行化。因为static代表类的状态, transient代表对象的临时数据。

6、下面有关java类加载器,说法正确的是?

A、引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的
B、扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。
C、系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类
D、tomcat为每个App创建一个Loader,里面保存着此WebApp的ClassLoader。需要加载WebApp下的类时,就取出ClassLoader来使用

答案:A B C D
解析:a、Bootstrap ClassLoader/启动类加载器。
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作.
B、Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作
C、System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作.
B、 User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性.

7、对于java类型变量char c,short s,float f,double d,表达式c*s+f+d的结果类型为()

A、float
B、char
C、short
D、double

答案:D
解析:1.若参与运算的数据类型不同,则先转换成同一类型,然后进行运算。
2.转换按数据长度增加的方向进行,以保证精度不降低。例如int型和long型运算时,先把int量转成long型后再进行运算。
3.所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4.char型和short型参与运算时,必须先转换成int型。
5.在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型将转换为左边变量的类型。
如果右边表达式的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度。
img
**&&.**long与double在java中本身都是用64位存储的,但是他们的存储方式不同,导致double可储存的范围比long大很多

8、有变量int i = 0; int a = i++; int b = ++a; int c = a+b; int d = (a == 1)?b:c; 请问a和d的值分别是多少?( )。答案:D

A、2,4
B、1, 4
C、1, 2
D、1,1
解析:int i = 0; //i=0
int a = i++; //a=i,a=0,i++,i=1
int b = ++a; //a++,a=1,b=a,b=1
int c = a+b;//c=2
int d = (a == 1)?b:c;//a1,d=b,d=1
综上a
1, d==1
三目运算符 基本格式为: boolean表达式1 ? 有返回值的表达式2 : 有返回值的表达式3
计算表达式1的值,若值为true则执行表达式2并得到其值,否则则执行表达式3并得到其值。

9、面向对象方法的多态性是指()答案:C

A、一个类可以派生出多个特殊类
B、一个对象在不同的运行环境中可以有不同的变体
C、针对一消息,不同的对象可以以适合自身的方式加以响应
D、一个对象可以是由多个其他对象组合而成的
解析:《疯狂java讲义》的标准解释是: 相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态。

10、有以下程序段, 则下面正确的选项是()答案:B C D
public class MyThead extends Thread{
    public static void main(String[] args) {
        MyThead t=new MyThead();
        MyThead s=new MyThead();
        t.start();
        System.out.println("one.");
        s.start();
        System.out.println("two.");
    }
    public void run() {
        System.out.println("Thread");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

A、编译失败
B、

程序运行可能结果为:
one.
Thread
two.
Thread       
  • 1
  • 2
  • 3
  • 4
  • 5

C、

程序运行可能结果是:
one.
two.
Thread
Thread
  • 1
  • 2
  • 3
  • 4
  • 5

D、程序运行结果不稳定
解析:单选题选D,多选题选BCD,都是套路!

11、下列选项中是正确的方法声明的是?()答案: A B C D

A、protected abstract void f1();
B、public final void f1() {}
C、static final void fq(){}
D、private void f1() {}
解析:A:抽象方法只可以被public 和 protected修饰;
B:final可以修饰类、方法、变量,分别表示:该类不可继承、该方法不能重写、该变量是常量
C:static final 可以表达在一起来修饰方法,表示是该方法是静态的不可重写的方法
D:private 修饰方法(这太常见的)表示私有方法,本类可以访问,外界不能访问

12、类方法中可以直接调用对象变量?答案:B

A、正确
B、错误
解析:是不能静态方法中引用非静态的域。原因也很简单关于类初始化的过程中,静态域是随着类加载就完成了初始化,而非静态域此时都没有完成初始化,你引用它肯定就出错了。

13、BufferedReader的父类是以下哪个?答案:D

A、FilterReader
B、InputStreamReader
C、PipedReader
D、Reader
解析:img

14、已知如下类说明: 如下哪些使用是正确的()答案:D
public class Test{
    private float f=1.0f;
    int m=12;
    static int n=1;
    public static void main(String args[]){
        Test t=new Test();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

A、t.f = 1.0
B、this.n
C、Test.m
D、Test.n
解析:A:编译不成功,因为float浮点类型默认是double类型 所以float f=1.0f;(必须加上f 强调定义的是float)此处是精度由高(double)向低(float)转型所以会报错 但是若是float f=1;这里是默认类型是Int 类型 精度由低(int)向高转型(float)不丢失精度不会报错。
B:this的使用时针对在方法内部使局部变量等值于实例变量而使用的一个关键字,此处的n是静态变量而非实例变量 所以this的调用会出错(试想一下,static本来是全类中可以使用的,是全局的,你非得this去调用,这不是区分局部变量和实例变量的分水线吗?但是此处是全局的,不需要区分)
C:m是实例变量,什么是实例变量:就是需要new 一个对象出来才能使用的,这里直接用类名就调用了,jvm怎么知道m是谁?
D:类变量可以通过类直接调用

15、下面哪些Java中的流对象是字节流? 答案:A B C D

A、FileInputStream
B、BufferedInputStream
C、PushbackInputStream
D、ByteArrayInputStream
解析:stream结尾都是字节流,reader和writer结尾都是字符流 两者的区别就是读写的时候一个是按字节读写,一个是按字符。 实际使用通常差不多。 在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流。 只是读写文件,和文件内容无关的,一般选择字节流。
imgimg

字节流:

InputStream
|-- FileInputStream (基本文件流)
|-- BufferedInputStream
|-- DataInputStream

|-- ObjectInputStream

字符流

Reader
|-- InputStreamReader (byte->char 桥梁)
|-- BufferedReader (常用)
Writer
|-- OutputStreamWriter (char->byte 桥梁)
|-- BufferedWriter
|-- PrintWriter (常用)

16、jdk1.8版本之前的前提下,接口和抽象类描述正确的有( ) 答案:B C

A、抽象类没有构造函数
B、接口没有构造函数
C、抽象类不允许多继承
D、接口中的方法可以有方法体
解析:A,抽象类是一个类,所以有构造器
B,接口不是一个类,所以没有构造函数
C,抽象类是一个类,类不允许继承多个类,但是可以实现多个接口。而接口可以继承多个接口,接口不能实现接口。
D,jdk1.8之前,接口中的方法都是抽象方法,用public abstract修饰,jdk1.8新特性:可以有默认方法(用default修饰,不能缺省)和静态方法(static修饰),jdk1.9:接口中的默认方法还可以用private修饰

17、下列符号中可以在 java 程序里表示单行注释的是( ) 答案:C

A、–
B、/* ……/
C、//
D、/** ……
/
解析:1、单行(single-line)–短注释://……
注释格式:/* 注释内容 /
2、块(block)–块注释:/
……/
/

* 注释内容
/
3、文档注释:/**……
/
注释若干行,并写入javadoc文档。每个文档注释都会被置于注释定界符
/**…*/之中

18、下面代码运行结果是? 答案:A
public class Test
{
    static boolean foo(char c)
    {
        System.out.print(c);
        return true;
    }
    public static void main( String[] argv )
    {
        int i = 0;
        for ( foo('A'); foo('B') && (i < 2); foo('C'))
        {
            i++ ;
            foo('D');
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

A、ABDCBDCB
B、ABCDABCD
C、Compilation fails.
D、An exception is thrown at runtime.
解析:for(条件1;条件2;条件3) {

	  //语句
  • 1

​ }

​ 执行顺序是条件1->条件2->语句->条件3->条件2->语句->条件3->条件2…

​ 如果条件2为true,则一直执行。如果条件2位false,则for循环结束

19、下列代码执行结果为() 答案:A
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");
	    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

A、21
B、12
C、可能为12,也可能为21
D、以上答案都不对
解析:thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的 Join()方法,直到线程A执行完毕后,才会继续执行线程B。

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

20、尝试编译以下程序会产生怎么样的结果?() 答案:C
public class MyClass {
    long var;
    public void MyClass(long param) { var = param; }//(1)
    public static void main(String[] args) {
        MyClass a, b;
        a =new MyClass();//(2)
        b =new MyClass(5);//(3)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

A、编译错误将发生在(1),因为构造函数不能指定返回值
B、编译错误将发生在(2),因为该类没有默认构造函数
C、编译错误将在(3)处发生,因为该类没有构造函数,该构造函数接受一个int类型的参数
D、该程序将正确编译和执行
解析:这道题一定要看仔细了,MyClass方法并不是构造参数,而是返回类型为void的普通方法,普通方法自然需要实例化对象然后去调用它,所以124不对,第三个是正确的,因为没有带参数的构造器,所以自然不能传一个int进去。

构造方法就是:public 类名, 没有方法修饰符
 
所以 (1)  处就是一个普通方法
 
所以该类没有带参数构造方法 ,编译报错
  • 1
  • 2
  • 3
  • 4
  • 5

(1)虽然方法名和类名相同,不过由于void的修饰,所以它并不是一个构造方法,只是一个普通方法。因此题类仍然只有默认的无参构造器,(3)向构造方法中传入一个参数故而有误。

21、下面代码在main()方法中第八行后可以正常使用的是( ) 答案:A D
public class Test
{
    private int a=10;
    int b=20;
    static int c=1;
    public static void main(String arg[])
    {
        Test t = new Test();
    }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

A、t.a
B、this.c
C、Test.b
D、t.c
解析:A : 在private 修饰不能在外部类中调用,main 方法属于Test类的方法, 所以 对象 t 可以在他自己的类方法中调用它的

​ private

​ B : static 方法中没有this 这么一说

​ C: b不是static变量

​ D: 合理

22、以下关于继承的叙述正确的是 答案:A

A、在Java中类只允许单一继承
B、在Java中一个类不能同时继承一个类和实现一个接口
C、在Java中接口只允许单一继承
D、在Java中一个类只能实现一个接口
解析:1)接口可以继承接口,而且可以继承多个接口,但是不能实现接口,因为接口中的方法全部是抽象的,无法实现;

另外,如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法

2)普通类可以实现接口,并且可以实现多个接口,但是只能继承一个类,这个类可以是抽象类也可以是普通类,如果继承抽象类,必须实现抽象类中的所有抽象方法,否则这个普通类必须设置为抽象类;

3)抽象类可以实现接口,可以继承具体类,可以继承抽象类,也可以继承有构造器的实体类。

抽象类中可以有静态main方法;抽象类里可以没有抽象方法,没有抽象方法的抽象类就是不想让别人实例化它;

另外,抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super(参数列表)调用抽象类中的构造方法,可以用于实例化抽象类的字段。

下面总结常见的抽象类与接口的区别:

1)抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象;

2)接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现(java8中 接口可以有实现方法 使用default修饰);

3)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;

4)抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类;

5)抽象方法要被实现,所以不能是静态static的,也不能是私有private的,也不能被final修饰(试想一下,静态方法可以被类名直接调用,而类名直接调用一个没有实现的抽象方法没有意义)。

总结得比较杂乱,见谅!

23、以下程序的执行结果是: 答案:
static boolean foo(char c){
     System.out.print(c);
     return true;
 }
 public static void main(String[] args) {
     int i =0;
     for(foo('A');foo('B')&&(i<2);foo('C')){
         i++;
         foo('D');
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A、ABDCBDCB
B、ABCDABCD
C、编译时出错
D、运行时抛出异常
解析:1.其实foo(‘A’);就是初始化条件,只会执行一次,所以第一个打印的肯定是A
2.因为i=0;循环条件是i<2 (由此可知循环i等于2的时候就会停止循环,)所有0<2满足条件,接着会输出B,然后执行i++;i就变成1了,再输出D,再最后输出C,一次循环后的结果是:ABDC
3.第二次循环的开始是foo(‘A’);是初始条件所以不会执行,直接从foo(‘B’)开始,输出B,然后i为1,且小于2,此时循环体内再次执行i++;i的值为2了,再次输出D,最后输出C
第二次循环输出:BDC
4.*然后循环再次执行for(foo(‘A’);foo(‘B’)&&(i<2);foo(‘C’))
直接输出B,***i的值在第二轮循环后的值变成了2,2<2不成立,终止循环,输出B

考察的是for循环三条语句的执行顺序 for(第一条语句;第二条语句;第三条语句;) 首次循环时先执行前两句。以后的每次循环结束,都是执行最后一条语句,然后执行判断语句(也就是第二条语句)条件成立进入下一次循环。 第一条语句只会被执行一次

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

A、Error
B、Exception
C、RuntimeException
D、Throwable
解析:

img

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

2、既然是要捕获在 编译期运行期

首先编译期在有些方法是必须要进行 try catch

而运行期可以手动添加 try catch

运行期间出现的异常都可以使用RuntimeException这个是运行期间所有异常的 “组长”

但是编译期就多了,他们没有这个所谓的 “组长”,但是它们上面还有个 “班长”(Exception)也就时 “组长” 的 “头儿”

*所以可以使用这个 “班长”**(Exception)*解决这两个组的异常

25、以下 json 格式数据,错误的是 答案:A C

A、{company:4399}
B、{“company”:{“name”:[4399,4399,4399]}}
C、{[4399,4399,4399]}
D、{“company”:[4399,4399,4399]}
E、{“company”:{“name”:4399}}

解析:
A:错误 {company:4399} 首先,其为json对象。但json对象要求属性必须加双引号。

B:正确

C:错误 {[4399,4399,4399]} 。使用 {} 则为json对象。json对象必须由一组有序的键值对组成。

D:正确。

答案:AC.

另参考(摘自<<Javascript 高级程序设计(第三版)>>):

JSON语法可以表示以下三种类型的值:

1.简单值:使用与JavaScript 相同的语法,可以在JSON中表示字符串,数值,布尔值和null。

2.对象:对象作为一种复杂数据类型,表示的是一组有序的键值对。而每组键值对中的值可以是简单值,也可以是复杂数据类型的值。

3.数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型–简单值,对象或数组。

26、以下哪种JAVA得变量声明方式可以避免程序在多线程竞争情况下读到不正确的值( ) 答案: A B

A、volatile
B、static volatile
C、synchronized
D、static
解析:1、synchronized不是修饰变量的 它修饰方法或代码块或对象
2、线程安全性比较关键的两个点:内存可见性和操作原子性 如果你不修改值,可以使用private static final int , final可以保证内存可见性语义。对于原生变量,final修饰后不可更改,从而也不存在操作原子性的问题。 如果你只是想单纯地进行赋值,而不进行复合操作,那么可以使用volatile int. volatile可以确保内存可见性,但是无法确保原子性,所以不支持复合操作的线程安全性。 如果你想进行复合操作,可以使用AtomicInteger这个原子类,支持CAS操作,可确保内存可见性和操作原子性。

27、下列程序段的输出结果是:( ) 答案:
public void complicatedexpression_r(){
    int x=20, y=30;
    boolean b;
    b = x > 50 && y > 60 || x > 50 && y < -60 || x < -50 && y > 60 || x < -50 && y < -60;
    System.out.println(b);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

A、true
B、false
C、1
D、0
解析:

1、答:此题考查运算符优先级。

题中符号的优先级排序是:’>’,’<’,’&&’,’||’。

即 b=(x>50&&y>60)||(x>50&&y<-60)||(x<-50&&y>60)||(x<-50&&y<-60);

x>50结果为0,x<-50结果为0,所以括号中的表达式结果都为0,四个0或的结果0。

b为boolean类型,所以输出为false。

2、x>50为false,由于&&与操作,||或操作都是短路操作符,即与操作时一旦遇到false就停止执行后当前关系式中的后续代码,同理或操作时一旦遇到true也停止执行。

x>50&&y>60中x>50结果为false,所以就不需要判断y>60。继续判断第一个||或操作符后面的代码,结果为false || false || false || false。因此最终答案选择false。

28、默认RMI采用的是什么通信协议? 答案:C

A、HTTP
B、UDP/IP
C、TCP/IP
D、Multicast
解析:RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制。使用这种机制,某一台计算机上的对象可以调用另外一台计算机上的对象来获取远程数据。RMI是Enterprise JavaBeans的支柱,是建立分布式Java应用程序的方便途径。在过去,TCP/IP套接字通讯是远程通讯的主要手段,但此开发方式没有使用面向对象的方式实现开发,在开发一个如此的通讯机制时往往令程序员感觉到乏味,对此RPC(Remote Procedure Call)应运而生,它使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然未能很好的支持,而且RPC未能做到面向对象调用的开发模式。针对RPC服务遗留的问题,RMI出现在世人面前,它被设计成一种面向对象的通讯方式,允许程序员使用远程对象来实现通信,并且支持多线程的服务,这是一次远程通讯的***,为远程通信开辟新的里程碑。

RMI的开发步骤

先创建远程接口及声明远程方法,注意这是实现双方通讯的接口,需要继承Remote

开发一个类来实现远程接口及远程方法,值得注意的是实现类需要继承UnicastRemoteObject

通过javac命令编译文件,通过java -server 命令注册服务,启动远程对象

最后客户端查找远程对象,并调用远程方法

所以选C

2、RMI采用的是TCP/IP协议

29、运行代码,结果正确的是: 答案: B
Boolean flag = false;
if(flag = true){
System.out.println("true");
}else{
System.out.println("false");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

A、编译错误
B、true
C、false
D、什么也没有输出
解析:if(flag = true)的时候flag已经是true了,所以输出true;

​ 要是为if(flag == true)输出才为false

30、下面代码输出结果是? 答案:C
int i = 5;
int j = 10;
System.out.println(i + ~j);
  • 1
  • 2
  • 3

A、Compilation error because”~”doesn’t operate on integers
B、-5
C、-6
D、15
解析:1、公式-n=n+1可推出n=-n-1,所以~10=-11再加5结果为-6

2、我认为应该是:

计算机本身储存的就是补码:

那么10的补码就是10的原码:0000 0000 0000 1010——这是补码,因为现在是计算机在计算

~10的补码就是:1111 1111 1111 0101

~10的反码就是:1111 1111 1111 0100——补码减1

~10的原码就是:1000 0000 0000 1011——反码取反:这个才是正常二进制数,换算为整数为-11

原码才可以对应为正常的整数,补码只有转换为原码才能被正常人类识别。

31、单例模式中,两个基本要点是答案: A D

A、构造函数私有
B、静态工厂方法
C、以上都不对
D、唯一实例
解析:

设计模式-单例模式
知识点
什么是单例模式?
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式有分为饿汉式和懒汉式

特点:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
应用实例:

1、一个班级只有一个班主任。
2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
优点:

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景:

1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

实例
单例模式-饿汉式
代码
//单例模式-饿汉式
public class SingletonDemo {
    public static void main(String[] args) {
        //编译错误:无法实例化
        // Singleton singleton = new Singleton();
 
        //正确获取对象的方法
        Singleton singleton = Singleton.getINSTANCE();
        singleton.hello();
    }
}
 
class Singleton{
    //创建一个本身对象
    private static final Singleton INSTANCE = new Singleton();
 
    //让构造方法为private,这样该类就不会被实例化
    private Singleton(){}
 
    //创建一个获取对象的方法
    public static Singleton getINSTANCE() {
        return INSTANCE;
    }
 
    public void hello(){
        System.out.println("Hello World! ——单例模式-饿汉式");
    }
}
结果

1
Hello World! ——单例模式-饿汉式
单例模式-懒汉式(线程不安全版)
这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

代码
//单例模式-懒汉式
public class SingletonDemo2 {
    public static void main(String[] args) {
        Singleton2 singleton = Singleton2.getInstance();
        singleton.hello();
 
    }
 
}
 
class Singleton2{
    private static Singleton2 instance;
    private Singleton2(){}
 
    public static Singleton2 getInstance() {
        if (instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
 
    public void hello(){
        System.out.println("Hello World! ——单例模式-懒汉式");
    }
}
结果

1
Hello World! ——单例模式-懒汉式
单例模式-懒汉式(线程安全版)
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

代码
//单例模式-懒汉式
public class SingletonDemo3 {
    public static void main(String[] args) {
        Singleton3 singleton = Singleton3.getInstance();
        singleton.hello();
 
    }
 
}
 
class Singleton3{
    private static Singleton3 instance;
    private Singleton3(){}
 
    public synchronized static Singleton3 getInstance() {
        if (instance == null){
            instance = new Singleton3();
        }
        return instance;
    }
 
    public void hello(){
        System.out.println("Hello World! ——单例模式-懒汉式");
    }
}
结果

复制代码
1
Hello World! ——单例模式-懒汉式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
32、有以下代码: 请问输出的结果是: 答案: A
class A{
    public A(String str){
         
    }
}
public class Test{
    public static void main(String[] args) {
        A classa=new A("he");
        A classb=new A("he");
        System.out.println(classa==classb);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

A、false
B、true
C、报错
D、以上选项都不正确
解析:1、答案为 false 因为== 表示的是否指向的是同一个内存。

System.out.println(classa.equals(classb)); 如果这这样输出 答案也是错误的 因为子类没有覆盖Object

的equals()方法,而默认调用==的这个方法 判断两个对象是否相等需要覆盖equals()方法和hashcaode()方法

2、这题不管是还是equals输出结果都为false因为equals没有被重写时默认调用进行比较。

3、object类――众类鼻祖 1.取得对象信息:toString():对象输出时,会默认调用Object类的toString()方法,将对象信息变为字符串返回。 2.对象相等判断方法:equals():两个对象进行比较时,实际上是比较两个对象的地址值(从程序看出两个对象内容完全相等,但是结果是不相等的,这是因为classa与classb的内容分别在不同的内存空间指向了不同的内存地址)。所以要对equals()进行覆写,判断equals()方法里面的Object类对象是否与调用equals()的类是同一个类的实例(用instanceof判断),如果是,则进行向下转型,然后再调用String类中的equals方法对属性进行比较。 3.对象签名:hashCode():Object类有两种方法来推断对象的标识:equals()和hashCode()。如果根据equals()方法判断两个对象是相等的,那么对这两个对象中的每一个调用hashCode()方法都必然生成相同的整数结果。但是反过来,如果两个hashCode()返回的结果相等,两个对象的equals()方法却不一定相等。在默认情况下equals()方法用来比较两个对象的地址值,而原始的hashCode()方法用来返回其所在对象的物理地址(ps:对于非字符串变量而言,equals和比较的是地址,对于字符串变量而言equals()比较的是内容比较地址)

33、以下代码将打印出 答案:B
public static void main(String args[]) {
      List  Listlist1 = new ArrayList();
      Listlist1.add(0);
      List Listlist2 = Listlist1;
      System.out.println(Listlist1.get(0) instanceof Integer);
      System.out.println(Listlist2.get(0) instanceof Integer);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

A、编译错误
B、true true
C、true false
D、false false
解析:collection类型的集合(ArrayList,LinkedList)只能装入对象类型的数据,该题中装入了0,是一个基本类型,但是JDK5以后提供了自动装箱与自动拆箱,所以int类型自动装箱变为了Integer类型。编译能够正常通过。

将list1的引用赋值给了list2,那么list1和list2都将指向同一个堆内存空间。instanceof是Java中关键字,用于判断一个对象是否属于某个特定类的实例,并且返回boolean类型的返回值。显然,list1.get(0)和list2.get(0)都属于Integer的实例

2、答案B 不指定ArrayList类型,存入数据,再次取出时,默认是Object类型;但这个题的关键是instanceof关键字,instanceof执行时类似利用java反射机制,识别对象信息。

3、List集合中的元素必须是对象。

Listlist1.add(0);JDK1.5之后支持自动装箱(int类型自动装箱成Integer),编译通过。

instanceof:前一个参数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是一个接口, 它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例

List没有使用泛型,说明使用get(0)取出的元素的编译类型是Object型的, 但运行时类型是Integer。所以打印true。这边体现了多态。

而Listlist1把引用赋给了List list2,说明两个指向同一个对象。第二个打印的也是true。

34、下面代码运行结果是? 答案:
class Value{
    public int i=15;
}
public class Test{
    public static void main(String argv[]){
        Test t=new Test( );
        t.first( );
    }
 
public void first( ){
    int i=5;
    Value v=new Value( );
    v.i=25;
    second(v,i);
    System.out.println(v.i);
}
 
public void second(Value v,int i){
    i = 0;
    v.i = 20;
    Value val = new Value( );
    v = val;
    System.out.println(v.i+" "+i);
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

A、15 0 20
B、15 0 15
C、20 0 20
D、0 15 20
解析:1、这题选A,考察的是值传递与引用传递,Java中原始数据类型都是值传递,传递的是值得副本,形参的改变不会影响实际参数的值, 引用传递传递的是引用类型数据,包括String,数组,列表, map,类对象等类型,形参与实参指向的是同一内存地址,因此形参改变会影响实参的值。

2、img

3、可能有人会选择B,包括我刚开始也是。总以为v不是已经指向了val了吗??为什么还是20呢?不应该是15吗?

其实,原因很简单。现在我们把second()换一下

publicvoidsecond(Value tmp,inti){

i = 0;

tmp.i = 20;

Value val = newValue( );

tmp = val;

System.out.println(tmp.i+" "+i);

}

这个tmp其实相当于是一个指向原来first中的V这个对象的指针,也就是对v对象的引用而已。但是引用是会改变所指的地址的值的。

所以在second中当tmp.i= 20的时候,就把原来first中的v的i值改为20了。接下来,又把tmp指向了新建的一个对象,所以在second中的tmp

现在指的是新的对象val,i值为15.

当执行完毕second后,在first中在此输出v.i的时候,应为前面second中已经把该位置的i的值改为了20,所以输出的是20.

至于疑惑v指向了val,其实只是名字的问题,在second中的v实践也是另外的一个变量,名字相同了而已,这个估计也是纠结的重点。

简单的总结,不对希望可以提出来,谢谢!

35、有关线程的哪些叙述是对的() 答案:B C D

A、一旦一个线程被创建,它就立即开始运行。
B、使用start()方法可以使一个线程成为可运行的,但是它不一定立即开始运行。
C、当一个线程因为抢先机制而停止运行,它可能被放在可运行队列的前面。
D、一个线程可能因为不同的原因停止并进入就绪状态。
解析:1、我自己最开始的时候只选了BD没选C。看评论里面也对C存疑,通过书籍查证C是可以选的。

在抢先式系统下,由高优先级的线程参与调度。分为2种情况:

1.若多个线程都处于就绪状态,则具有高优先级的线程会在低优先级之前得到执行;

2.在当前线程的运行过程中,如果有较高级别的线程准备就绪,则正在运行的较低级别的线程将被挂起,转到较高级别的线程运行,直到结束后又会转到原来被挂起的线程。

第二种情况就描述了C所代表的情况,可以看到当较高级别的线程抢去运行权并运行完成之后,是先将权利转给原来的线程的,所以C是正确的。

2、一个新创建的线程并不是自动的开始运行的,必须调用它的start()方法使之将线程放入可运行态(runnable state),这只是意味着该线程可被JVM的线程调度程序调度而不是意味着它可以立即运行。
线程的调度是抢先式的,而不是分时间片式的。
具有比当前运行线程高优先级的线程可以使当前线程停止运行而进入就绪状态。
不同优先级的线程间是抢先式的,而同级线程间是轮换式的。
一个线程停止运行可以是因为不同原因,可能是因为更高优先级线程的抢占,也可能是因为调用sleep()方法。
而即使是因为抢先而停止也不一定就进入可运行队列的前面,因为同级线程是轮换式的,它的运行可能就是因为轮换,而它因抢占而停止后只能在轮换队列中排队而不能排在前面。

36、下面哪些类可以被继承? Java.lang.Thread、java.lang.Number、java.lang.Double、java.lang.Math、 java.lang.ClassLoad 答案:A B E

A、Thread
B、Number
C、Double
D、Math
E、ClassLoader
解析:答案:ABE

A,Thread可以被继承,用于创建新的线程

B,Number类可以被继承,Integer,Float,Double等都继承自Number类

C,Double类的声明为

public final class Doubleextends Numberimplements Comparable<Double>
  • 1

final生明的类不能被继承

D,Math类的声明为

public final class Mathextends Object
  • 1

不能被继承

E,ClassLoader可以被继承,用户可以自定义类加载器

2、java.lang包中不能被继承的类:

public final class Byte

public final class Character

public static final class Character.UnicodeBlock

public final class Class

public final class Compile

public final class Double

public final class Float

public final class Integer

public final class Long

public final class Math

public final class ProcessBuilder

public final class RuntimePermission

public final class Short

public final class StackTraceElement

public final class StrictMath

public final class String

public final class StringBuffer

public final class StringBuilder

public final class System

public final class Void

37、下列类定义中哪些是合法的抽象类的定义?() 答案:C

A、abstract Animal{abstract void growl();}
B、class abstract Animal{abstract void growl();}
C、abstract class Animal{abstract void growl();}
D、abstract class Animal{abstract void growl(){System.out.println( “growl”);};}
解析:选C

1. 首先,类的修饰符,都应该在class关键字之前,AB错;

2. 抽象方法不能有方法体,D错。

2、自己总结的,有遗漏请私我指正,不知道为什么网上都说接口没有Main方法,然而我用IDEA和eclipse是可以的,不知道是不是我理解错了。

*jdk1.8之前*

*接口*

1.多实现

2.变量类型默认且只能为为public static final

3.函数类型默认且只能为public,只能有public类型的静态成员函数

4.非静态成员函数没有方法体,静态成员函数有方法体

5.子类必须实现所有接口函数

6.可以有main方法;可以new一个接口,需要在方法体中实现所有接口函数

7.没有构造器

*抽象类*

1.单继承

2.变量类型不限(静态变量+非静态变量)

3.函数类型不限(静态函数+非静态函数)

4.非静态函数包含没有方法体的抽象函数. 有方法体的普通函数

5.子类可以不覆写父类的抽象方法,但子类也要申明为抽象类;子类可以选择覆写父类的非抽象方法

6.可以有main方法;不可以new一个抽象类

7.可以有构造器

*Jdk1.8*

*接口中可以有default类型的方法,实现类可以选择实现该方法*

****意义:****默认方法的主要优势是提供一种拓展接口的方法,而不破坏现有代码。另一个优势为该方法是可选的,子类可以根据不同的需求Override或默认实现。

38、Java的Daemon线程,setDaemon( )设置必须要? 答案:A

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

setDaemon()方法必须在线程启动之前调用,当线程正在运行时调用会产生异常。

2、java线程基础知识----java daemon线程

java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程.

1.首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程

A.  用户线程: 用户线程可以简单的理解为用户定义的线程,当然包括main线程(以前我错误的认为main线程也是一个daemon线程,但是慢慢的发现原来main线程不是,因为如果我再main线程中创建一个用户线程,并且打出日志,我们会发现这样一个问题,main线程运行结束了,但是我们的线程任然在运行).

B.  daemon线程: daemon线程是为我们创建的用户线程提供服务的线程,比如说jvm的GC等等,这样的线程有一个非常明显的特征: 当用户线程运行结束的时候,daemon线程将会自动退出.(由此我们可以推出下面关于daemon线程的几条基本特点)

2. daemon 线程的特点:

A.  守护线程创建的过程中需要先调用setDaemon方法进行设置,然后再启动线程.否则会报出IllegalThreadStateException异常.(个人在想一个问题,为什么不能动态更改线程为daemon线程?有时间一个补上这个内容,现在给出一个猜测: 是因为jvm判断线程状态的时候,如果当前只存在一个线程Thread1,如果我们把这个线程动态更改为daemon线程,jvm会认为当前已经不存在用户线程而退出,稍后将会给出正确结论,抱歉!如果有哪位大牛看到,希望给出指点,谢谢!)

B.  由于daemon线程的终止条件是当前是否存在用户线程,所以我们不能指派daemon线程来进行一些业务操作,而只能服务用户线程.

C.  daemon线程创建的子线程任然是daemon线程.

3、A

java中线程分为两种类型:

1:用户线程。通过Thread.setDaemon(false)设置为用户线程;

2:守护线程。通过Thread.setDaemon(true)设置为守护线程,如果不设置,默认用户线程;

守护线程是服务用户线程的线程,在它启动之前必须先set。

39、当你编译和运行下面的代码时,会出现下面选项中的哪种情况? 答案:B
public class Pvf{
    static boolean Paddy;
    public static void main(String args[]){
        System.out.println(Paddy);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

A、编译时错误
B、编译通过并输出结果false
C、编译通过并输出结果true
D、编译通过并输出结果null
解析:类中声明的变量有默认初始值;方法中声明的变量没有默认初始值,必须在定义时初始化,否则在访问该变量时会出错。

boolean类型默认值是false

img

40、能单独和finally语句一起使用的块是( ) 答案:

A、try
B、catch
C、throw
D、throws
解析:解析:处理异常常用的两种方式:
1、try…catch(捕获处理机制);
2、throws(冒泡处理机制).
注意细节:使用try…catch块捕获时可以没有catch块,但当没用catch块的时候必须得有finally块.故选A)

40、以下代码段执行后的输出结果为 答案:D
public class Test {
    public static void main(String[] args) {
        System.out.println(test());
 
    }
    private static int test() {
        int temp = 1;
        try {
            System.out.println(temp);
            return ++temp;
        } catch (Exception e) {
            System.out.println(temp);
            return ++temp;
        } finally {
            ++temp;
            System.out.println(temp);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

A、1,2,2
B、1,2,3
C、1,3,3
D、1,3,2
解析:执行顺序为:

输出try里面的初始temp:1;

temp=2;

保存return里面temp的值:2;

执行finally的语句temp:3,输出temp:3;

返回try中的return语句,返回存在里面的temp的值:2;

输出temp:2。

2、finally代码块在return中间执行。return的值会被放入临时空间,然后执行finally代码块,如果finally中有return,会刷新临时空间的值,方法结束返回临时空间值。

41、以下哪项不是java基础类型() 答案: C

A、int
B、boolean
C、String
D、float
解析:C是正确答案

Java中基本数据类型大体分为两类 数字类型(byte,short,int,long,float,double,char),布尔类型(boolean); 备注:由于char可以和数字间转换,也可认为大的范围是数字类型的。

2、数据类型包括基本数据类型和引用数据类型

基本数据类型:byte,short,int,long,char,float,double,boolean

引用数据类型:数组,接口,枚举,类,空类

3、java的基本数据类型有八种: 1)四种整数类型(byte、short、int、long): byte:8 位,用于表示最小数据单位,如文件中数据,-128~127 short:16 位,很少用,-32768 ~ 32767 int:32 位、最常用,-231-1~231 (21 亿) long:64 位、次常用 注意事项: int i=5; // 5 叫直接量(或字面量),即 直接写出的常数。 整数字面量默认都为 int 类型,所以在定义的 long 型数据后面加 L或 l。 小于 32 位数的变量,都按 int 结果计算。 强转符比数算符优先级高。见常量与变量中的例子。 2)两种浮点数类型(float、double): float:32 位,后缀 F 或 f,1 位符号位,8 位指数,23 位有效尾数。 double:64 位,最常用,后缀 D 或 d,1 位符号位,11 位指数,52 位有效尾 注意事项: 二 进 制 浮 点 数 : 1010100010=101010001.02=10101000.10210(2次方)=1010100.010*211(3次方)= . 10101000102^1010(10次方) 尾数: . 1010100010 指数: 1010 基数:2 浮点数字面量默认都为 double 类型,所以在定义的 float 型数据后面加F 或 f;double 类型可不写后缀,但在小数计算中一定要写 D 或 X.X float 的精度没有 long 高,有效位数(尾数)短。 float 的范围大于 long 指数可以很大。 浮点数是不精确的,不能对浮点数进行精确比较。 3)一种字符类型(char): char:16 位,是整数类型,用单引号括起来的 1 个字符(可以是一个中文字符),使用 Unicode 码代表字符,0~2^16-1(65535) 。 注意事项: 不能为 0个字符。 转义字符:\n 换行 \r 回车 \t Tab 字符 " 双引号 \ 表示一个\ 两字符 char 中间用“+”连接,内部先把字符转成 int 类型,再进行加法运算,char 本质就是个数!二进制的,显示的时候,经过“处理”显示为字符。 4)一种布尔类型(boolean):true 真 和 false 假。 5)类型转换: char–> 自动转换:byte–>short–>int–>long–>float–>double 强制转换:①会损失精度,产生误差,小数点以后的数字全部舍弃。②容易超过取值范围。 6)记忆:8位:Byte(字节型) 16位:short(短整型)、char(字符型) 32位:int(整型)、float(单精度型/浮点型) 64位:long(长整型)、double(双精度型) 最后一个:boolean(布尔类型

42、执行语句“int a= ’ 2 ’ ”后,a的值是( ) 答案:B

A、2
B、50
C、49
D、0
解析:1、常用ASCII码值:空格为32;数字0为48;“A”为65;“a”值为97。

2、一个简便的记忆法:0:48 A:65 a:97,数字连起来是486597 -> 486 597 -> 486 (486 + 111)

3、常见字符的ASCII码值如下:空格的ASCII码值为32;数字0到9的ASCII码值分别为48到57;大写字母“A”到“Z”的ASCII码值分别为65到90;小写字母“a”到“z”的ASCII码值分别为97到到122。

43、Which lines of the following will produce an error? 答案:A
byte a1 = 2, a2 = 4, a3;
short s = 16;
a2 = s;
a3 = a1 * a2;
  • 1
  • 2
  • 3
  • 4

A、Line 3 and Line 4
B、Line 1 only
C、Line 3 only
D、Line 4 only
解析:答案:A

short类型转为byte类型出错

a1*a2结果为int类型,转为byte类型出错

2、数值型变量在默认情况下为Int型,byte和short型在计算时会自动转换为int型计算,结果也是int 型。所以a1*a2的结果是int 型的。

44、 以下代码结果是什么? 答案: C
public class foo {
    public static void main(String sgf[]) {
 
        StringBuffer a=new StringBuffer("A");
 
        StringBuffer b=new StringBuffer("B");
 
        operate(a,b);
 
        System.out.println(a+"."+b);
    }
    static void operate(StringBuffer x,StringBuffer y) {
        x.append(y);
        y=x;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

A、代码可以编译运行,输出“AB.AB”。
B、代码可以编译运行,输出“A.A”。
C、代码可以编译运行,输出“AB.B”。
D、代码可以编译运行,输出“A.B”。
解析:这里简单地说,a,b,x,y就是四个指针。y本来指向的是b所指向的对象,但是一个“=”,y就指向了x所指向的目标即是a指向的对象,因此原来b所指向的目标并没有发生任何改变。与y不同的是,x进行的是对象操作,此时此对象在内存中是真正的本质上的改变。有点绕,但是手机打字,没发画图,不然其实很容易理解。

2、引用a指向对象A

引用b指向对象B

引用x指向对象A

引用y指向对象B

在operate方法中,引用x指向的对象A被连接了B,对象A也就被改变为AB

然后又把引用y指向了x所指向的对象地址,也就是此时引用a,x,y指向同一个对象AB

而引用b没有发生任何变化,依旧指向对象B。

45、在J2EE中,使用Servlet过滤器,需要在web.xml中配置()元素 答案:A B

A、
B、
C、
D、
解析:答案:AB
Servlet过滤器的配置包括两部分:
第一部分是过滤器在Web应用中的定义,由元素表示,包括和两个必需的子元素
第二部分是过滤器映射的定义,由元素表示,可以将一个过滤器映射到一个或者多个Servlet或JSP文件,也可以采用url-pattern将过滤器映射到任意特征的URL。

46、如下的Java程序 答案:B
public class Test { 
     public static void main(String[] args) { 
     System.out.println(args[0]); 
     } 
} 
 若采用命令行“java Test one two three”调用,则程序输出的结果为:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

A、Test
B、one
C、two
D、java
解析:采用命令行“ java Test one two three ”调用

其中Test为调用的方法,而one two three则为Test方法里面main函数的参数;

System.out.println(args[0]);表示输出第一个元素,故为one;

47、事务隔离级别是由谁实现的? 答案:C

A、Java应用程序
B、Hibernate
C、数据库系统
D、JDBC驱动程序
解析:答案:C

A,我们写java程序的时候只是设定事物的隔离级别,而不是去实现它

B,Hibernate是一个java的数据持久化框架,方便数据库的访问

C,事物隔离级别由数据库系统实现,是数据库系统本身的一个功能

D,JDBC是java database connector,也就是java访问数据库的驱动

2、C

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。

√: 可能出现 ×: 不会出现

脏读不可重复读幻读
Read uncommitted
Read committed×
Repeatable read××
Serializable×××
48、上述代码返回结果为: 答案:B
Integer a = 1;
Integer b = 1;
Integer c = 500;
Integer d = 500;
System.out.print(a == b);
System.out.print(c == d);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

A、true、true
B、true、false
C、false、true
D、false、false
解析:1、

Integer类型在-128–>127范围之间是被缓存了的,也就是每个对象的内存地址是相同的,赋值就直接从缓存中取,不会有新的对象产生,而大于这个范围,将会重新创建一个Integer对象,也就是new一个对象出来,当然地址就不同了,也就!=;

2、Interger的范围时[-128,127],在这个范围内比较大小,相等为true,超过范围为false

49、执行语句“int a= ’ 2 ’ ”后,a的值是( ) 答案:B

A、2
B、50
C、49
D、0
解析:1、常用ASCII码值:空格为32;数字0为48;“A”为65;“a”值为97。

2、一个简便的记忆法:0:48 A:65 a:97,数字连起来是486597 -> 486 597 -> 486 (486 + 111)

3、常见字符的ASCII码值如下:空格的ASCII码值为32;数字0到9的ASCII码值分别为48到57;大写字母“A”到“Z”的ASCII码值分别为65到90;小写字母“a”到“z”的ASCII码值分别为97到到122。

50、从以下哪一个选项中可以获得Servlet的初始化参数? 答案:C

A、Servlet
B、ServletContext
C、ServletConfig
D、GenericServlet
解析:C

通过ServletConfig接口的getInitParameter(java.lang.String name)方法

2、ServletContext对象:servlet容器在启动时会加载web应用,并为每个web应用创建唯一的servlet context对象,可以把ServletContext看成是一个Web应用的服务器端组件的共享内存,在ServletContext中可以存放共享数据。ServletContext对象是真正的一个全局对象,凡是web容器中的Servlet都可以访问。

整个web应用只有唯一的一个ServletContext对象

servletConfig对象:用于封装servlet的配置信息。从一个servlet被实例化后,对任何客户端在任何时候访问有效,但仅对servlet自身有效,一个servlet的ServletConfig对象不能被另一个servlet访问

51、下列类在多重catch中同时出现时,哪一个异常类应最后一个列出() 答案:C

A、ArithmeticException
B、NumberFormatException
C、Exception
D、ArrayIndexOutOfBoundException
解析:这是多重catch块的顺序问题,由于异常处理系统就近寻找匹配异常处理程序,应先子类后父类。

2、ArithmeticException 是算数异常

NumberFormatException 是数据格式异常

Exception 异常

ArrayIndexOutOfBoundException 数组索引超过界限异常

先处理具体的异常,如果没有则放到一个大的范围之中Exception

52、下面有关java实例变量,局部变量,类变量和final变量的说法,错误的是? 答案:B

A、实例变量指的是类中定义的变量,即成员变量,如果没有初始化,会有默认值。
B、局部变量指的是在方法中定义的变量,如果没有初始化,会有默认值
C、类变量指的是用static修饰的属性
D、final变量指的是用final 修饰的变量
解析:B,局部变量必须有初始值。

2、定义在类中的变量是类的成员变量,可以不进行初始化,Java会自动进行初始化,如果是引用类型默认初始化为null,如果是基本类型例如int则会默认初始化为0

局部变量是定义在方法中的变量,必须要进行初始化,否则不同通过编译

被static关键字修饰的变量是静态的,静态变量随着类的加载而加载,所以也被称为类变量

被final修饰发变量是常量

53、 答案:C
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)保留的字符数为()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

A、5
B、10
C、15
D、20
解析:substring实际是new,5字符

str3和4也都是new,每个5字符

分别都会创建新的对象

常量池是PermGen的

因此应该是一共15字符

2、解析:这是一个关于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

54、下面哪些情况会引发异常: 答案:A B C

A、数组越界
B、指定URL不存在
C、使用throw语句抛出
D、使用throws语句
解析:1、throws出现在方法头,throw出现在方法体 2、throws表示出现异常的一种可能性,并不一定会发生异常;throw则是抛出了异常,执行throw则一定抛出了某种异常。 3、两者都是消极的异常处理方式,只是抛出或者可能抛出异常,是不会由函数处理,真正的处理异常由它的上层调用处理。

55、下面哪些描述是正确的:( ) 答案:B C
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;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

A、b = null执行后b可以被垃圾回收
B、a = null执行后b可以被垃圾回收
C、a = null执行后a可以被垃圾回收
D、a,b必须在整个程序结束后才能被垃圾回收
解析:

img

2、内存如下:

a -> “a(b)”
b -> “b”

a引用指向一块空间,这块空间里面包含着b对象

b引用指向一块空间,这块空间是b对象

A选项,b = null执行后b可以被垃圾回收。这里"b可以被垃圾回收"中的b指的是引用b指向的内存。这块内存即使不被引用b指向,还是被引用a指向着,不会被回收。
B选项,a = null执行后b可以被垃圾回收。从代码中可以看到,a = null是在b = null后执行的,该行执行后,引用a和b都没有指向对象,对象会被回收。

C选项,同理。

56、只有实现了()接口的类,其对象才能序列化。 答案:A

A、Serializable
B、Cloneable
C、Comparable
D、Writeable
解析:Serializable要实现序列化对象必须要实现的接口

2、答案是A:Serializable接口是专门提供给类实现序列化用的。要实现序列化对象必须要实现 Serializable 接口

3、B、可进行复制

C、比较器

D、hadoop中的接口

57、的输出是? 答案:D
class Foo {
    final int i;
    int j;
    public void doSomething() {
        System.out.println(++j + i);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

A、0
B、1
C、2
D、不能执行,因为编译有错
解析:D。final类型的变量一定要初始化,因为final的变量不可更改。

final作为对象成员存在时,必须初始化;但是,如果不初始化,也可以在类的构造函数中初始

因为java允许将数据成员声明为final,却不赋初值。但是,blank finals必须在使用之前初始化,且必须在构造函数中初始化

58、下列代码编译和运行的结果是:() 答案:C
public class Threads4{
     public static void main(String[] args){
         new Threads4().go();
     }
     public void go(){
         Runnable r=new Runnable(){
             public void run(){
                 System.out.print("foo");
             }
         };
     Thread t=new Thread(r);
     t.start();
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

A、编译错误
B、抛出运行时异常
C、输出:foo
D、代码正常运行,但是无输出
解析:在java多线程中实现多线程的方式有两种①extends Thread ②implements Runnable。这两种情况是我们最常见的,还有一种是由第二种变形而来的直接new Runnable(){},我们都知道java的接口是不可以实例化的,但代码中的new Runnable(){xxx}确是实例化了,为什么? 接口和抽象类不可以实例化是对的,这个是java语法规范来的,而new Runnable(){}其实不是实例化Runnable接口来的,实际上一种内部类的一种简写 在这里:

①首先构造了一个”implements Runnable “的无名local内部类(方法内的内部类)

②然后构造了这个无名local内部类的一个实例

③然后用Runnable来表示这个无名local内部类的type(OO多态)。 例如上面这段代码编译后你会看到其实是编译了两个类来的,如下:

其中Text2$1就是无名local内部内类,这个也就很好地解释了为什么在main()方法中new Runnable(){xxx}里面的调用main()方法中的变量的时候要用final关键字来修饰

59、关于Java中参数传递的说法,哪个是错误的? 答案:D

A、在方法中,修改一个基础类型的参数不会影响原始参数值
B、在方法中,改变一个对象参数的引用不会影响到原始引用
C、在方法中,修改一个对象的属性会影响原始对象参数
D、在方法中,修改集合和Maps的元素不会影响原始集合参数
解析:

解析: 注意!Java中方法的参数传递都是值传递
A. 在方法中,修改一个基础类型的参数不会影响原始参数值
public static void main(String []args){
    int i = 5;   
    func(i);
    System.out.println(i);
}
static void func(int j){
    j = 10;
}
 
//输出结果
5
在主方法调用func(int j) 时 , 参数i是实际参数 , 值为5 , 参数j是形式参数 , 值是i给的 , 也是5 , i和j没有任何关系 , 是两个独立的参数 , 所以修改j的值时与i没有关系 , 仍然输出5。

B. 在方法中,改变一个对象参数的引用不会影响到原始引用
public static void main(String []args){
    User rabbiter = new User();
    rabbiter.setName("rabbiter");
    func(rabbiter);
    System.out.println(rabbiter.getName());
}
static void func(User user){
    user = new User();
    user.setName("zhangsan");
}
 
//输出结果
rabbiter
在主方法调用func(User user) 时 , 对象rabbiter保存的是一个地址值 , 本质上就是把rabbiter的地址值给了形参user , 所以此时实参rabbiter和形参user指向在堆中的同一个对象 , 他们的地址值相同 , 只是指向的对象一致 , 所以并不违反值传递的理论。
此时 , 如果修改形参user , new一个新的对象并让user指向它 , 修改的只是形参保存的地址 , 与实参rabbiter无关 , rabbiter指向的对象仍然是之前的那个对象。

C. 在方法中,修改一个对象的属性会影响原始对象参数
public static void main(String []args){
    User rabbiter = new User();
    rabbiter.setName("rabbiter");
    func(rabbiter);
    System.out.println(rabbiter.getName());
}
static void func(User user){
    user.setName("zhangsan");
}
 
//输出结果
zhangsan
在主方法调用func(User user) 时 , 对象rabbiter保存的是一个地址值 , 本质上就是把rabbiter的地址值给了形参user , 所以此时实参rabbiter和形参user指向在堆中的同一个对象 , 他们的地址值相同 , 指向的对象一致 , 所以并不违反值传递的理论。
那么user对其指向的对象的属性name进行修改 , rabbiter指向的对象的name属性也就被修改了。

D. 在方法中,修改集合和Maps的元素不会影响原始集合参数
集合和Maps都是对象 , 所以此项跟C选项的解析一致。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
60、下面哪项技术可以用在WEB开发中实现会话跟踪实现? 答案:A B C D

A、session
B、Cookie
C、地址重写
D、隐藏域
解析:会话跟踪是一种灵活、轻便的机制,它使Web上的状态编程变为可能。
HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。当一个客户在多个页面间切换时,服务器会保存该用户的信息。
有四种方法可以实现会话跟踪技术:URL重写、隐藏表单域、Cookie、Session。
1).隐藏表单域:,非常适合步需要大量数据存储的会话应用。
2).URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。
3).Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP
响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个
Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至
在客户端计算机重启后它仍可以保留其值
4).Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话

61、try括号里有return语句, finally执行顺序 答案:B

A、不执行finally代码
B、return前执行
C、return后执行
D、
解析:

下面的关键内容来自:

https://www.ibm.com/developerworks/cn/java/j-lo-finally/

是关于 try return finally 的详细解释文档,很有说服力。

清单 5.
 public class Test { 
 public static void main(String[] args) { 
        System.out.println("return value of getValue(): " + getValue()); 
	 } 

 public static int getValue() { 
        try { 
                 return 0; 
        } finally { 
                 return 1; 
	        } 
	 } 
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

清单 5 的执行结果:

 return value of getValue(): 1
  • 1
清单 6.
 public class Test { 
 public static void main(String[] args) { 
        System.out.println("return value of getValue(): " + getValue()); 
	 } 

 public static int getValue() { 
        int i = 1; 
        try { 
                 return i; 
        } finally { 
                 i++; 
        } 
	 } 
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

清单 6 的执行结果:

 return value of getValue(): 1
  • 1

利用我们上面分析得出的结论:finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。 由此,可以轻松的理解清单 5 的执行结果是 1。因为 finally 中的 return 1;语句要在 try 中的 return 0;语句之前执行,那么 finally 中的 return 1;语句执行后,把程序的控制权转交给了它的调用者 main()函数,并且返回值为 1。那为什么清单 6 的返回值不是 2,而是 1 呢?按照清单 5 的分析逻辑,finally 中的 i++;语句应该在 try 中的 return i;之前执行啊? i 的初始值为 1,那么执行 i++;之后为 2,再执行 return i;那不就应该是 2 吗?怎么变成 1 了呢?

关于 Java 虚拟机是如何编译 finally 语句块的问题,有兴趣的读者可以参考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 节 Compiling finally。那里详细介绍了 Java 虚拟机是如何编译 finally 语句块。实际上,Java 虚拟机会把 finally 语句块作为 subroutine(对于这个 subroutine 不知该如何翻译为好,干脆就不翻译了,免得产生歧义和误解。)直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值。

是不是不太好理解,那我们就用具体的例子来做形象的说明吧!

为了能够解释清单 6 的执行结果,我们来分析一下清单 6 的字节码(byte-code):

 Compiled from "Test.java"
 public class Test extends java.lang.Object{ 
 public Test(); 
  Code: 
   0: 	 aload_0 
   1:invokespecial#1; //Method java/lang/Object."<init>":()V 
   4: 	 return 

  LineNumberTable: 
   line 1: 0 

 public static void main(java.lang.String[]); 
  Code: 
   0: 	 getstatic 	 #2; //Field java/lang/System.out:Ljava/io/PrintStream; 
   3: 	 new 	 #3; //class java/lang/StringBuilder 
   6: 	 dup 
   7: 	 invokespecial 	 #4; //Method java/lang/StringBuilder."<init>":()V 
   10: 	 ldc 	 #5; //String return value of getValue(): 
   12: 	 invokevirtual 	 
   #6; //Method java/lang/StringBuilder.append:(
       Ljava/lang/String;)Ljava/lang/StringBuilder; 
   15: 	 invokestatic 	 #7; //Method getValue:()I 
   18: 	 invokevirtual 	 
   #8; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 
   21: 	 invokevirtual 	 
   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
   24: 	 invokevirtual 	 #10; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
   27: 	 return 

 public static int getValue(); 
  Code: 
   0: 	 iconst_1 
   1: 	 istore_0 
   2: 	 iload_0 
   3: 	 istore_1 
   4: 	 iinc 	 0, 1 
   7: 	 iload_1 
   8: 	 ireturn 
   9: 	 astore_2 
   10: 	 iinc 	 0, 1 
   13: 	 aload_2 
   14: 	 athrow 
  Exception table: 
   from   to  target type 
     2     4     9   any 
     9    10     9   any 
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

对于 Test()构造方法与 main()方法,在这里,我们不做过多解释。让我们来分析一下 getValue()方法的执行。在这之前,先让我把 getValue()中用到的虚拟机指令解释一下,以便读者能够正确的理解该函数的执行。

1.	iconst_ 
Description: Push the int constant  (-1, 0, 1, 2, 3, 4 or 5) onto the operand stack.
Forms: iconst_m1 = 2 (0x2)  iconst_0 = 3 (0x3)  iconst_1 = 4 (0x4)  
iconst_2 = 5 (0x5) iconst_3 = 6 (0x6)  iconst_4 = 7 (0x7)  iconst_5 = 8 (0x8)

2.	istore_ 
Description: Store int into local variable. The  must be an index into the 
local variable array of the current frame. 
Forms: istore_0 = 59 (0x3b)  istore_1 = 60 (0x3c)  istore_2 = 61 (0x3d)  
istore_3 = 62 (0x3e)

3.	iload_ 
Description: Load int from local variable. The  must be an index into the 
local variable array of the current frame. 
Forms: iload_0 = 26 (0x1a)  iload_1 = 27 (0x1b)  iload_2 = 28 (0x1c)  iload_3 = 29 (0x1d)

4.	iinc index, const 
Description: Increment local variable by constant. The index is an unsigned byte that 
must be an index into the local variable array of the current frame. The const is an 
immediate signed byte. The local variable at index must contain an int. The value 
const is first sign-extended to an int, and then the local variable at index is 
incremented by that amount.
Forms:  iinc = 132 (0x84)

Format:
iinc 	
index 	
const 	

5.	ireturn 
Description: Return int from method.
Forms:  ireturn = 172 (0xac)

6.	astore_ 
Description: Store reference into local variable. The  must be an index into the 
local variable array of the current frame.
Forms: astore_0 = 75 (0x4b) astore_1 = 76 (0x4c) astore_2 =77 (0x4d) astore_3 =78 (0x4e)

7.	aload_ 
Description: Load reference from local variable. The  must be an index into the 
local variable array of the current frame.
Forms: aload_0 = 42 (0x2a) aload_1 = 43 (0x2b) aload_2 = 44 (0x2c) aload_3 = 45 (0x2d)

8.	athrow 
Description: Throw exception or error.
Forms: athrow = 191 (0xbf)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

有了以上的 Java 虚拟机指令,我们来分析一下其执行顺序:分为正常执行(没有 exception)和异常执行(有 exception)两种情况。我们先来看一下正常执行的情况,如图 1 所示:

图 1. getValue()函数正常执行的情况

img

由上图,我们可以清晰的看出,在 finally 语句块(iinc 0, 1)执行之前,getValue()方法保存了其返回值(1)到本地表量表中 1 的位置,完成这个任务的指令是 istore_1;然后执行 finally 语句块(iinc 0, 1),finally 语句块把位于 0 这个位置的本地变量表中的值加 1,变成 2;待 finally 语句块执行完毕之后,把本地表量表中 1 的位置上值恢复到操作数栈(iload_1),最后执行 ireturn 指令把当前操作数栈中的值(1)返回给其调用者(main)。这就是为什么清单 6 的执行结果是 1,而不是 2 的原因。

再让我们来看看异常执行的情况。是不是有人会问,你的清单 6 中都没有 catch 语句,哪来的异常处理呢?我觉得这是一个好问题,其实,即使没有 catch 语句,Java 编译器编译出的字节码中还是有默认的异常处理的,别忘了,除了需要捕获的异常,还可能有不需捕获的异常(如:RunTimeException 和 Error)。

从 getValue()方法的字节码中,我们可以看到它的异常处理表(exception table), 如下:

Exception table:

from to target type

2 4 9 any

它的意思是说:如果从 2 到 4 这段指令出现异常,则由从 9 开始的指令来处理。

图 2. getValue()函数异常执行的情况

img

先说明一点,上图中的 exception 其实应该是 exception 对象的引用,为了方便说明,我直接把它写成 exception 了。

由上图(图 2)可知,当从 2 到 4 这段指令出现异常时,将会产生一个 exception 对象,并且把它压入当前操作数栈的栈顶。接下来是 astore_2 这条指令,它负责把 exception 对象保存到本地变量表中 2 的位置,然后执行 finally 语句块,待 finally 语句块执行完毕后,再由 aload_2 这条指令把预先存储的 exception 对象恢复到操作数栈中,最后由 athrow 指令将其返回给该方法的调用者(main)。

通过以上的分析,大家应该已经清楚 try-catch-finally 语句块的执行流程了吧!

62、关于继承和实现说法正确的 是 ? ( ) 答案:A

A、类可以实现多个接口,接口可以继承(或扩展)多个接口
B、类可以实现多个接口,接口不能继承(或扩展)多个接口
C、类和接口都可以实现多个接口
D、类和接口都不可以实现多个接口
解析:1.类与类之间的关系为继承,只能单继承,但可以多层继承。 2.类与接口之间的关系为实现,既可以单实现,也可以多实现。 3.接口与接口之间的关系为继承,既可以单继承,也可以多继承。 故为A

2、java类是单继承的。 java接口可以多继承。 不允许类多重继承的主要原因是,如果A同时继承B和C,而B和C同时又有一个D方法,A如何决定该继承那一个呢? 但接口不存在这样的问题,接口全都是抽象方法继承谁都无所谓,所以接口可以继承多个接口

63、java中下面哪些是Object类的方法() 答案:A B D

A、notify()
B、notifyAll()
C、sleep()
D、wait()
解析:Object类中方法:

protected Object clone()创建并返回此对象的一个副本。

boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
class getClass()返回此 Object 的运行时类。
int hashCode()返回该对象的哈希码值。
void notify()唤醒在此对象监视器上等待的单个线程。
void notifyAll()唤醒在此对象监视器上等待的所有线程。
String toString()返回该对象的字符串表示。
void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。

64、关于下面这段Java程序,哪些描述是正确的:( ) 答案:C
public class ThreadTest extends Thread {
    public void run() {
        System.out.println("In run");
        yield();
        System.out.println("Leaving run");
    }
    public static void main(String []argv) {
        (new ThreadTest()).start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

A、程序运行输出只有In run
B、程序运行输出只有Leaving run
C、程序运行输出先有In run后有Leaving run
D、程序运行输出先有Leaving run后有In run
解析:Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。

yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

65、关于运行时常量池,下列哪个说法是正确的 答案:B C D

A、运行时常量池大小受栈区大小的影响
B、运行时常量池大小受方法区大小的影响
C、存放了编译时期生成的各种字面量
D、存放编译时期生成的符号引用
解析:之前写的确实写的有问题,我都没想到会被这么多人赞,为了不误人子弟,我重新写一写这个题,用到的知识点:

为了避免歧义,以下提及的JVM,是Hotspot

方法区是什么?
方法区是广义上的概念,是一个定义、标准,可以理解为Java中的接口,在Jdk6、7方法区的实现叫永久代;Jdk8之后方法区的实现叫元空间,并从JVM内存中移除,放到了直接内存中;
方法区是被所有方法线程共享的一块内存区域.

运行时常量池是什么?
运行时常量池是每一个类或接口的常量池的运行时表示形式.

具体体现就是在Java编译后生成的.class文件中,会有class常量池,也就是静态的运行时常量池;

运行时常量池存放的位置?

运行时常量池一直是方法区的一部分,在不同版本的JDK中,由于方法区位置的变化,运行时常量池所处的位置也不一样.JDK1.7及之前方法区位于永久代.由于一些原因在JDK1.8之后彻底祛除了永久代,用元空间代替。

运行时常量池存放什么?
存放编译期生成的各种字面量和符号引用;(字面量和符号引用不懂的同学请自行查阅)
运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。 此时不再是常量池中的符号地址了,这里换为真实地址。

运行时常量池与字符串常量池?(可能有同学把他俩搞混)
字符串常量池:在JVM中,为了减少相同的字符串的重复创建,为了达到节省内存的目的。会单独开辟一块内存,用于保存字符串常量,这个内存区域被叫做字符串常量池.

字符串常量池位置?

JDK1.6时字符串常量池,被存放在方法区中(永久代),而到了JDK1.7,因为永久代垃圾回收频率低;而字符串使用频率比较高,不能及时回收字符串,会导致导致永久代内存不足,就被移动到了堆内存中。

66、以下不属于构造方法特征的是() 答案:D

A、构造方法名与类名相同
B、构造方法不返回任何值,也没有返回类型
C、构造方法在创建对象时调用,其他地方不能显式地直接调用
D、每一个类只能有一个构造方法
解析:这道题目感觉有很多模糊又不明确的地方,题目质量不好。

A:一个类里面多个内部类,构造方法名是与和.java文件同名的public类名。内部类也是类,构造方法名和内部类名不同。

B:构造方法不返回任何值,也没有返回类型。无异议。

C:子类在构造方法里面调用父类的构造方法时,会在第一行使用“super(参数列表)”显示调用父类的构造方法。这里是显示地直接调用,而且没有创建新对象。

D:每一个和.java文件同名的public类可以有多个构造方法,构造方法允许重载。内部类也可以有多个构造方法,而匿名内部类一个构造方法都没有。

67、有以下代码片段:请问输出的结果是: 答案:D
String str1="hello";
 
String str2="he"+ new String("llo");
 
System.out.println(str1==str2);
  • 1
  • 2
  • 3
  • 4
  • 5

A、true
B、都不对
C、null
D、false
解析:

 1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。
 
    2)String类底层是char数组来保存字符串的。
 
    对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象
 
 
 
<h3 style="color: rgb(47,47,47);">
    字符串常量池
 
 
    在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。
 
    JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池
 
    工作原理
 
    当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
 
    实现前提
 
    字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。
 
 
 
    String str1 = "hello";
 
    这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的;
 
    String str2 = "he" + new String("llo");
 
    这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。
 
    如果用str1.equal(str2),那么返回的是true;因为String类重写了equals()方法。
 
    编译器没那么智能,它不知道"he" + new String("llo")的内容是什么,所以才不敢贸然把"hello"这个对象的引用赋给str2.
 
    如果语句改为:"he"+"llo"这样就是true了。
 
    new String("zz")实际上创建了2个String对象,就是使用“zz”通过双引号创建的(在字符串常量池),另一个是通过new创建的(在堆里)。只不过他们的创建的时期不同,一个是编译期,一个是运行期。
 
    String s = "a"+"b"+"c";
 
    语句中,“a”,"b", "c"都是常量,编译时就直接存储他们的字面值,而不是他们的引用,在编译时就直接将它们连接的结果提取出来变成"abc"了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
68、在java7中,下列哪个说法是正确的: 答案:D

A、ConcurrentHashMap使用synchronized关键字保证线程安全
B、HashMap实现了Collection接口
C、Arrays.asList方法返回java.util.ArrayList对象
D、SimpleDateFormat对象是线程不安全的
解析:hashMap在单线程中使用大大提高效率,在多线程的情况下使用hashTable来确保安全。hashTable中使用synchronized关键字来实现安全机制,但是synchronized是对整张hash表进行锁定即让线程独享整张hash表,在安全同时造成了浪费。concurrentHashMap采用分段加锁的机制来确保安全

2、Arrays.asList()

将一个数组转化为一个List对象,这个方***返回一个ArrayList类型的对象, 这个ArrayList类并非java.util.ArrayList类,**而是Arrays类的静态内部类!**用这个对象对列表进行添加删除更新操作,就会报UnsupportedOperationException异常。

69、如下代码,执行test()函数后,屏幕打印结果为() 答案:D
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 + "");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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

70、下面哪个不对? 答案:C

A、RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine.
B、A method is not required to declare in its throws clause any subclasses of RuntimeExeption that might be thrown during the execution of the method but not caught
C、An RuntimeException is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
D、NullPointerException is one kind of RuntimeException
解析:

img

运行时异常: 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常): 是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

2、四个选项都来自于Java API原文.

A选项是RuntimeException的定义;

B选项是把Error的第二段定义拿来改掉换成RuntimeException,但这样说对于RuntimeException也没错;

C选项也是把Error的定义换成了RuntimeException,但这里的"indicates serious problems"不应该用在RuntimeException上,Error才表示严重的错误,RuntimeException并不是.

D选项显然.

71、 答案:B

类 ABC 定义如下:

1 . public class ABC{

2 . public int max( int a, int b) { }

3 .

4 . }

将以下哪个方法插入行 3 是不合法的。( )。

A、public float max(float a, float b, float c){ }
B、public int max (int c, int d){ }
C、public float max(float a, float b){ }
D、private int max(int a, int b, int c){ }
解析:选B,

细说一下重写和重载:

这两个都是多态的一种表现形式。

重载:

1、 重载是在编译器通过方法中形参的静态类型确定调用方法版本的过程。

2、 重载是多态在编译期的表现形式

3、 重载的判定只有两个条件(其他的条件都不能作为判定):

1、 方法名一致

2、形参列表不同

重写:

1、重写在方法运行时,通过调用者的实际类型来确定调用的方法版本。(具体细说,就是子父类中的重写方法在对应的class文件常量池的位置相同,一旦子类没有重写,那么子类的实例就会沿着这个位置往上找,直到找到父类的同名方法**)**

2、重写只发生在可见的实例方法中:

1、静态方法不存在重写,形式上的重写只能说是隐藏。

2、私有方法也不存在重写,父类中private的方法,子类中就算定义了,就是相当于一个新的方法。

3、静态方法和实例方法不存在相互重写。

3、重写满足一个规则:两同两小一大

1、两同:方法名和形参列表一致

2、两小:重写方法的返回值(引用类型)和抛出异常,要和被重写方法的返回值(引用类型)和抛出异常****相同或者是其子类。注意,一旦返回值是基本数据类型,那么重写方法和被重写方法必须相同,且不存在自动拆装箱的问题。

3、一大:重写方法的访问修饰符大于等于被重写方法的访问修饰符。

72、下列哪些语句关于内存回收的说明是正确的? ( ) 答案:B

A、程序员必须创建一个线程来释放内存
B、内存回收程序负责释放无用内存
C、内存回收程序允许程序员直接释放内存
D、内存回收程序可以在指定的时间释放内存对象
解析:A、JVM一旦启动,就会创建一个守护线程来监测是否需要有对象内存被释放。

C、无法直接释放。

D、不可以指定时间,System.gc(),只是提醒JVM可以进行一次Full GC,但是什么时候真正执行,还是不知道的。

img

73、instanceof运算符能够用来判断一个对象是否为: 答案:C

A、一个类的实例
B、一个类的实例
C、全部正确
D、一个子类的实例
解析:instance是java的二元运算符,用来判断他左边的对象是否为右面类(接口,抽象类,父类)的实例

74、以下程序的输出结果是 答案:A
public class Print{
    static boolean out(char c){
        System.out.print(c);
        return true;
    }
    public static void main(String[] argv){
        int i = 0;
        for(out('A');out('B') && (i<2);out('C')){
            i++;
            out('D');
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

A、ABDCBDCB
B、BCDABCD
C、编译错误
D、运行错误
解析:答案选A 解释:这道题考for循环执行顺序 参看 http://jingyan.baidu.com/article/7f766dafaa6ee04101e1d0e6.html

for循环的执行顺序用如下表达式:

for(expression1;expression2;expression3){

expression4;

}

执行的顺序应该是:

1)第一次循环,即初始化循环。

首先执行表达式expression1(一般为初始化语句);再执行expression2(一般为条件判断语句),判断expression1是否符合expression2的条件;如果符合,则执行expression4,否则,停止执行;最后执行expression3。

2)第N(N>=2)次循环

首先执行expression2,判断在expression3是否符合在expression2要求;如果符合,则继续执行在expression4,否则,停止执行。最后执行在expression3。如此往复,直至expression3不满足在expression2条件是为止。

总结:

总的来说,执行的顺序是一致的。先条件判断(expression2),再函数体执行(expression4),最后for执行(expression3)。往复…区别在于,条件判断的对象。第一次判断时,对象为初始化语句(expression1),后续的判断对象为执行后的结果(expression3)。

75、下列哪个说法是正确的() 答案:D

A、ConcurrentHashMap使用synchronized关键字保证线程安全
B、HashMap实现了Collction接口
C、Array.asList方法返回java.util.ArrayList对象
D、SimpleDateFormat是线程不安全的
解析:

A选项中,ConcurrentHashMap 使用segment来分段和管理锁,segment继承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock来保证线程安全。

B中,HashMap定义规则如下:

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
  • 1
  • 2
  • 3

C中,应该是Arrays.asList(),其将一个数组转化为一个List对象,这个方***返回一个ArrayList类型的对象, 这个ArrayList类并非java.util.ArrayList类,而是Arrays类的内部类:

图片说明

2、A. JDK1.8 的 ConcurrentHashMap 采用CAS+Synchronized保证线程安全。 JDK1.7 及以前采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock,因此采用Lock锁来保证线程安全。

B. img

C. Arrays.asList() 返回 java.util.Arrays.ArrayList 对象,这里的 ArrayList 是 Arrays 私有的内部类

D. img

76、Java Application 源程序的主类是指包含有( )方法的类。 答案:

A、public static void main方法
B、toString方法
C、init方法
D、actionPerfromed方法
解析:java程序种类:

1.内嵌于web文件中,有浏览器观看的applet

2.可独立运行的application

3.服务器端的servlets

77、在 applet 的方法中 , 可关闭小应用程序并释放其占用资源的是( ) 答案:D

A、stop()
B、paint()
C、init()
D、destroy()
解析: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() 方法就是输出字符串。

78、下列说法正确的是( ) 答案:C

A、volatile,synchronized 都可以修改变量,方法以及代码块
B、volatile,synchronized 在多线程中都会存在阻塞问题
C、volatile能保证数据的可见性,但不能完全保证数据的原子性,synchronized即保证了数据的可见性也保证了原子性
D、volatile解决的是变量在多个线程之间的可见性、原子性,而sychroized解决的是多个线程之间访问资源的同步性
解析:synchronized关键字和volatile关键字比较:

  • volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。

  • 多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞

  • volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。

  • volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。

    2、synchronized: 具有原子性,有序性和可见性;(三个都有)
    volatile:具有有序性和可见性(缺一个原子性)

79、下面程序的输出是什么? 答案:B
public class TestDemo
{
    public static String output = "";
    public static void foo(inti)
    {
        try
        {
            if (i == 1)
            {
                throw new Exception();
            }
        }
        catch (Exception e)
        {
            output += "2";
            return ;
        } finally
        {
            output += "3";
        }
        output += "4";
    }
    public static void main(String[] args)
    {
        foo(0);
        foo(1);
        System.out.println(output);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

A、342
B、3423
C、34234
D、323
解析:首先是foo(0),在try代码块中未抛出异常,finally是无论是否抛出异常必定执行的语句,

所以 output += “3”;然后是 output += “4”;

执行foo(1)的时候,try代码块抛出异常,进入catch代码块,output += “2”;

前面说过finally是必执行的,即使return也会执行output += “3”

由于catch代码块中有return语句,最后一个output += “4”不会执行。

所以结果是3423

2、try-catch-finally块中,finally块在以下几种情况将不会执行。

(1)finally块中发生了异常。

(2)程序所在线程死亡。

(3)在前面的代码中用了System.exit();

(4)关闭了CPU

80、如何获取ServletContext设置的参数值? 答案:B

A、context.getParameter()
B、context.getInitParameter()
C、context.getAttribute()
D、context.getRequestDispatcher()
解析:getParameter()是获取POST/GET传递的参数值;
getInitParameter获取Tomcat的server.xml中设置Context的初始化参数

getAttribute()是获取对象容器中的数据值;
getRequestDispatcher是请求转发。

81、现有一变量声明为 boolean aa; 下面赋值语句中正确的是 ( ) 答案:A

A、aa=false;
B、aa=False;
C、aa=“true”;
D、aa=0;
解析:

img

82、执行下列程序的输出结果为( ) 答案:D
public class Test {
    public static void main(String[] args) {
         String s1 = "HelloWorld";
         String s2 = new String("HelloWorld");
         if (s1 == s2) {
             System.out.println("s1 == s2");
         } else {
             System.out.println("s1 != s2");
         }
         if (s1.equals(s2)) {
             System.out.println("s1 equals s2");
         } else {
             System.out.println("s1 not equals s2");
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

A、

s1 == s2
s1 not equals s2
  • 1
  • 2

B、

s1 == s2
s1 equals s2
  • 1
  • 2

C、

s1 != s2
s1 not equals s2
  • 1
  • 2

D、

s1 != s2
s1 equals s2
  • 1
  • 2

解析:1.== 和 equals():

(1)“==” 用于比较基本数据类型时比较的是值,用于比较引用类型时比较的是引用指向的地址。

(2)Object 中的equals() 与 “==” 的作用相同,但String类重写了equals()方法,比较的是对象中的内容。

public boolean equals(Object anObject) {  if (this == anObject) {
          return true;    } else {  if (anObject instanceof String) {
            String aString = (String)anObject;
       if (this.coder() == aString.coder()) {  return this.isLatin1() ? StringLatin1.equals(this.value, aString.value) : StringUTF16.equals(this.value, aString.value); 
       }
      } return false;    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
83、在一个基于分布式的游戏服务器系统中,不同的服务器之间,哪种通信方式是不可行的()? 答案:A

A、管道
B、消息队列
C、高速缓存数据库
D、套接字
解析:对于管道,有下面这几种类型:

①普通管道(PIPE):通常有两种限制,一是单工,即只能单向传输;二是血缘,即常用于父子进程间(或有血缘关系的进程间)。

②流管道(s_pipe):去除了上述的第一种限制,实现了双向传输。

③命名管道(name_pipe):去除了上述的第二种限制,实现了无血缘关系的不同进程间通信。

*显然,要求是对于不同的服务器之间的通信,是要要求全双工形式的,而管道只能是半双工**,虽然可以双向,*但是同一时间只能有一个方向传输,全双工和半双工的区别可以如下图示理解:

img

84、关于中间件特点的描述.不正确的是() 答案:A

A、中间件运行于客户机/服务器的操作系统内核中,提高内核运行效率
B、中间件应支持标准的协议和接口
C、中间件可运行于多种硬件和操作系统平台上
D、跨越网络,硬件,操作系统平台的应用或服务可通过中间件透明交互
解析:

中间件是一种独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源。中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯。是连接两个独立应用程序或独立系统的软件。相连接的系统,即使它们具有不同的接口,但通过中间件相互之间仍能交换信息。执行中间件的一个关键途径是信息传递。通过中间件,应用程序可以工作于多平台或OS环境。

85、下面有关java classloader说法正确的是()? 答案:A C D

A、ClassLoader就是用来动态加载class文件到内存当中用的
B、JVM在判定两个class是否相同时,只用判断类名相同即可,和类加载器无关
C、ClassLoader使用的是双亲委托模型来搜索类的
D、Java默认提供的三个ClassLoader是Boostrap ClassLoader,Extension ClassLoader,App ClassLoader
解析:JDK中提供了三个ClassLoader,根据层级从高到低为:

  1. Bootstrap ClassLoader,主要加载JVM自身工作需要的类。
  2. Extension ClassLoader,主要加载%JAVA_HOME%\lib\ext目录下的库类。
  3. Application ClassLoader,主要加载Classpath指定的库类,一般情况下这是程序中的默认类加载器,也是ClassLoader.getSystemClassLoader() 的返回值。(这里的Classpath默认指的是环境变量中配置的Classpath,但是可以在执行Java命令的时候使用-cp 参数来修改当前程序使用的Classpath)

JVM加载类的实现方式,我们称为 双亲委托模型

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

双亲委托模型的重要用途是为了解决类载入过程中的安全性问题。

假设有一个开发者自己编写了一个名为***Java.lang.Object*的类,想借此欺骗JVM。现在他要使用自定义ClassLoader来加载自己编写的java.lang.Object*类。然而幸运的是,双亲委托模型不会让他成功。因为JVM会优先在Bootstrap ClassLoader的路径下找到**java.lang.Object***类,并载入它

86、给出以下代码 答案:B
public class TestObj{
    public static void main(String[] args){
        Object o=new Object(){
            public boolean equals(Object obj){
                return true;
            }
        };
        System.out.println(o.equals("Fred"));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

A、运行时抛出异常
B、true
C、Fred
D、第三行编译错误
解析:本题涉及匿名内部类、多态和覆盖三个知识点。 语句

Object o=new Object(){
            public boolean equals(Object obj){
                return true;
            }
        };
  • 1
  • 2
  • 3
  • 4
  • 5

创建了一个匿名内部类,并将所创建的匿名对象赋给 Object (多态:子类对象赋给超类引用)。同时,该匿名内部类重写了 Object 类的 equals 方法。

在执行语句

o.equals(“Fred”)
  • 1

时,根据多态及覆盖原则,会调用匿名内部类重写后的 equals 方法。

关于 “Java 内部类 ” 和 “Java 继承、多态与类的复用” 的更详细的阐述,请查看我的两篇博文 “http://blog.csdn.net/justloveyou_/article/details/53245561” 和 “http://blog.csdn.net/justloveyou_/article/details/52798666”。

87、下面有关java基本类型的默认值和取值范围,说法错误的是? 答案:C

A、字节型的类型默认值是0,取值范围是-27—27-1
B、boolean类型默认值是false,取值范围是true\false
C、字符型类型默认是0,取值范围是-2^15 —2^15-1
D、long类型默认是0,取值范围是-263—263-1
解析:

  1. 默认值 取值范围 示例

字节型 : 0 -27—-27-1 byte b=10;

字符型 : ‘ \u0000′ 0—-2^16-1 char c=’c’ ;

short : 0 -215—-215-1 short s=10;

int : 0 -231—-231-1 int i=10;

long : 0 -263—-263-1 long o=10L;

float : 0.0f -231—-231-1 float f=10.0F

double : 0.0d -263—-263-1 double d=10.0;

boolean: false true\false boolean flag=true;

默认值存储需求(字节)取值范围示例
byte01-27—27-1byte b=10;
char‘ \u0000′20—2^16-1char c=’c’ ;
short02-215—215-1short s=10;
int04-231—231-1int i=10;
long08-263—263-1long o=10L;
float0.0f4-231—231-1float f=10.0F
double0.0d8-263—263-1double d=10.0;
booleanfalse1true\falseboolean flag=true;
88、访问权限控制从最大权限到最小权限依次为:public、 包访问权限、protected和private 。( ) 答案:B

A、正确
B、错误
解析:应该是:public>protected>默认(包访问权限)>private,因为protected除了可以被同一包访问,还可以被包外的子类所访问

img

89、关于访问权限说法正确 的是 ? ( ) 答案:B

A、外部类前面可以修饰public,protected和private
B、成员内部类前面可以修饰public,protected和private
C、局部内部类前面可以修饰public,protected和private
D、以上说法都不正确
解析:

privatedefaultprotectedpublic
同一个类中
同一个包中
子类中
全局范围内

( 1 )对于外部类而言,它也可以使用访问控制符修饰,但外部类只能有两种访问控制级别: public 和默认。因为外部类没有处于任何类的内部,也就没有其所在类的内部、所在类的子类两个范围,因此 private 和 protected 访问控制符对外部类没有意义。

( 2 )内部类的上一级程序单元是外部类,它具有 4 个作用域:同一个类( private )、同一个包( protected )和任何位置( public )。

( 3 ) 因为局部成员的作用域是所在方法,其他程序单元永远不可能访问另一个方法中的局部变量,所以所有的局部成员都不能使用访问控制修饰符修饰。

90、下列说法正确的有( ) 答案:A C D

A、构造方法的方法名必须与类名相同
B、构造方法也没有返回值,但可以定义为void
C、在子类构造方法中调用父类的构造方法,super() 必须写在子类构造方法的第一行,否则编译不通过
D、一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个默认的构造方法,这个构造方法不执行任何代码
解析:关于B选项:Java:语法要求的构造函数只能那么写。如果写成public void 类名(){} 这种格式的话。此时就相当与你重新定义了一个函数,不能起到构造函数的作用,调用这个类的时候不能自动执行构造函数里的代码。

91、若有下列定义,下列哪个表达式返回false? 答案:
String s = "hello";
String t = "hello";
char c[] = {'h', 'e', 'l', 'l', 'o'} ;
  • 1
  • 2
  • 3

A、s.equals(t);
B、t.equals©;
C、s==t;
D、t.equals(new String(“hello”));
解析:Java又不是C++,什么时候字符数组等于字符串了(对这句话我不负责任)?

而常量池中的字符串,只有变量名不同是可以用双等号判断是否相等的,内存都是常量池中的字符串。

但是new出来的字符串,只能用equals,用双等号是不相等的,因为是两个内存对象。

public class HelloWorld {
    public static void main(String []args) {
        String s = "hello";
        String t = "hello";
        char c[] = {'h','e','l','l','o'} ;
        System.out.println(s.equals(t));
        //c++中定义的东西,不要在java中混为一谈。(对这句话我不负责任)
        System.out.println(t.equals(c));
        System.out.println(s==t);
        System.out.println(t.equals(new String("hello")));
        //这个不相等,因为语句中new的字符串不在常量池,是在堆
        System.out.println(t==new String("hello"));
        //这样可以判断字符数组与字符串是否包含同样的字符序列
        System.out.println(t.equals(new String(c)));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
92、关于protected 修饰的成员变量,以下说法正确的是 答案:A

A、可以被该类自身、与它在同一个包中的其它类、在其它包中的该类的子类所访问
B、只能被该类本身和该类的所有的子类访问
C、只能被该类自身所访问
D、只能被同一个包中的类访问
解析:java中有四大修饰符,分别为private,default,protected,public,下面主要是四者之间的区别:
- private(私有的)
private可以修饰成员变量,成员方法,构造方法,不能修饰类(此刻指的是外部类,内部类不加以考虑)。被private修饰的成员只能在其修饰的本类中访问,在其他类中不能调用,但是被private修饰的成员可以通过set和get方法向外界提供访问方式
- default(默认的)
defalut即不写任何关键字,它可以修饰类,成员变量,成员方法,构造方法。被默认权限修饰后,其只能被本类以及同包下的其他类访问。
- protected(受保护的)
protected可以修饰成员变量,成员方法,构造方法,但不能修饰类(此处指的是外部类,内部类不加以考虑)。被protected修饰后,只能被同包下的其他类访问。如果不同包下的类要访问被protected修饰的成员,这个类必须是其子类。
- public(公共的)
public是权限最大的修饰符,他可以修饰类,成员变量,成员方法,构造方法。被public修饰后,可以再任何一个类中,不管同不同包,任意使用。
public protected default private
同一个类 √ √ √ √
同一个包 √ √ √
子类 √ √
不同包 √
img

93、下列说法正确的是() 答案:C

A、WebLogic中开发消息Bean的non-persistent 方式可以保证消息的可靠
B、EJB容器发生错误,non-persistent方式下JMS容器仍然会将消息发送
C、EJB容器发生错误,persistent方式下JMS容器仍然会将消息发送
D、EJB容器发生错误,两种方式下JMS容器仍会在MDB可用的时候将消息发送
解析:weblogic中开发消息Bean时的persistent与non-persisten的差别:

  • persistent方式的MDB可以保证消息传递的可靠性,也就是如果EJB容器出现问题而JMS服务器依然会将消息在此MDB可用的时候发送过来。
  • non-persistent方式的消息将被丢弃
94、以下代码运行输出的是 答案:C
public class Person{
    private String name = "Person";
    int age=0;
}
public class Child extends Person{
    public String grade;
    public static void main(String[] args){
        Person p = new Child();
        System.out.println(p.name);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A、输出:Person
B、没有输出
C、编译出错
D、运行出错
解析:Java中对字段属性是静态绑定,方法成员是动态绑定,这里错在:在子类中试图访问父类的private字段,所以编译不通过,将private去掉就可访问,不是动态绑定的问题,它本来就属于静态绑定。

2、
1.一个java文件里,public 的类只能出现一个,只能出现一个,只能出现一个,否则,不管你用哪一个类名命名文件名编译器都会报错

2.关于多态。子类继承了父类的所有成员,包括private权限的成员变量,但是继承的子类具有私有变量的拥有权但是没有使用权。

3.private的成员变量,根据权限修饰符的访问控制范围,只有在类内部才能被访问,就算是他的子类,也不能访问。

95、以下哪些语言是面向对象的是() 答案:B C

A、C
B、C++
C、JAVA
D、汇编
解析:c是面向过程,c++面向对象,JAVA面向对象,汇编是面向机器

96、类 ABC 定义如下 答案:B

1 . public class ABC{

2 . public double max( double a, double b) { }

3 .

4 . }

将以下哪个方法插入行 3 是不合法的。()

A、public float max(float a, float b, float c){ return a }
B、public double max (double c, double d){ return c }
C、public float max(float a, float b){ return a }
D、private int max(int a, int b, int c){return a }
解析:重载要求方法的参数列表需要不一样(个数,或者参数类型),修改参数名或者修改返回值以及访问权限并没有用
img

97、通过HttpServletRequest. getParameter获取的参数. 答案:C

A、总是采用UTF-8编码
B、总是采用lS08859-1编码
C、由客户端浏览器和Web容器配置共同决定编码
D、由服务器所在的操作系统决定编码
解析:编码格式由浏览器决定,浏览器根据html中指定的编码格式进行编码,tomcat根据指定的格式进行解码,另外get请求和post请求对编码格式的处理也是不同的
2、选C

1、浏览器根据jsp页面开头声明的编码方式对request中参数编码;

2、tomcat默认解码是ISO-8859-1, 但是我们可以显示指定解码格式通过调用 request.setCharacterEncoding(“UTF-8”),或者修改tomcat的配置文件server.xml中的编码,添加uriEncoding属性。

98、Math.floor(-8.5)=( ) 答案:D

A、(float)-8.0
B、(long)-9
C、(long)-8
D、(double)-9.0
解析:D Math.floor(x) 返回小于等于x的最接近整数,类型为double

99、ava中Hashtable, Vector, TreeSet, LinkedList哪些线程是安全的? 答案: A B

A、Hashtable
B、Vector
C、TreeSet
D、LinkedList
解析:线程安全概念:

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量静态变量引起的。

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

img

LinkedList 和 ArrayList 都是不同步的,线程不安全;
Vector 和 Stack 都是同步的,线程安全;
Set是线程不安全的;

Hashtable的方法是同步的,线程安全;
HashMap的方法不是同步的,线程不安全;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

简单记忆线程安全的集合类: 喂! SHE 喂是指 vector S 是指 stack H 是指 hashtable E 是指: Eenumeration

100、下述有关c++的虚类和java接口的描述,说法错误的是? 答案:C D

A、c++虚类相当与java里面的抽象类
B、c++中没有接口的概念,与之对应的是纯虚类,对应的是java的接口
C、纯虚函数和虚函数的区别在于前者只包含定义,而后者还可以包含函数体。
D、一个抽象类和接口中的方法必须是抽象方法
解析:

1、一个子类只能继承一个抽象类(虚类),但能实现多个接口;
2、一个抽象类可以有构造方法,接口没有构造方法;
3、一个抽象类中的方法不一定是抽象方法,即其中的方法可以有实现(有方法体),接口中的方法都是抽象方法,不能有方法体,只有声明;
4、一个抽象类可以是public、private、protected、default,
   接口只有public;
5、一个抽象类中的方法可以是public、private、protected、default,
   接口中的方法只能是public和default
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
101、设int x=1,float y=2,则表达式x/y的值是:() 答案:D

A、0
B、1
C、2
D、以上都不是
解析:本题的意义在于两点,明白这两点之后题会不会本身就不重要了:①float x = 1;与float x = 1.0f,这两种对于float类型的变量来说定义的方式都是正确的,也是比较常见的笔试题里面考察类型转换的例子,当第一种情况时,是将低精度int向上转型到float,是由于java的特性导致而不需要进行强制转换,而第二种情况则是比较正式的对于float变量的定义,由于这种类型本身在工作项目中并不常见,常用的带小数的数字我们一般都直接使用double类型,而double类型直接定义是没有问题的:double x = 1.0。而由于float的精度没有double类型高,因此必须对其进行显示的格式书写,如果没有这个f,就默认是double类型了。当然double x = 1.0d也是正确的命名,不信你可以尝试,虽然这是一个令人窒息的操作。②当多个精度的数字同时进行运算时,最终结果以最高精度为准。在多数情况下,整数和小数的各级混合运算中,一般结果都是double类型的。但就本题而言,结果是float类型的,因为x,y两个数字精度最高的就是float,所以最终结果是0.5,并且这个0.5是float类型的。为什么说不是double类型呢,当然如果你这样处理:double m = x/y,当然m是double类型的,也不会报错,而如果你写成int m = x/y,编译器报错提示的时候就会让你转换成float或者进行强制转换成int,他是不会提示你转换成double的,尽管这么写并没有报错,原因就是①

中所说的向上强转。float转换成double不需要任何提示。

102、定义有StringBuffer s1=new StringBuffer(10);s1.append(“1234”),则s1.length()和s1.capacity()分别是多少? 答案:A

A、4 10
B、4 4
C、10 10
D、10 4
解析:length 返回当前长度

如果字符串长度没有初始化长度大,capacity返回初始化的长度

如果append后的字符串长度超过初始化长度,capacity返回增长后的长度

103、若需要定义一个类,下列哪些修饰符是允许被使用的?( ) 答案:A C D

A、static
B、package
C、private
D、public
解析:这题只说定义一个类,但是没有说这个类是普通外部类或者内部类。

因为**普通类也就是外部类,**通过 eclipse 的警告“Illegal modifier for the class Test; only public, abstract & final are permitted” 可知只能用 public, abstract 和 final 修饰。

内部类则可以用 **修饰成员变量的修饰符修饰内部类,**比如 private, static, protected 修饰。

2、

104、下面哪些类实现或继承了 Collection 接口? 答案:B C

A、HashMap
B、ArrayList
C、Vector
D、Iterator
解析:

img

105、character流和byte流的的说法错误的是 答案:A B D

A、每次读入的字节数不同
B、前者带有缓冲,后者没有。
C、前者是字符读入,后者是字节读入。
D、二者没有区别,可以互换。
解析:字符流和字节流每次读入的字节数是不确定的,可能相同也可能不相同;字符流和字节流都有缓冲流
2、Java的流操作分为字节流和字符流两种。

字节流与字符流主要的区别是他们的处理方式

字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的。但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化

这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联。

在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的。
字节流---->字符流
字节流转化为字符流,实际上就是byte[]转化为String时,
public String(byte bytes[], String charsetName)
有一个关键的参数字符集编码,通常我们都省略了,那系统就用操作系统的lang
字符流---->字节流

字符流转化为字节流,实际上是String转化为byte[]时,byte[] String.getBytes(String charsetName)也是一样的道理至于java.io中还出现了许多其他的流,按主要是为了提高性能和使用方便,如BufferedInputStream,PipedInputStream等
  • 1

常识:

对于GBK编码标准,英文占用1个字节,中文占用2个字节
对于UTF-8编码标准,英文占用1个字节,中文占用3个字节
对于Unicode编码标准,英文中文都是2个字节。这也是为什么叫做unicode

106、cnt的值是 答案: A
public class Test1 {
 
    static int cnt = 6;
 
    static {
        cnt += 9;
    }
 
    public static void main(String[] args) {
        System.out.println("cnt =" + cnt);
    }
 
    static {
        cnt /= 3;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

A、cnt=5
B、cnt=2
C、cnt=3
D、cnt=6
解析:看了前面的解答,我想更正一下其中几位同学的解答。

如楼上有的同学说的,静态初始化块,静态变量这两个是属于同一级别的,是按代码写得顺序执行的!

而不是先执行静态变量后执行静态初始化块!这是错的。我举个例子:

public class Test{  static{  cnt = 6;
    }  static int cnt = 100;  public static void main(String[] args){
        System.out.println("cnt = " + cnt);
        //最后输出是50,如果按照错误说法就应该是3
        //按顺序执行就是cnt=6--->cnt=100---->cnt = 100/2 = 50.
    }  static{ cnt /= 2;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、(1)父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。

(2)子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。

(3)父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。

(4)执行父类构造方法。

(5)子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。

(6)执行子类构造方法。

107、在Java中,以下关于方法重载和方法重写描述正确的是? 答案:D

A、方法重载和方法的重写实现的功能相同
B、方法重载出现在父子关系中,方法重写是在同一类中
C、方法重载的返回值类型必须一致,参数项必须不同
D、方法重写的返回值类型必须相同或相容。(或是其子类)
解析:方法重载的返回值的类型可以不同,因为判断方法重载的方法主要是根据方法的参数不同来判定;方法重写的返回值类型需要相同,重写就是子类继承了父类的方法,并在此方法上重写属于自己的特征,既然是继承过来的,那么它的返回值类型就必须要相同
2、

public class TTTTT extends SuperC{
    public String get(){
        return null;
    }
}
class SuperC{
    Object get(){
        return null;
    }
}
方法重载(overload):
1.必须是同一个类
2方法名(也可以叫函数)一样
3参数类型不一样或参数数量不一样

方法的重写(override)两同两小一大原则:
方法名相同,参数类型相同
子类返回类型小于等于父类方法返回类型,
子类抛出异常小于等于父类方法抛出异常,
子类访问权限大于等于父类方法访问权限。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
108、Math.round(11.5) 等于多少 (). Math.round(-11.5) 等于多少 ( ). 答案:C

A、11 ,-11
B、11 ,-12
C、12 ,-11
D、12 ,-12
解析:floor : 意为地板,指向下取整,返回不大于它的最大整数 ceil : 意为天花板,指向上取整,返回不小于它的最小整数 round : 意为大约,表示“四舍五入”,而四舍五入是往大数方向入。Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11而不是-12。

109、实现或继承了Collection接口的是() 答案:B C E

A、Map
B、List
C、Vector
D、Iterator
E、Set
解析:

A,Map接口未实现Collection接口
B,List接口的定义为
public interface List<E>extends Collection<E>
C,Vector定义为
public class Vector<E>extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, Serializable
Vector实现了List接口自然实现了Collection接口

D,Iterator接口未实现Collection接口
E,
public interface Set<E>extends Collection<E>
Set接口继承自Collection接口
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
110、Hashtable 和 HashMap 的区别是: 答案:B C D E

A、Hashtable 是一个哈希表,该类继承了 AbstractMap,实现了 Map 接口
B、HashMap 是内部基于哈希表实现,该类继承AbstractMap,实现Map接口
C、Hashtable 线程安全的,而 HashMap 是线程不安全的
D、Properties 类 继承了 Hashtable 类,而 Hashtable 类则继承Dictionary 类
E、HashMap允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。
解析:选B、C、D、E。

Hashtable

(1)Hashtable 是一个散列表,它存储的内容是键值对(key-value)映射。

(2)Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。

(3)HashTable直接使用对象的hashCode。

HashMap:

(1)由数组+链表组成的,基于哈希表的Map实现,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。

(2)不是线程安全的,HashMap可以接受为null的键(key)和值(value)。

(3)HashMap重新计算hash

Hashtable,HashMap,Properties继承关系如下:

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable
 
public class HashMap<K,V>extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
java.lang.Objecct
  java.util.Dictionary<K,V>
    java.util.Hashtable<Object,Object>
      java.util.Properties 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
111、在上下文和头文件正常的情况下,代码将打印? 答案:B
System.out.println(10%3*2);
  • 1

A、1
B、2
C、4
D、6
解析:%和*是同一个优先级,从左到右运算

img

112、在 JAVA 编程中, Java 编译器会将 Java 程序转换为( ) 答案:A

A、字节码
B、可执行代码
C、机器代码
D、以上都不对
解析:
编译器将Java源代码编译成字节码class文件
类加载到JVM里面后,执行引擎把字节码转为可执行代码
执行的过程,再把可执行代码转为机器码,由底层的操作系统完成执行。

113、下列关于计算机系统和Java编程语言的说法,正确的是() 答案:C

A、计算机是由硬件、操作系统和软件组成,操作系统是缺一不可的组成部分。
B、Java语言编写的程序源代码可以不需要编译直接在硬件上运行。
C、在程序中书写注释不会影响程序的执行,可以在必要的地方多写一些注释。
D、Java的集成开发环境(IDE),如Eclipse,是开发Java语言必需的软件工具。
解析:裸机也可以跑,以前搞嵌入式的时候,并不一定要安装操作系统,直接操作寄存器就可以了,操作系统不是必须的
/2多写详细的注释,我认为是错的。大量详细的注释会导致系统后期难以维护。应该是良好的编码风格+清晰的变量定义+必要的注释。

114、以下 b 的值是: byte b = (byte)129; 答案:B

A、-126
B、-127
C、-128
D、-129
解析:答案是B。
因为byte是有符号单字节整形,所以存储数字范围是[-128·127]
而127[01111111]+1==128[10000000]。
为什么呢?
因为科学家定义数字的时候是一个环,最大的数字后面就是最小,这样才可以把[0·255]分配给[-128·127]。
底层就是补码的概念。
好,我们再从java程序上运行一次。

public class HelloWorld {
    public static void main(String []args) {
       byte b = (byte)129;
       byte c = (byte)128;
       System.out.println(b);
       System.out.println(c);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

都写的啥****,我来正解,上面没看到完全正确的,所以实在忍不了写出正确的解答

这题考察的就两个知识点:一、强制转换(主要涉及各个类型占几个字节,这里我只简单说一下byte型占一个字节,也就是8位,int型4个字节,32位);二、在计算机系统中,数值一律用补码来表示(存储)

正数:补码=反码=原码(当然以二进制形式表达)

129 int类型(4个字节)二进制: 00000000 00000000 00000000 10000001

强制转换byte型后,只有一个字节即 10000001(注意这里从二进制角度看,第一位是符号位,即求负数的补码接下来)

只要求出上面原码对应的补码就行了,然后再转换对应的int型数值(因为题干所给的答案都是比较int型)

10000001(原码) 对应的反码为1111 1110

又补码等于反码+1

即1111 1111 该二进制转换int型刚好是-127(1+2+4+8+16+32+64)

普及一下:正数原码,反码,补码相同

负数反码除了符号位不变,其他位取反,补码=反码+1;

之前那些解答都啥玩意,不会别误导大家,我的是正解,嘻嘻

115、JDK1.8版本之前,抽象类和接口的区别,以下说法错误的是 答案:D

A、接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的。
B、abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface,实现多重继承。接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。
C、在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是 static final的,不过在 interface中一般不定义数据成员),所有的成员方法默认都是 public abstract 类型的。
D、abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"has-a"关系,interface表示的是"is-a"关系。
解析:1)接口可以继承接口,而且可以继承多个接口,但是不能实现接口,因为接口中的方法全部是抽象的,无法实现;

另外,如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法

2)普通类可以实现接口,并且可以实现多个接口,但是只能继承一个类,这个类可以是抽象类也可以是普通类,如果继承抽象类,必须实现抽象类中的所有抽象方法,否则这个普通类必须设置为抽象类;

3)抽象类可以实现接口,可以继承具体类,可以继承抽象类,也可以继承有构造器的实体类。

抽象类中可以有静态main方法;抽象类里可以没有抽象方法,没有抽象方法的抽象类就是不想让别人实例化它;

另外,抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super(参数列表)调用抽象类中的构造方法,可以用于实例化抽象类的字段。

下面总结常见的抽象类与接口的区别:

1)抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象;

2)接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现(java8中 接口可以有实现方法 使用default修饰);

3)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;

4)抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类;

5)抽象方法要被实现,所以不能是静态static的,也不能是私有private的,也不能被final修饰(试想一下,静态方法可以被类名直接调用,而类名直接调用一个没有实现的抽象方法没有意义)。
2、is-a:继承关系 has-a:从属关系 like-a:组合关系

116、下面哪个选项是main方法的返回类型? 答案: B

A、int
B、void
C、Boolean
D、static
解析:Java中类的主方法定义如下

class Demo{
    public static void main(String args[]){
    //代码段
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
117、代码片段: 关于上面代码片段叙述正确的是() 答案:C
byte b1=1,b2=2,b3,b6; 
final byte b4=4,b5=6; 
b6=b4+b5; 
b3=(b1+b2); 
System.out.println(b3+b6);
  • 1
  • 2
  • 3
  • 4
  • 5

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类型。
2、表达式的数据类型自动提升, 关于类型的自动提升,注意下面的规则。

①所有的byte,short,char型的值将被提升为int型;

②如果有一个操作数是long型,计算结果是long型;

③如果有一个操作数是float型,计算结果是float型;

④如果有一个操作数是double型,计算结果是double型;

而声明为final的变量会被JVM优化,第6行相当于 b6 = 10

118、下列关于if-else if选择结构的说法正确的是 答案:B D

A、多个else if块之间的顺序可以改变,改变之后对程序的执行结果没有影响
B、多个else if块之间的顺序可以改变,改变之后可能对程序的执行结果有影响
C、多个else if块之间的顺序不可以改变,改变后程序编译不通过
D、多个else if块之间的顺序可以改变,改变后程序编译可以通过
解析:

int age = 11;
int a = 0;
if(age < 10){
    a += 1;
}else if(age < 15){
    a += 2;
}else if(age < 25){
    a += 3;
}上面的代码  两个ifelse如果互换位置   a的值就不一样了:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
119、java运行时内存分为“线程共享”和“线程私有”两部分,以下哪些属于“线程共享”部分 答案: B D

A、程序计算器
B、方法区
C、java虚拟机栈
D、java堆
解析:共享的资源有:

a. 堆 由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的)

b. 全局变量 它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的

c. 静态变量 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的

d. 文件等公用资源 这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。

独享的资源有

a. 栈 栈是独享的

b. 寄存器 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC

私有:java虚拟机栈,程序计数器,本地方法栈 共享:java堆,方法区
  • 1
120、Given the following code: 正确答案: A D
package cn.com.test;
 
public class EnclosingOne {
    public class InsideOne {}
 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
package cn.com.cow;
 
import cn.com.test.EnclosingOne;
import cn.com.test.EnclosingOne.InsideOne;
public class InerTest
{
    public static void main(String[]args)
    {
        EnclosingOne eo = new EnclosingOne();
        //insert code here 
    }
 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Which statement at line 10 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();
解析:

public class Enclosingone {
    //非静态内部类
    public class InsideOne {}
    //静态内部类
    public static class InsideTwo{}
}
 
class Mytest02{
    public static void main(String args []){
        Enclosingone.InsideOne obj1 = new Enclosingone().new InsideOne();//非静态内部类对象
        Enclosingone.InsideTwo obj2 = new Enclosingone.InsideTwo();//静态内部类对象
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2、对于A答案 主要在开头添加 import EnclosingOne.Insider这一句,不然的话A肯定是错误,其他类不能够直接引用内部类的

img

121、编译 Java 源程序文件产生的字节码文件的扩展名为() 答案:B

A、java
B、class
C、html
D、exe
解析:java源文件的后缀名是.java。源文件通过jvm虚拟机编译后会生成二进制字节码文件,后缀是.class

122、根据以下代码段,执行new Child(“John”, 10); 要使数据域data得到10,则子类空白处应该填写( )。 答案:D
class Parent {
    private int data;
    public Parent(int d){ data = d; }
}
class Child extends Parent{
    String name;
    public Child(String s, int d){
        ___________________
        name = s;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A、data = d;
B、super.data = d;
C、Parent(d);
D、super(d);
解析:1.子父类存在同名成员时,子类中默认访问子类的成员,可通过super指定访问父类的成员,格式:super.xx (注:xx是成员名);

2.创建子类对象时,默认会调用父类的无参构造方法,可通过super指定调用父类其他构造方法,格式:s uper(yy) (注:yy是父类构造方法需要传递的参数)
2:1.super可以访问父类中public、default、protected修饰的成员变量,不能访问private修饰的成员变量。格式为super.成员名称。

2.super可以访问父类中public、default、protected修饰的实例方法,不能访问private修饰的实例方法。格式为super.实例方法。

3.super可以访问父类中public、default、protected修饰的构造方法,不能访问private修饰的构造方法,格式为super(参数).

123、以下多线程对int型变量x的操作,哪个不需要进行同步() 答案:D

A、++x
B、x=y
C、x++
D、x=1
解析:同步是害怕在操作过程的时候被其他线程也进行读取操作,一旦是原子性的操作就不会发生这种情况。
因为一步到位的操作,其他线程不可能在中间干涉。另外三项都有读取、操作两个步骤,而X=1则是原子性操作。
2、前三个都至少需要先读取,再操作,非原子操作。而D的话,直接赋值。

124、下面有关java object默认的基本方法,说法错误的是? 答案:B

A、equals(Object obj) 指示某个其他对象是否与此对象“相等”
B、copy() 创建并返回此对象的一个副本
C、wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
D、toString() 返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成
解析:
Object里的方法如下所示,其中不包含copy方法img

125、以下各类中哪几个是线程安全的?( ) 答案:B C D

A、ArrayList
B、Vector
C、Hashtable
D、Stack
解析:在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:

vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。

statck:堆栈类,先进后出

hashtable:就比hashmap多了个线程安全

enumeration:枚举,相当于迭代器

除了这些之外,其他的都是非线程安全的类和接口。
2、线程同步:喂,SHE

喂(Vector)

S(Stack)

H(hashtable)

E(enumeration)
img

126、下面语句正确的是() 答案:D

A、x+1=5
B、i++=1
C、a++b=1
D、x+=1
解析:总结一下: 1-首先赋值运算符“=”右值可以是任何常数、变量或者表达式(只要能生成一个值就行)。但左值必须是一个明确的、已命名的变量。 2-常用的双元运算符:+=,-=,*=,/= 解析: A:x+1=5,赋值运算符左边是表达式,不对; B:i++=1,从左到右运算是i=i+1=1,赋值运算符左边是表达式,错误; C:a++b=1,赋值运算符左边为表达式,错误。 D:x+=1,既x=x+1,正确。 注意背一下各个运算符的先后顺序。

127、Which of the following statements are valid array declaration? 答案:

(A) int number();
(B) float average[];
© double[] marks;
(D) counter int[];

A、(B) & ©
B、(A)
C、(A) & ©
D、(D)
解析:java里面有两种数组声明方式
2/invalid 无效的 valid 有效的
可能大家错误都犯在这里

128、以下代码输出的是: 答案:A
public class SendValue{
    public String str="6";
    public static void main(String[] args) {
        SendValue sv=new SendValue();
        sv.change(sv.str);
        System.out.println(sv.str);
    }
    public void change(String str) {
        str="10";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A、6
B、10
C、都不对
D、16
解析:补充Java内存管理知识:

1. 内存分配策略

按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的。

静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间。这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求。

栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的。和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存。和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。

静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。

2. JVM中的堆和栈

JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈,也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

java把内存分两种:一种是栈内存,另一种是堆内存

栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

栈(stack):是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量。

堆(heap):是一个可动态申请的内存空间(其记录空闲内存空间的链表由操作系统维护),是一个运行时数据区,C中的malloc语句所产生的内存空间就在堆中。

3. 堆和栈优缺点比较

栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

4. Java中的数据类型有两种

一种是基本类型

共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。

这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

另外,**栈有一个很重要的特殊性,就是存在栈中的数据可以共享。**假设我们同时定义:

int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。

特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

另一种是包装类数据

如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。

String是一个特殊的包装类数据。即可以用String str = new String(“abc”);的形式来创建,也可以用String str = “abc”;的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = “abc”;中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。

5.String在内存中的存放

String是一个特殊的包装类数据,可以用用以下两种方式创建:

String str = new String(“abc”);第一种创建方式是用new()来新建对象的,它会存放于堆中。每调用一次就会创建一个新的对象。

String str = “abc”; 第二种创建方式先在栈中创建一个对String类的对象引用变量str,然后在栈中查找有没有存放值为”abc”的地址,如果没有,则开辟一个存放字面值为”abc”的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为”abc”的地址,则查找对象o,并返回o的地址,最后将str指向对象o的地址。

值得注意的是,一般String类中字符串值都是直接存值的。但像String str = “abc”;这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!

6.数组在内存中的存放

int x[] 或者int []x 时,在内存栈空间中创建一个数组引用,通过该数组名来引用数组。

x = new int[5] 将在堆内存中分配5个保存int型数据的空间,堆内存的首地址放到栈内存中,每个数组元素被初始化为0。

7.static变量在内存中的存放

用 static的修饰的变量和方法,实际上是指定了这些变量和方法在内存中的“固定位置”-static storage。既然要有“固定位置”那么他们的 “大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在栈中或堆中开辟空间那就是非常的方便了。如果静态的变量或方法在不出其作用域的情况下,其引用句柄是不会发生改变的。

8. java中变量在内存中的分配

1、类变量(static修饰的变量)

在程序加载时系统就为它在堆中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期一直持续到整个”系统”关闭

2、实例变量

当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量(比如说类实例),然后根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”。 实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

3、局部变量

局部变量,由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放

129、执行以下程序,最终输出可能是: *代表空格 答案:C

img

A、010 2123012 3434
B、01201 340124 2334
C、0012314 01223344**
D、12345 12345 12345
解析:每个线程输出0,1,2,3,4,’空格, 输出空格前必有线程输出了0-4,所以选C、

130、 答案:A C D G

class A {}
class B extends A {}
class C extends A {}

class D extends B {}

下面的哪4个语句是正确的?

A、The type Listis assignable to List.
B、The type Listis assignable to List.
C、The type Listis assignable to List<?>.
D、The type Listis assignable to List<?extends B>.
E、The type List<?extends A>is assignable to List.
F、The type Listis assignable to any List reference.
G、The type List<?extends B>is assignable to List<?extends A>.
解析:耐心看完,保证能懂这道题!

**1. 只看尖括号里边的!!明确点和范围两个概念**2. 如果尖括号里的是一个类,那么尖括号里的就是一个点,比如List,List,List**3. 如果尖括号里面带有问号,那么代表一个范围,<? extends A> 代表小于等于A的范围,<? super A>代表大于等于A的范围,<?>代表全部范围4. 尖括号里的所有点之间互相赋值都是错,除非是俩相同的点5. 尖括号小范围赋值给大范围,对,大范围赋值给小范围,错。如果某点包含在某个范围里,那么可以赋值,否则,不能赋值6. List<?>和List 是相等的,都代表最大范围----------------------------------------------------------------------------------7.补充:List既是点也是范围,当表示范围时,表示最大范围

public static void main(String[] args) {
        List<A> a;
        List list;
        list = a;   //A对,因为List就是List<?>,代表最大的范围,A只是其中的一个点,肯定被包含在内
        List<B> b;
        a = b;      //B错,点之间不能相互赋值
        List<?> qm;
        List<Object> o;
        qm = o;     //C对,List<?>代表最大的范围,List<Object>只是一个点,肯定被包含在内
        List<D> d;
        List<? extends B> downB;
        downB = d;  //D对,List<? extends B>代表小于等于B的范围,List<D>是一个点,在其中
        List<?extends A> downA;
        a = downA;  //E错,范围不能赋值给点
        a = o;      //F错,List<Object>只是一个点
        downA = downB;  //G对,小于等于A的范围包含小于等于B的范围,因为B本来就比A小,B时A的子类嘛
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
131、下列代码的执行结果是() 答案:B
public class Test {
    public static int a = 1;
    public static void main(String[] args) {
        int a = 10;
        a++; Test.a++;
        Test t=new Test();
        System.out.println("a=" + a + " t.a=" + t.a);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

A、a=10 t.a=3
B、a=11 t.a=2
C、a=12 t.a=1
D、a=11 t.a=1
解析:静态成员变量未被final时,它的值可以被更改;所以t.a = 2;
2、值为1的a属于类变量也叫作成员变量,值为10的a是局部变量 首先a++时就近原则,用局部变量10来加,Text.a直接用类名调用成员变量的情况,只能是static 修饰的成员变量1来加,然后又实例化了对象,在输出中第一个a= 用就近原则输出11,第二个t.a 对象只能调用类变量输出2

132、关于Float,下列说法错误的是() 答案:C

A、Float是一个类
B、Float在java.lang包中
C、Float a=1.0是正确的赋值方法
D、Float a= new Float(1.0)是正确的赋值方法
解析:
Float是类,float不是类.
查看JDK源码就可以发现Byte,Character,Short,Integer,Long,Float,Double,Boolean都在java.lang包中.
Float正确复制方式是Float f=1.0f,若不加f会被识别成double型,double无法向float隐式转换.
Float a= new Float(1.0)是正确的赋值方法,但是在1.5及以上版本引入自动装箱拆箱后,会提示这是不必要的装箱的警告,通常直接使用Float f=1.0f.
2、Float a = new Float(1.0); 这个的东西能存在,是因为Float类中有形参是float和double的两个构造器。

Double d = new Double(1.0F);这个能成立的原因是float向上转型了。

Float a = 1.0;这个东西不成立是因为浮点型的默认类型是double,而double不会自动转成float,然后再装箱。

Double d = 1.0f;不成立的原因是因为Double类中的装箱方法,只有valueOf(String s)和valueOf(double d);装箱本身可不会自动向上转型啊。

133、语句:char foo=‘中’,是否正确?(假设源文件以GB2312编码存储,并且以javac – encoding GB2312命令编译) 答案:A

A、正确
B、错误
解析:Java语言中,中文字符所占的字节数取决于字符的编码方式,一般情况下,采用ISO8859-1编码方式时,一个中文字符与一个英文字符一样只占1个字节;采用GB2312或GBK编码方式时,一个中文字符占2个字节;而采用UTF-8编码方式时,一个中文字符会占3个字节。

在C++中

在C++中,char是基础数据类型,8位,1个字节。byte不是基础数据类型,一般是typedef unsigned char byte;这样子的,也就是说,byte其实是unsigned char类型,那么也是8位,1个字节。不同的是,char可以表示的范围是-128-127,而byte可以表示的范围是0-255。

在Java中

在java中,char和byte都是基础数据类型,其中的byte和C++中的char类型是一样的,8位,1个字节,-128-127。但是,char类型,是16位,2个字节, ‘\u0000’-’\uFFFF’。

为什么java里的char是2个字节?

因为java内部都是用unicode的,所以java其实是支持中文变量名的,比如string 世界 = “我的世界”;这样的语句是可以通过的。

综上,java中采用GB2312或GBK编码方式时,一个中文字符占2个字节,而char是2个字节,所以是对的

134、下面对静态数据成员的描述中,正确的是 答案:A

A、静态数据成员可以在类体内进行初始化
B、静态数据成员不可以被类的对象调用
C、静态数据成员不受private控制符的作用
D、静态数据成员可以直接用类名调用
解析:D选项需要考虑在A类通过类名访问B类的静态成员变量时,B类的静态成员变量必须public修饰
2、答案应该是A,D很明显是错误的,最典型的就是单例模式。

事实上Java的设计原则是属性私有,接口公开,方法看情况,静态数据成员也不例外,枚举类型才公开,但枚举的也不能叫成员,是实例。

针对小哥的疑问,我就直接上图了。因为篇幅的原因,所以代码阅读性一般,见谅。

img

135、下面是java语言的基本特性是?() 答案:A B C

A、封装
B、多态
C、继承
D、高效
解析:封装 继承 多态 还有个抽象

136、下列程序执行后结果为( ) 答案: A
class A {
    public int func1(int a, int b) {
        return a - b;
    }
}
class B extends A {
    public int func1(int a, int b) {
        return a + b;
    }
}
public class ChildClass {
    public static void main(String[] args) {
    A a = new B();
    B b = new B();
    System.out.println("Result=" + a.func1(100, 50));
    System.out.println("Result=" + b.func1(100, 50));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

A、

Result=150
Result=150
  • 1
  • 2

B、

Result=100
Result=100
  • 1
  • 2

C、

Result=100
Result=150
  • 1
  • 2

D、

Result=150
Result=100
  • 1
  • 2

解析:

其实很简单,涉及转型的题目,分为向上或者向下转型。

关键的来了,不论向上或者向下转型,都是一句话,“编译看左边,运行看右边”。也就是编译时候,会看左边引用类型是否能正确编译通过,运行的时候是调用右边的对象的方法。

就本题来说,编译时候会发现左边满足条件所以编译通过,运行时候又会调用右边也就是 class B 的方法,所以答案都是150。
2、此题考查的是多态。

对于多态,可以总结它为:

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

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

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

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

多态的3个必要条件:

​ 1.继承 2.重写 3.父类引用指向子类对象。

向上转型: Person p = new Man() ; //向上转型不需要强制类型转化

向下转型: Man man = (Man)new Person() ; //必须强制类型转化

137、用户不能调用构造方法,只能通过new关键字自动调用。() 答案: B

A、正确
B、错误
解析:在类内部可以用户可以使用关键字this.构造方法名()调用(参数决定调用的是本类对应的构造方法)
在子类中用户可以通过关键字super.父类构造方法名()调用(参数决定调用的是父类对应的构造方法。)
反射机制对于任意一个类,都能够知道这个类的所有属性和方法,包括类的构造方法。
2、1. 在类的其他构造方法中可以用this()的方式调用其他构造方法;

  1. 在类的子类中则可以通过super调用父类中指定的构造方法;
  2. 在反射中可以使用newInstance()的方式调用。
138、对于Java中异常的描述正确的是( ) 答案: D

A、用throws定义了方法可能抛出的异常,那么调用此方法时一定会抛出此异常。
B、如果try块中没有抛出异常,finally块中的语句将不会被执行。
C、抛出异常意味着程序发生运行时错误,需要调试修改
D、Java中的非检测(unchecked)异常可能来自RuntimeException类或其子类。
解析:A错 在调用此方法的时候 也可以再次申明以将异常交由更高一级处理。
B错 finally块中的语句一定会被执行。除非catch块中有System.exit(0)
C错 抛出异常不一定是运行时异常,也有可能是编译时异常。
D对 运行时异常的特点是Java编译器不会检查它。
2、Exception(异常)
是程序本身可以处理的异常。主要包含RuntimeException等运行时异常和IOException,SQLException等非运行时异常。
运行时异常 包括:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常(编译异常) 包括:RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常

139、()运算符把其操作数中所有值为0和所有值为1的位分别在结果的相应中设置1和0 答案:D

A、&
B、|
C、!
D、~
解析:&与操作;

|或操作;

!非操作;

~取反操作;
2、~是位运算符,意义是 按位非(NOT)
按位非也叫做补,一元运算符NOT“~”是对其运算数的每一位取反。

  • 仅用于整数值
  • 反转位,即0位变为1位,1变成0
  • 在所有情况下〜x等于(-x)- 1

例如

  ~ 0111 (7) = 1000 (8)
  • 1
140、下面有关Java的说法正确的是( ) 答案:A C D F

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

解析:解释一下c选项,意思是父类中的protected方法子类在重写的时候访问权限可以修改,其实就是重写的要素之一,换了个说法而已
2、解释一下后两个,final 的成员方法除了能读取类的成员变量,还能读取类变量。(之前混淆了,给大家带来混乱,抱歉)

img

String 不可以修改,StringBuffer 和 StringBuilder 可以修改,String 只能改变指引,如果字符串常量池中没有正需要的串,就创建一 个新的字符串,然后让 String 对象指向它。

141、在委托事件模型中,源生成事件并把它发送给一个或多个监听器,每个监听器必须向事件源注册。 答案:A

A、T
B、F
解析:建议牛客取消关于图形化界面的题

142、一个类可以有多个不同名的构造函数 (不考虑内部类的情况)。( ) 答案:B

A、正确
B、错误
解析:只有与类名相同的方法可以叫构造函数
2、有歧义:此题本意是想说构造方法的名字与类名相同,而方法的签名是由方法的名字加参数的构成的
所以如果说是方法的签名不同也是可以说的通

143、abstract和final可以同时作为一个类的修饰符。( ) 答案:B

A、正确
B、错误
解析:abstract修饰一个类,这个类肯定可以被继承,但是final类是不能继承的,所以有矛盾,肯定不能同时用
2、Abstract表示抽象类,抽象类本身不可实例化,必须有子类去继承,且子类中实现抽象父类中所有的抽象方法,子类才可实例化。

final修饰的类,不可继承。

这个修饰符功能相克的。

144、下面代码将输出什么内容:() 答案:
public class SystemUtil{
    public static boolean isAdmin(String userId){
        return userId.toLowerCase()=="admin";
    }
    public static void main(String[] args){
        System.out.println(isAdmin("Admin"));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

A、true
B、false
C、1
D、编译错误
解析:equals和==的区别 == [查看全部](javascript:void(0))

145、对于JVM内存配置参数: 答案:D

-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3

,其最小内存值和Survivor区总大小分别是()

A、5120m,1024m
B、5120m,2048m
C、10240m,1024m
D、10240m,2048m
解析:-Xmx:最大堆大小

-Xms:初始堆大小

-Xmn:年轻代大小

-XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值

年轻代5120m, Eden:Survivor=3,Survivor区大小=1024m(Survivor区有两个,即将年轻代分为5份,每个Survivor区占一份),总大小为2048m。

-Xms初始堆大小即最小内存值为10240m

-Xmx10240m:代表最大堆
 -Xms10240m:代表最小堆
 -Xmn5120m:代表新生代
 -XXSurvivorRatio=3:代表Eden:Survivor = 3    根据Generation-Collection算法(目前大部分JVM采用的算法),一般根据对象的生存周期将堆内存分为若干不同的区域,一般情况将新生代分为Eden ,两块Survivor;    计算Survivor大小, Eden:Survivor = 3,总大小为5120,3x+x+x=5120  x=1024
新生代大部分要回收,采用Copying算法,快!
老年代 大部分不需要回收,采用Mark-Compact算法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
146、以下关于Integer与int的区别错误的是 答案:D

A、int是java提供的8种原始数据类型之一
B、Integer是java为int提供的封装类
C、int的默认值为0
D、Integer的默认值为1
解析:int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)
Integer 是 int 包装类;
int是基本数据类型,默认值为0,
Integer 是类,默认值为null;
Integer 表示的是对象,用一个引用指向这个对象,
int是基本数据类型,直接存储数值。

147、问这个程序的输出结果。 答案:D
class Base
{
    public void method()
    {
        System.out.println("Base");
    } 
}
class Son extends Base
{
    public void method()
    {
        System.out.println("Son");
    }
     
    public void methodB()
    {
        System.out.println("SonB");
    }
}
public class Test01
{
    public static void main(String[] args)
    {
        Base base = new Son();
        base.method();
        base.methodB();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

A、Base SonB
B、Son SonB
C、Base Son SonB
D、编译不通过
解析:

Base base = new Son();
  • 1

这句new 了一个派生类,赋值给基类,所以下面的操作编译器认为base对象就是Base类型的

Base类中不存在methodB()方法,所以编译不通过

148、关于OutOfMemoryError,下面说法正确的是()? 答案: A B C

A、java.lang.OutOfMemoryError: PermGen space 增加-XX:MaxPermSize这个参数的值的话,这个问题通常会得到解决。
B、java.lang.OutOfMemoryError: Requested array size exceeds VM limit当你正准备创建一个超过虚拟机允许的大小的数组时,这条错误将会出现
C、java.lang.OutOfMemoryError: Java heap space 一般情况下解决这个问题最快的方法就是通过-Xmx参数来增加堆的大小
D、java.lang.OutOfMemoryError: nativeGetNewTLA这个异常只有在jRockit虚拟机时才会碰到
解析:关于此题,《深入理解java虚拟机》有关于OOM(OutOfMemory)问题的解释

A:属于运行时常量池导致的溢出,设置-XX:MaxPermSize可以解决这个问题,

B:属于堆空间不足导致的错误,问题比较少见,解决方式和C相同,

C:属于java堆内存问题,一般的手段是通过内存映像分析工具,对Dump出来的堆转储存快照进行分析,重点是确认内存中的对象是否是有必要的,也就是要判断是出现了内存泄漏,还是出现了内存溢出,如果是内存列楼,通过工具检查泄露对象打GC Roots的引用链信息,可以准确的确定出泄露代码的位置,不存在泄露,就应该检查虚拟机的堆参数,如果可以继续调大,可以设置-Xmx解决问题

D:java.lang.OutOfMemoryError: nativeGetNewTLA指当虚拟机不能分配新的线程本地空间(Thread Local Area)的时候错误信息,此错误是线程申请一个新的TLA时产生的,这个异常一般只会发生在jRockit虚拟机,只有过于绝对。

149、以下关于JAVA语言异常处理描述正确的有? 答案:C D

A、throw关键字可以在方法上声明该方法要抛出的异常。
B、throws用于抛出异常对象。
C、try是用于检测被包住的语句块是否出现异常,如果有异常,则捕获异常,并执行catch语句。
D、finally语句块是不管有没有出现异常都要执行的内容。

E、在try块中不可以抛出异常

解析:Java语言中的异常处理包括声明异常、抛出异常、捕获异常和处理异常四个环节。

throw用于抛出异常。

throws关键字可以在方法上声明该方法要抛出的异常,然后在方法内部通过throw抛出异常对象。

try是用于检测被包住的语句块是否出现异常,如果有异常,则抛出异常,并执行catch语句。

cacth用于捕获从try中抛出的异常并作出处理。

finally语句块是不管有没有出现异常都要执行的内容。

150、Gadget has-a Sprocket and Gadget has-a Spring and Gadget is-a Widget and Widget has-a

Sprocket 以下哪两段代码可以表示这个关系? (选择两项) ( ) 答案:A C

A、

class Widget { Sprocket s; }
class Gadget extends Widget { Spring s; }
  • 1
  • 2

B、

class Widget { }
class Gadget extends Widget { Spring s1; Sprocket s2; }
  • 1
  • 2

C、

class Widget { Sprocket s1; Spring s2; }
class Gadget extends Widget { }
  • 1
  • 2

D、

class Gadget { Spring s; }
class Widget extends Gadget{ Sprocket s; }
  • 1
  • 2

解析:
is-a 表示继承:Gadget is-a Widget就表示Gadget 继承 Widget;

has-a表示从属:Gadget has-a Sprocket就表示Gadget中有Sprocket的引用,Sprocket是Gadget的组成部分;

like-a表示组合:如果A like-a B,那么B就是A的接口
2、从题目中可以得出以下几个结论:

  1. Gadget中有对Sprocket的引用。
  2. Gadget中有对Spring的引用。
  3. Gadget继承了Widget。
  4. Widget中有对Sprocket的引用。
  • A

    class Widget { Sprocket s; }
    class Gadget extends Widget { Spring s; }
    
    • 1
    • 2

    完全符合要求,这里的结论1虽然没有明确表明,但是因为结论3(Gadget继承了Widget)的存在,即父类中的非私有成员(Sprocket)子类都默认拥有。故结论都成立。

  • B

    class Widget { }
    class Gadget extends Widget { Spring s1; Sprocket s2; }
    
    • 1
    • 2

    结论123成立,但是没有表明结论4。

  • C

    class Widget { Sprocket s1; Spring s2; }
    class Gadget extends Widget { }
    
    • 1
    • 2

    完全符合要求,这里的结论12虽然没有明确表明,但是因为结论3(Gadget继承了Widget)的存在,即父类中的非私有成员(Sprocket和Spring

    )子类都默认拥有。故结论都成立。

  • D

    class Gadget { Spring s; }
    class Widget extends Gadget{ Sprocket s; }
    
    • 1
    • 2

    结论24成立,但是结论13没有表明。这里只是表明了Widget继承了Gadget,并且Widget具有对Spring的引用。

151、关于下面代码 int[] x=new int[25]; 描述正确的是() 答案:C

A、x[25]存放了数据“\0”。
B、x[24] 存放了数据“\0”。
C、若访问x[25],程序将抛出异常。
D、x[1]访问此数组的第一个元素。
解析:A:不存在x[25] 索引从0开始到length-1
B:x[24] 存的是默认值0(java中没有’\0’这一说)
C:超出内存 正确
D:第二元素

152、JDK8之前版本,HashMap的数据结构是怎样的? 答案:C

A、数组
B、链表
C、数组+链表/红黑树
D、二叉树
解析:JDK8及其以后版本,HashMap的数据结构是数组+链表+红黑树

153、假如某个JAVA进程的JVM参数配置如下:

-Xms1G -Xmx2G -Xmn500M -XX:MaxPermSize=64M -XX:+UseConcMarkSweepGC -XX:SurvivorRatio=3,
请问eden区最终分配的大小是多少? 答案:C

A、64M
B、500M
C、300M
D、100M
解析:Xms 起始内存

Xmx 最大内存

Xmn 新生代内存

Xss 栈大小。 就是创建线程后,分配给每一个线程的内存大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

154、下列关于容器集合类的说法正确的是? 答案: C

A、LinkedList继承自List
B、AbstractSet继承自Set
C、HashSet继承自AbstractSet
D、WeakMap继承自HashMap
解析:
a选项linkedlist类是实现了List接口,而不是继承

b选项AbstractSet类实现Set接口

c选项HashSet继承 AbstractSet类,同时也实现set

d选项WeakMap是js里面的玩意儿吧,,不太懂

155、下列关于JAVA多线程的叙述正确的是() 答案:B C

A、调用start()方法和run()都可以启动一个线程
B、CyclicBarrier和CountDownLatch都可以让一组线程等待其他线程
C、Callable类的call()方法可以返回值和抛出异常
D、新建的线程调用start()方法就能立即进行运行状态
解析:A,start是开启线程,run是线程的执行体,run是线程执行的入口。

**B,**CyclicBarrier和CountDownLatch都可以让一组线程等待其他线程。前者是让一组线程相互等待到某一个状态再执行。后者是一个线程等待其他线程结束再执行。

C,Callable中的call比Runnable中的run厉害就厉害在有返回值和可以抛出异常。同时这个返回值和线程池一起用的时候可以返回一个异步对象Future。

D,start是把线程从new变成了runnable

156、下列程序段执行后t3的结果是()。 答案: A
int t1 = 2, t2 = 3, t3;
t3 = t1 < t2 ? t1 : (t2 + t1);
  • 1
  • 2

A、2
B、4
C、5
D、6
解析:if(t1<t2)
t3=t1;;
else
t3=t2+t1;

157、以下对选择语句描述错误的是() 答案:A

A、根据某一条件重复执行一部分代码直到满足终止条件为止
B、可以根据条件控制程序流程,改变程序执行的顺序
C、选择语句可以嵌套使用
D、当条件满足时就会执行相应的语句
解析:流程控制语句分类:
顺序结构
选择结构:if语句、switch语句
循环结构:while语句、for语句
2、A答案说的是循环语句

java的4类流程控制语句

  1. 循环语句:while,for,do while
  2. 选择语句(分支语句):if,switch
  3. 跳转语句:break,continue,break,label
  4. 异常处理语句:try catch finally,throw
158、Which lines of the following will produce an error? 答案:A
byte a1 = 2, a2 = 4, a3;
short s = 16;
a2 = s;
a3 = a1 * a2;
  • 1
  • 2
  • 3
  • 4

A、Line 3 and Line 4
B、Line 1 only
C、Line 3 only
D、Line 4 only
解析:short类型转为byte类型出错

a1*a2结果为int类型,转为byte类型出错

159、下面描述属于java虚拟机功能的是? 答案:A B C D

A、通过 ClassLoader 寻找和装载 class 文件
B、解释字节码成为指令并执行,提供 class 文件的运行环境
C、进行运行期间垃圾回收
D、提供与硬件交互的平台
解析:A,C不用解释,B中JVM将字节码转换成不同平台(OS)下可执行的机器码指令。D中说的与硬件交互是JVM机器指令与硬件的交互。

160、下列哪些操作会使线程释放锁资源? 答案:B C

A、sleep()
B、wait()
C、join()
D、yield()
解析:join()底层就是调用wait()方法的,wait()释放锁资源,故join也释放锁资源

img

2、1.sleep会使当前线程睡眠指定时间,不释放锁

2.yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁

3.wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态

4.当前线程调用 某线程.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait,释放锁
2、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方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。

161、下列叙述错误的是( ) 答案: D

A、在接口中定义的方法除了default和static关键字修饰的方法拥有方法体,其他方法都应是没有方法体的抽象方法(JDK1.8以后)
B、一个java类只能有一个父类,但可以实现多个接口
C、在类声明中,用implements关键字声明该类实现的接口
D、定义接口时使用implements关键字。
解析
A、JDK8开始,接口中可以定义有方法体的方法,方法必须被default和static修饰。除此之外,其他方法都是抽象方法。

B、Java的语法是单继承,但是继承可以传递。其实B更准确一点是只能有一个直接父类。

C、继承用extends,实现用implements。先继承后实现。

D、类是class,接口是interface。

162、如果定义一种表达式结构:(+ 6 3)的值为9,(- 6 3)的值为3,(* 6 3)的值为18,(/ 6 3)的值为2;那么对于表达式(* (- 16 (* 3 2 2 )) (+ 5 (/ 6 (- 5 3))))输出的结果为____。 答案:D

A、44
B、40
C、40
D、32
解析:(* (- 16 (* 3 2 2 )) (+ 5 (/ 6 (- 5 3))))

(* (- 16 (* 3 2 2 )) (+ 5 (/ 6 2)))

(* (- 16 (* 3 2 2 )) (+ 5 3))

(* (- 16 (* 3 2 2 )) 8)

(* (- 16 12) 8)

(* 4 8)

32

163、关键字super的作用是? 答案:D

A、用来访问父类被隐藏的非私有成员变量
B、用来调用父类中被重写的方法
C、用来调用父类的构造函数
D、以上都是
解析:super代表父类对应的对象,所以用super访问在子类中无法直接使用的父类成员和方法
2、 1:特殊变量super,提供了对父类的访问。
2:可以使用super访问父类被子类隐藏的变量或覆盖的方法。
3:每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
4:构造是不能被继承的。

164、How should servlet developers handle the HttpServlet’s service() methond when extending HttpServlet? 答案: D

A、They should override the service()method in most cases;
B、They should call the service()method from doGet()or doPost();
C、They should call the service()method from the init()method;
D、They should override at least one doXXX()method(such as doPost())
解析:题目的意思是开发者在开发servlet继承HttpServlet时如何处理父类的service方法,一般我们都是不对service方法进行重载(没有特殊需求的话),而只是重载doGet()之类的doXxx()方法,减少了开发工作量。但如果重载了service方法,doXXX()方法也是要重载的。即不论是否重载service方法,doXXX()方法都是需要重载的。D说至少需要重载doXXX()方法是对的。

165、下面有关maven和ant的描述,描述错误的是? 答案:C

A、Ant 没有正式的约定如一个一般项目的目录结构,你必须明确的告诉 Ant 哪里去找源代码
B、Maven 拥有约定,因为你遵循了约定,它已经知道你的源代码在哪里
C、maven和ant都有“生命周期”的概念,当你输入一个命令后,maven或者ant会执行一系列的有序的步骤,直到到达你指定的生命周期
D、Ant构建文件默认命名为build.xml,Maven默认构建文件为pom.xml
解析:Ant和Maven都是基于Java的构建(build)工具。理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷。Ant是软件构建工具,Maven的定位是软件项目管理和理解工具。
Ant特点 ›
没有一个约定的目录结构 ›必须明确让ant做什么,什么时候做,然后编译,打包 ›没有生命周期,必须定义目标及其实现的任务序列 ›没有集成依赖管理
Maven特点
›拥有约定,知道你的代码在哪里,放到哪里去 ›拥有一个生命周期,例如执行 mvn install 就可以自动执行编译,测试,打包等构建过程 ›只需要定义一个pom.xml,然后把源码放到默认的目录,Maven帮你处理其他事情 ›拥有依赖管理,仓库管理

166、Continue语句跳出整个循环 答案:B

A、正确
B、错误
解析:1)continue是跳出本次循环,

比如

(for i = 0; i < 5; i++){
    if(i == 2){
        continue;
    }
    System.out.println("i = " + i);
}
//则结果应该是:
//i = 0
//i = 1
//i = 3
//i = 4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

即当遇到continue时,本次循环结束,直接开始下一次循环;

2)break是跳出本循环体

比如

(for i = 0; i < 4; i++){
(for j = 0; j < 4; j++){
    if(j == 2){
        break;
    }
    System.out.println("i = " + i + ", j = " + j);
}
//则结果应该是:
//i = 0, j = 0
//i = 0, j = 1
//i = 1, j = 0
//i = 1, j = 1
//i = 2, j = 0
//i = 2, j = 1
//i = 3, j = 0
//i = 3, j = 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

即当遇到break时,本循环体结束。

这些就是区别。

167、以下java程序代码,执行后的结果是() 答案:C
java.util.HashMap map=new java.util.HashMap(); 
map.put("name",null);      
map.put("name","Jack");
System.out.println(map.size());
  • 1
  • 2
  • 3
  • 4

A、0
B、null
C、1
D、2
解析:HashMap可以插入null的key或value,插入的时候,检查是否已经存在相同的key,如果不存在,则直接插入,如果存在,则用新的value替换旧的value,在本题中,第一条put语句,会将key/value对插入HashMap,而第二条put,因为已经存在一个key为name的项,所以会用新的value替换旧的vaue,因此,两条put之后,HashMap中只有一个key/value键值对。那就是(name,jack)。所以,size为1.

168、在类Tester中定义方法如下,

public double max(int x, int y) { // 省略 }

则在该类中定义如下哪个方法头是对上述方法的重载(Overload)? 答案:B

A、public int max(int a, int b) {}
B、public int max(double a, double b) {}
C、public double max(int x, int y) {}
D、private double max(int a, int b) {}
解析:重载就是一句话:同名不同参,返回值无关。

覆盖/重写:同名同参
2、Java 重载的规则:

1、必须具有不同的参数列表;

2、可以有不同的返回类型,只要参数列表不同就可以;

3、可以有不同的访问修饰符;

4、可以抛出不同的异常;

5、方法能够在一个类中或者在一个子类中被重载。

方法的重写:

1、在子类中可以根据需要对从基类中继承来的方法进行重写。

2、重写的方法和被重写的方法必须具有相同方法名称、参数列表和返回类型。

3、重写方法不能使用比被重写的方法更严格的访问权限。

169、根据下面的程序代码,哪些选项的值返回true? 答案:C
public class Square {  
    long width;  
    public Square(long l) {   
        width = l;  
    }  
    public static void main(String arg[]) {   
        Square a, b, c;  
        a = new Square(42L);   
        b = new Square(42L);   
        c = b;   
        long s = 42L;  
    } 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

A、a == b
B、s == a
C、b == c
D、a.equals(s)
解析:C

a = new Square(42L);   
 b = new Square(42L);   
  • 1
  • 2

这里new了两个对象,所以a,b不是同一个引用a!=b

s的类型跟a,b不同类型,所以s!=a,s!=b

 c = b;
  • 1

这里b,c是同一个对象的引用,所以b==c是true

170、下面有关servlet service描述错误的是? 答案:B

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

171、局部变量能否和成员变量重名? 答案:A

A、可以,局部变量可以与成员变量重名,这时可用“this”来指向成员变量
B、可以,这时可用“local”关键字来指向局部变量
C、不能,局部变量不能与成员变量重名
D、不能,在一个类中不能有重名变量,不管是成员变量还是函数中的局部变量
解析: 局部变量可以和成员变量重名,不加“this”修饰时,优先使用最近的变量。

img

172、下面的程序将来打印什么?() 答案:A
public class TestIncr {
    public static void main(String args[]) {
        int i = 0;
        i = i++ + i;
        System.out.println("I =" +i);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

A、I = 1
B、I = 2
C、I = 3
D、编译出错
解析:我相信很多人会不懂为什么是A

首先,在 i = i++ + i 中,先执行的是 i++ ,此时式子可为 i = 0 + i

然后再进行后一步 +i ,因为前面执行了 i++ ,所以这个 i 的值已经 +1 了

那么最后这个式子就是 i = 0 + 1 ,话不多说,直接上代码看吧

img

173、Java创建对象的说法正确的有() 答案:A B C D

A、用new语句创建对象,是最常见的创建对象的方法。
B、运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
C、调用对象的clone()方法。
D、运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
解析: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(); }
2、Java创建对象的5种方式:

  • 1.new
  • 2.对象克隆clone()方法
  • 3.反射Constructor类的newInstance()方法
  • 4.反射的Class类的newInstance()方法
  • 5.反序列化的readObject()方法
174、以下 json 格式数据,错误的是 答案:A C

A、{company:4399}
B、{“company”:{“name”:[4399,4399,4399]}}
C、{[4399,4399,4399]}
D、{“company”:[4399,4399,4399]}

解析:A:错误 {company:4399} 首先,其为json对象。但json对象要求属性必须加双引号。

B:正确

C:错误 {[4399,4399,4399]} 。使用 {} 则为json对象。json对象必须由一组有序的键值对组成。

D:正确。

答案:AC.

另参考(摘自<<Javascript 高级程序设计(第三版)>>):

JSON语法可以表示以下三种类型的值:

1.简单值:使用与JavaScript 相同的语法,可以在JSON中表示字符串,数值,布尔值和null。

2.对象:对象作为一种复杂数据类型,表示的是一组有序的键值对。而每组键值对中的值可以是简单值,也可以是复杂数据类型的值。

3.数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型–简单值,对象或数组。

175、Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持,下面关于Java反射的描述,错误的:( ) 答案:A D F

A、Java反射主要涉及的类如Class, Method, Filed,等,他们都在java.lang.reflet包下
B、通过反射可以动态的实现一个接口,形成一个新的类,并可以用这个类创建对象,调用对象方法
C、通过反射,可以突破Java语言提供的对象成员、类成员的保护机制,访问一般方式不能访问的成员
D、Java反射机制提供了字节码修改的技术,可以动态的修剪一个类
E、Java的反射机制会给内存带来额外的开销。例如对永生堆的要求比不通过反射要求的更多
F、Java反射机制一般会带来效率问题,效率问题主要发生在查找类的方法和字段对象,因此通过缓存需要反射类的字段和方法就能达到与之间调用类的方法和访问类的字段一样的效率

解析:A选项Class类位于lang包下面,D选项反射的本质就是从字节码中查找,动态获取类的整容结构,包括属性,构造器,动态调用对象的方法,而不是修剪类,F选项我觉得应该是,使用了反射的效率都会降低,就算加了缓存
2、A Class类在java.lang包

B 动态代理技术可以动态创建一个代理对象,反射不行

C 反射访问私有成员时,Field调用setAccessible可解除访问符限制

D CGLIB实现了字节码修改,反射不行

E 反射会动态创建额外的对象,比如每个成员方法只有一个Method对象作为root,他不胡直接暴露给用户。调用时会返回一个Method的包装类

F 反射带来的效率问题主要是动态解析类,JVM没法对反射代码优化。

176、有这样一段程序: 请问运行主要的程序会打印出的是什么() 答案:C
public class Test{
    public static void main(String [] args){
        List list=new ArrayList();
        list.add("a");
        list.add("b");
        list.add("a");
        Set set=new HashSet();
        set.add("a");
        set.add("b");
        set.add("a");
        System.out.println(list.size()+","+set.size());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

A、2,2
B、2,3
C、3,2
D、3,3
解析:1、List和Set的区别,set中不能放重复的
2、Set中重复的定义,未定义自己的equels方法的话,调用默认的,也就是直接==

由于此题采用的添加的是字符串,而字符串已经实现了equels方法,所以不会产生2中提到的问题,但是自己定义的类就要注意了。

综上所述,题目应该更改为只是为了检测1中的概念

publicclassTest{

public staticvoidmain(String [] args){

​ List list=newArrayList();

​ List.add(“a”);

​ List.add(“b”);
​ List.add(“a”);

​ Set set=newHashSet();

​ set.add(“a”);

​ set.add(“b”);

​ set.add(“a”);

​ System.out.println(list.size()+","+set.size());

}

};

177、执行以下程序后的输出结果是() 答案:D
public class Test {
    public static void main(String[] args) {
        StringBuffer a = new StringBuffer("A"); 
        StringBuffer b = new StringBuffer("B"); 
        operator(a, b); 
        System.out.println(a + "," + b); 
    } 
    public static void operator(StringBuffer x, StringBuffer y) { 
        x.append(y); y = x; 
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

A、A,A
B、A,B
C、B,B
D、AB,B
解析:StringBuffer a = newStringBuffer(“A”);

StringBuffer b = newStringBuffer(“B”);

此时内存中的状态如下图所示:

img

publicstaticvoidoperator(StringBuffer x, StringBuffer y) {

x.append(y); y = x;

}

进入如下方法后,内存中的状态为:

img

x.append(y);

这条语句执行后,内存的状态为:

img

y = x;

这条语句执行后,内存的状态为:

img

当operator方法执行完毕后内存中的状态为:因为方法执行完毕,局部变量消除。

img

有内存中的状态,可以知道最后的结果。

178、以下哪项陈述是正确的? 答案:E

A、垃圾回收线程的优先级很高,以保证不再使用的内存将被及时回收
B、垃圾收集允许程序开发者明确指定释放哪一个对象
C、垃圾回收机制保证了JAVA程序不会出现内存溢出
D、进入”Dead”状态的线程将被垃圾回收器回收
E、以上都不对
解析:E

A: 垃圾回收在jvm中优先级相当相当低。
B:垃圾收集器(GC)程序开发者只能推荐JVM进行回收,但何时回收,回收哪些,程序员不能控制。
C:垃圾回收机制只是回收不再使用的JVM内存,如果程序有严重BUG,照样内存溢出。
D:进入DEAD的线程,它还可以恢复,GC不会回收

179、下列描述错误的是? 答案:B D

A、类只能继承一个父类,但是可以实现多个接口
B、抽象类自身可以定义成员而接口不可以
C、抽象类和接口都不能被实例化(忽略匿名内部类)
D、一个类可以有多个父类和多个基接口
解析:**A、java为单继承,多实现。可以实现多个接口。
B、接口允许定义成员,但必须是常量。
C、*抽象类和接口类的无法实例化,任何编译器中直接使用new会报错。
D、A
,单继承,多实现。

180、下面有关java的引用类型,说法正确的有? 答案:A B C D

A、被GCroot强引用=Gcroot对象来说,只要有强引用的存在,它就会一直存在于内存中
B、如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
C、如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存
D、一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的空间
解析:发现这道题完全没头绪,就去查了一下,感觉说的比较清楚了。

四种引用类型

JDK1.2 之前,一个对象只有“已被引用”和"未被引用"两种状态,这将无法描述某些特殊情况下的对象,比如,当内存充足时需要保留,而内存紧张时才需要被抛弃的一类对象。

所以在 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。

一,强引用

Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收 obj = null; //手动置null

只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了

二,软引用

软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。

三,弱引用

弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。

四,虚引用

虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。
2、1、强引用:一个对象赋给一个引用就是强引用,比如new一个对象,一个对象被赋值一个对象。

2、软引用:用SoftReference类实现,一般不会轻易回收,只有内存不够才会回收。

3、弱引用:用WeekReference类实现,一旦垃圾回收已启动,就会回收。

4、虚引用:不能单独存在,必须和引用队列联合使用。主要作用是跟踪对象被回收的状态。

181、下列类定义代码,当用来声明对象car,并用Car car=new Car();实例化后,可以通过car对象直接赋值的字段是() 答案:B

img

A、type,No
B、type,price
C、heavy,owner
D、type,owner,price
解析:这题目就不严谨,题目说:可以通过car对象给变量赋值,还考虑个锤子的控制符作用域。我认为public,protect,default都可以。除了prive因为不是在本类中。垃圾题目。
img

182、指出下列程序运行的结果() 答案:B
public class Example{
    String str = new String("good");
    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';
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

A、good and abc
B、good and gbc
C、test ok and abc
D、test ok and gbc
解析:**简单总结一下:直接赋值而不是使用new关键字给字符串初始化,在编译时就将String对象放进字符串常量池中;使用new关键字初始化字符串时,是在堆栈区存放变量名和内容;字符串的拼接操作在程序运行时,才在堆中创建对象。一般,可以认为使用"=="比较的是引用,equals比较的是内容。**对于上面的题,看完下面的几个例子,你就会有所感悟:String str = new String(“good”);是在编译时在堆栈中创建对象和分配内容,而在传参的时候,传递的是地址,把外面的str引用地址复制了一份给方法内的str而不是里面的内容。

看例子:;

例子A:
String str1 = “java”;
String str2 = “java”;
System.out.print(str1str2);
大部分人也许认为会输出false,因为**比较的是引用,equals比较的是内容**。可以在自己的机子上运行一 下,结果是true!原因很简单,String对象被放进常量池里了,再次出现“java”字符串的时候,JVM很兴奋地把str2的引用也指向了 “java”对象,它认为自己节省了内存开销。不难理解吧 呵呵
例子B:
String str1 = new String(“java”);
String str2 = new String(“java”);
System.out.print(str1
str2);
看过上例的都学聪明了,这次肯定会输出true!很不幸,JVM并没有这么做,结果是false。原因很简单,例子A中**那种直接赋值(而没有通过new关键字实例化的字符串变量)声明的方式确实是在 String常量池创建“java”对象,但是一旦看到new关键字,JVM会在堆中为String分配空间。**两者声明方式貌合神离,这也是我把“如何创 建字符串对象”放到后面来讲的原因。大家要沉住气,还有一个例子。
例子C:
String str1 = “java”; //直接赋值而不是使用new关键字给字符串初始化,在编译时就将String对象放进字符串常量池中
String str2 = “blog”; //直接赋值而不是使用new关键字给字符串初始化,在编译时就将String对象放进字符串常量池中
String s = str1+str2; //字符串的拼接操作在程序运行时,才在堆中创建对象,
System.out.print(s
"javablog");
再看这个例子,很多同志不敢妄言是true还是false了吧。爱玩脑筋急转弯的人会说是false吧……恭喜你,你会抢答了!把那个“吧”字去掉你就完 全正确。原因很简单,JVM确实会对型如String str1 = “java”; 的String对象放在字符串常量池里,但是它是在编译时刻那么做的,而String s = str1+str2; 是在运行时刻才能知道(我们当然一眼就看穿了,可是Java必须在运行时才知道的,人脑和电脑的结构不同),也就是说str1+str2是在堆里创建的, s引用当然不可能指向字符串常量池里的对象。没崩溃的人继续看例子D。
例子D:
String s1 = “java”;
String s2 = new String(“java”);
System.out.print(s1.intern()==s2.intern());
intern()是什么东东?反正结果是true。如果没用过这个方法,而且训练有素的程序员会去看JDK文档了。简单点说就是
用intern()方法就可以用“==”比较字符串的内容了。在我看到intern()方法到底有什么用之前,我认为它太多余了。其实我写的这一条也很多余,intern()方法 还存在诸多的问题,如效率、实现上的不统一……

例子E:
String str1 = “java”;
String str2 = new String(“java”);
System.out.print(str1.equals(str2));
无论在常量池还是堆中的对象,用equals()方法比较的就是内容,就这么简单!

183、执行下面的程序段,语句3的执行次数为() 答案:C
for (i = 0; i <= n-1; i++)   // (1)
    for (j = n; j > i; j--// (2)
        state;               // (3)
  • 1
  • 2
  • 3

A、n(n+2)/2
B、(n-1)(n+2)/2
C、n(n+1)/2
D、(n-1)(n+2)
解析:假设代入法:

  • n=3,外层循环i的取值为0,1,2
  • 当i=0时,内部循环j的取值为3,2,1,所以state执行3次;当i=1时,内部循环j的取值3,2,所以state执行2次;当i=2时,内部循环j的取值为3,所以state执行1次。
  • 综上所述:3+2+1=6次。将n=3带入选项中的出C符合结果。
184、存根(Stub)与以下哪种技术有关 答案:B

A、交换
B、动态链接
C、动态加载
D、磁盘调度
解析:存根类是一个类,它实现了一个接口,它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法。但是一个类从业务来说,可能只需要其中一两个方法。如果直接去实现这个接口,除了实现所需的方法,还要实现其他所有的无关方法。而如果通过继承存根类就实现接口,就免去了这种麻烦。

RMI 采用stubs 和 skeletons 来进行远程对象(remote object)的通讯。stub 充当远程对象的客户端***,有着和远程对象相同的远程接口,远程对象的调用实际是通过调用该对象的客户端***对象stub来完成的。
每个远程对象都包含一个***对象stub,当运行在本地Java虚拟机上的程序调用运行在远程Java虚拟机上的对象方法时,它首先在本地创建该对象的***对象stub, 然后调用***对象上匹配的方法。每一个远程对象同时也包含一个skeleton对象,skeleton运行在远程对象所在的虚拟机上,接受来自stub对象的调用。这种方式符合等到程序要运行时将目标文件动态进行链接的思想

185、对Collection和Collections描述正确的是 答案: B D

A、Collection是java.util下的类,它包含有各种有关集合操作的静态方法
B、Collection是java.util下的接口,它是各种集合结构的父接口
C、Collections是java.util下的接口,它是各种集合结构的父接口
D、Collections是java.util下的类,它包含有各种有关集合操作的静态方法
解析:java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

186、关于Java语言的内存回收机制,下列选项中最正确的一项是 答案:C

A、Java程序要求用户必须手工创建一个线程来释放内存
B、Java程序允许用户使用指针来释放内存
C、内存回收线程负责释放无用内存
D、内存回收线程不能释放内存对象
解析:A,java的内存回收是自动的,Gc在后台运行,不需要用户手动操作

B,java中不允许使用指针

D,内存回收线程可以释放无用的对象内存

187、字符界面下接受用户从键盘输入,需要import的包是:( ) 答案:C

A、java.lang包
B、java.awt包
C、java.io包
D、java.applet包
解析:这个问题的前提是:字符界面下

前端用户输入、后台程序获取,都是字符流的传输,因此需要导入java.io包。

而java.util中的Scanner则是获取控制台的输入。

因此,答案选C

188、以下代码结果是什么? 答案:C
public class foo {
    public static void main(String sgf[]) {
 
        StringBuffer a=new StringBuffer("A");
 
        StringBuffer b=new StringBuffer("B");
 
        operate(a,b);
 
        System.out.println(a+"."+b);
    }
    static void operate(StringBuffer x,StringBuffer y) {
        x.append(y);
        y=x;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

A、代码可以编译运行,输出“AB.AB”。
B、代码可以编译运行,输出“A.A”。
C、代码可以编译运行,输出“AB.B”。
D、代码可以编译运行,输出“A.B”。
解析:这里简单地说,a,b,x,y就是四个指针。y本来指向的是b所指向的对象,但是一个“=”,y就指向了x所指向的目标即是a指向的对象,因此原来b所指向的目标并没有发生任何改变。与y不同的是,x进行的是对象操作,此时此对象在内存中是真正的本质上的改变。有点绕,但是手机打字,没发画图,不然其实很容易理解。
2、引用a指向对象A

引用b指向对象B

引用x指向对象A

引用y指向对象B

在operate方法中,引用x指向的对象A被连接了B,对象A也就被改变为AB

然后又把引用y指向了x所指向的对象地址,也就是此时引用a,x,y指向同一个对象AB

而引用b没有发生任何变化,依旧指向对象B。

189、下面哪几个语句正确的声明一个整型的二维数组() 答案:C D

A、int a[][]=new int[][]
B、int b[10][10]=new int[][]
C、int c[][]=new int[10][10]
D、int []d[]=new int[10][10]
解析:

img

\1. 定义一维数组时,必须显式指明数组的长度;

\2. 定义***数组时,其一维数组的长度必须首先指明,其他维数组长度可以稍后指定;

\3. 采用给定值初始化数组时,不必指明长度;

\4. “[]” 是数组运算符的意思,在声明一个数组时,数组运算符可以放在数据类型与变量之间,也可以放在变量之后。

190、关于volatile关键字,下列描述不正确的是? 答案:B D

A、用volatile修饰的变量,每次更新对其他线程都是立即可见的。
B、对volatile变量的操作是原子性的。
C、对volatile变量的操作不会造成阻塞。
D、不依赖其他锁机制,多线程环境下的计数器可用volatile实现。
解析:一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

2)禁止进行指令重排序。

volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值——每次都会从内存中读取。

而对该变量的修改,volatile并不提供原子性的保证。

由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况

多线程下计数器必须使用锁保护。

191、 答案:B

多重继承的概念在Java中实现是通过如下哪些?()

I. 扩展两个或多个类

II. 扩展一个类并实现一个或多个接口。

III. 实现两个或更多接口。

A、只有I &II
B、只有II & III
C、只有III
D、都是
解析:Java只支持单继承,实现多重继承三种方式:(1)直接实现多个接口 (2)扩展(extends)一个类然后实现一个或多个接口 (3)通过内部类去继承其他类

192、volatile关键字的说法错误的是 答案:A

A、能保证线程安全
B、volatile关键字用在多线程同步中,可保证读取的可见性
C、JVM保证从主内存加载到线程工作内存的值是最新的
D、volatile能禁止进行指令重排序
解析:出于运行速率的考虑,java编译器会把经常经常访问的变量放到缓存(严格讲应该是工作内存)中,读取变量则从缓存中读。但是在多线程编程中,内存中的值和缓存中的值可能会出现不一致。volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是volatile不能保证原子性,也就不能保证线程安全。
2、1.java的内存模型

java 内存模型规定了所有的变量都存储在主内存中,但是每个线程会有自己的工作内存,线程的工作内存保存了该线程中使用了的变量(从主内存中拷贝的),线程对变量的操作都必须在工作内存中进行,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值从传递都要经过主内存完成

图片说明

2.什么是原子性

一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账

3.什么是可见性

当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值

4.什么是有序性

程序执行的顺序按照代码的先后顺序执行

int` `a = ``0``; ``//1``int` `b = ``2``; ``//2
  • 1

像这2句代码1会比2先执行,但是jvm在正真执行时不一定是1在2之前,这里涉及一个概念叫做指令重排,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。比如上面的代码语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。
在指令重排时会考虑指令之间的数据依赖性,比如2依赖了1的数值,那么处理器会保证1在2之前执行。
但是在多线程的情况下,指令重排就会有影响了。

5.volatile到底做了什么

  • 禁止了指令重排
  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
  • 不保证原子性(线程不安全)
193、在Java中,关于HashMap类的描述,以下正确的是 () 答案: A C D

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

Map集合类keyvalue
HashMap允许为null允许为null
TreeMap不允许为null允许为null
ConcurrentMap不允许为null不允许为null
HashTable不允许为null不允许为null
194、String s=null;

下面哪个代码片段可能会抛出NullPointerException? 答案:A C

A、if((s!=null)&(s.length()>0))
B、if((s!=null)&&(s.length()>0))
C、if((s==null)|(s.length()0))
D、if((s
null)||(s.length()==0))
解析:s为null,因此只要调用了s.length()都会抛出空指针异常。因此这个题目就是考察if语句的后半部分会不会执行。
A,单个与操作的符号& 用在整数上是按位与,用在布尔型变量上跟&&功能类似,但是区别是无论前面是否为真,后面必定执行,因此抛出异常
B,与操作,前半部分判断为假,后面不再执行
C,这里跟 & 和&& 的区别类似,后面必定执行,因此抛出异常
D,或语句,前面为真,整个结果必定为真,后面不执行

195、下面有关servlet的层级结构和常用的类,说法正确的有? 答案:A B C D

A、GenericServlet类:抽象类,定义一个通用的、独立于底层协议的Servlet。
B、大多数Servlet通过从GenericServlet或HttpServlet类进行扩展来实现
C、ServletConfig接口定义了在Servlet初始化的过程中由Servlet容器传递给Servlet得配置信息对象
D、HttpServletRequest接口扩展ServletRequest接口,为HTTP Servlet提供HTTP请求信息
解析:img

196、下列外部类定义中,不正确的是:( ) 答案:C

A、class x { … }
B、class x extends y { … }
C、static class x implements y1,y2 { … }
D、public class x extends Applet { … }
解析:static修饰的为类成员,会随着类的加载而加载,比如静态代码块,静态成员,静态方法(这里只是加载,并没有调用)等等,可以想象一下,如果把一个Class文件中的外部类设为static,目的难道是让这个类随着应用的启动而加载吗?如果在这次使用过程中根本没有使用过这个类,那么是不是就会浪费内存。这样来说设计不合理,总而言之,设计不合理的地方,Java是不会让它存在的。
而为什么内部类可以使用static修饰呢,因为内部类算是类的成员了,如果没有使用静态来修饰,那么在创建内部类的时候就需要先有一个外部类的对象,如果我们一直在使用内部类,那么内存中就会一直存在外部类的引用,而我们有时候只需要使用内部类,不需要外部类,那么还是会浪费内存,甚至会造成内存溢出。使用static修饰内部类之后,内部类在创建对象时就不需要有外部类对象的引用了。
最终结论就是:static可以用来修饰内部类,但是不可以用来修饰外部类

197、下面论述正确的是()? 答案:D

A、如果两个对象的hashcode相同,那么它们作为同一个HashMap的key时,必然返回同样的值
B、如果a,b的hashcode相同,那么a.equals(b)必须返回true
C、对于一个类,其所有对象的hashcode必须不同
D、如果a.equals(b)返回true,那么a,b两个对象的hashcode必须相同
解析: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()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
2、A:在hashmap中,key值是不可能重复的,由hashCode和equals方法共同判断key值是否相等。即使两个对象的hashCode相同相等,也不能说他们的key值相等。

B和D:如果x.equals(y)返回true,那么这两个对象的hashCode返回的整数结果必然相同。如果x.equals(y)返回false,则不一定;

反之,hashCode返回的值不相等,则equals方法返回值一定不相等。hashCode返回值相等,则不一定

C:hashCode的值是可以相同的

198、有以下程序片段,下列哪个选项不能插入到第一行 。( )。 答案:A
1.

2.public  class  A{

3.//do sth

4. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

A、public class MainClass{ }
B、package mine;
C、class ANotherClass{ }
D、import java.util.*;
解析:**Java一个源程序只能有一个public类存在,且类名与文件名相同。**Java程序是从main方法开始执行的,public为类加载器提供入口,然后找到public类中的main方法开始执行。如果存在多个public类,程序将不知道该从哪里执行。
注意,内部类可以是public的,因为内部类是作为外部类的成员存在的。

199、下面代码的输出结果是什么? 答案:D
public class ZeroTest {
    public static void main(String[] args) {
     try{
       int i = 100 / 0;
       System.out.print(i);
      }catch(Exception e){
       System.out.print(1);
       throw new RuntimeException();
      }finally{
       System.out.print(2);
      }
      System.out.print(3);
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

A、3
B、123
C、1
D、12
解析:1、inti = 100/ 0; 会出现异常,会抛出异常,System.out.print(i)不会执行,

2、catch捕捉异常,继续执行System.out.print(1);

3、当执行 thrownewRuntimeException(); 又会抛出异常,这时,除了会执行finally中的代码,其他地方的代码都不会执行

200、以下哪种方式实现的单例是线程安全的 答案: A B C D

A、枚举
B、静态内部类
C、双检锁模式
D、饿汉式
解析:高频面试题:单列模式的6种实现方式。

整理分享不易,点个赞鸭~

目录:
img

一、单例模式的定义

定义: 确保一个类只有一个实例,并提供该实例的全局访问点。

这样做的好处是:有些实例,全局只需要一个就够了,使用单例模式就可以避免一个全局使用的类,频繁的创建与销毁,耗费系统资源。

二、单例模式的设计要素
  • 一个私有构造函数 (确保只能单例类自己创建实例)
  • 一个私有静态变量 (确保只有一个实例)
  • 一个公有静态函数 (给使用者提供调用方法)

简单来说就是,单例类的构造方法不让其他人修改和使用;并且单例类自己只创建一个实例,这个实例,其他人也无法修改和直接使用;然后单例类提供一个调用方法,想用这个实例,只能调用。这样就确保了全局只创建了一次实例。

三、单例模式的6种实现及各实现的优缺点
(一)懒汉式(线程不安全)

实现:

public class Singleton {
     private static Singleton uniqueInstance;

     private Singleton() {

    }

    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

说明: 先不创建实例,当第一次被调用时,再创建实例,所以被称为懒汉式。

优点: 延迟了实例化,如果不需要使用该类,就不会被实例化,节约了系统资源。

缺点: 线程不安全,多线程环境下,如果多个线程同时进入了 if (uniqueInstance == null) ,若此时还未实例化,也就是uniqueInstance == null,那么就会有多个线程执行 uniqueInstance = new Singleton(); ,就会实例化多个实例;

(二)饿汉式(线程安全)

实现:

public class Singleton {

    private static Singleton uniqueInstance = new Singleton();

    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
        return uniqueInstance;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

说明: 先不管需不需要使用这个实例,直接先实例化好实例 (饿死鬼一样,所以称为饿汉式),然后当需要使用的时候,直接调方法就可以使用了。

优点: 提前实例化好了一个实例,避免了线程不安全问题的出现。

缺点: 直接实例化好了实例,不再延迟实例化;若系统没有使用这个实例,或者系统运行很久之后才需要使用这个实例,都会操作系统的资源浪费。

(三)懒汉式(线程安全)

实现:

public class Singleton {
    private static Singleton uniqueInstance;

    private static singleton() {
    }

    private static synchronized Singleton getUinqueInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

说明: 实现和 线程不安全的懒汉式 几乎一样,唯一不同的点是,在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程能够进入该方法,避免了多线程不安全问题的出现。

优点: 延迟实例化,节约了资源,并且是线程安全的。

缺点: 虽然解决了线程安全问题,但是性能降低了。因为,即使实例已经实例化了,既后续不会再出现线程安全问题了,但是锁还在,每次还是只能拿到锁的线程进入该方***使线程阻塞,等待时间过长。

(四)双重检查锁实现(线程安全)

实现:

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

说明: 双重检查数相当于是改进了 线程安全的懒汉式。线程安全的懒汉式 的缺点是性能降低了,造成的原因是因为即使实例已经实例化,依然每次都会有锁。而现在,我们将锁的位置变了,并且多加了一个检查。 也就是,先判断实例是否已经存在,若已经存在了,则不会执行判断方法内的有锁方法了。 而如果,还没有实例化的时候,多个线程进去了,也没有事,因为里面的方法有锁,只会让一个线程进入最内层方法并实例化实例。如此一来,最多最多,也就是第一次实例化的时候,会有线程阻塞的情况,后续便不会再有线程阻塞的问题。

为什么使用 volatile 关键字修饰了 uniqueInstance 实例变量 ?

uniqueInstance = new Singleton(); 这段代码执行时分为三步:

  1. 为 uniqueInstance 分配内存空间
  2. 初始化 uniqueInstance
  3. 将 uniqueInstance 指向分配的内存地址

正常的执行顺序当然是 1>2>3 ,但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。
单线程环境时,指令重排并没有什么问题;多线程环境时,会导致有些线程可能会获取到还没初始化的实例。
例如:线程A 只执行了 1 和 3 ,此时线程B来调用 getUniqueInstance(),发现 uniqueInstance 不为空,便获取 uniqueInstance 实例,但是其实此时的 uniqueInstance 还没有初始化。

解决办法就是加一个 volatile 关键字修饰 uniqueInstance ,volatile 会禁止 JVM 的指令重排,就可以保证多线程环境下的安全运行。

优点: 延迟实例化,节约了资源;线程安全;并且相对于 线程安全的懒汉式,性能提高了。

缺点: volatile 关键字,对性能也有一些影响。

(五)静态内部类实现(线程安全)

实现:

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

说明: 首先,当外部类 Singleton 被加载时,静态内部类 SingletonHolder 并没有被加载进内存。当调用 getUniqueInstance() 方法时,会运行 return SingletonHolder.INSTANCE; ,触发了 SingletonHolder.INSTANCE ,此时静态内部类 SingletonHolder 才会被加载进内存,并且初始化 INSTANCE 实例,而且 JVM 会确保 INSTANCE 只被实例化一次。

优点: 延迟实例化,节约了资源;且线程安全;性能也提高了。

(六)枚举类实现(线程安全)

实现:

public enum Singleton {

    INSTANCE;

    //添加自己需要的操作
    public void doSomeThing() {

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

说明: 默认枚举实例的创建就是线程安全的,且在任何情况下都是单例。

优点: 写法简单,线程安全,天然防止反射和反序列化调用。

  • 防止反序列化
    **序列化:**把java对象转换为字节序列的过程;
    反序列化: 通过这些字节序列在内存中新建java对象的过程;
    说明: 反序列化 将一个单例实例对象写到磁盘再读回来,从而获得了一个新的实例。
    我们要防止反序列化,避免得到多个实例。
    枚举类天然防止反序列化。
    其他单例模式 可以通过 重写 readResolve() 方法,从而防止反序列化,使实例唯一重写 readResolve() :
private Object readResolve() throws ObjectStreamException{
        return singleton;
}
  • 1
  • 2
  • 3
四、单例模式的应用场景

应用场景举例:

  • 网站计数器。
  • 应用程序的日志应用。
  • Web项目中的配置对象的读取。
  • 数据库连接池。
  • 多线程池。

使用场景总结:

  • 频繁实例化然后又销毁的对象,使用单例模式可以提高性能。

  • 经常使用的对象,但实例化时耗费时间或者资源多,如数据库连接池,使用单例模式,可以提高性能,降低资源损坏。

  • 使用线程池之类的控制资源时,使用单例模式,可以方便资源之间的通信。

    2、

    第一种:饿汉模式(线程安全)

    public class Single2 {
    
        private static Single2 instance = new Single2();
        
        private Single2(){
            System.out.println("Single2: " + System.nanoTime());
        }
        
        public static Single2 getInstance(){
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    第二种:懒汉模式 (如果方法没有synchronized,则线程不安全)

    public class Single3 {
    
        private static Single3 instance = null;
        
        private Single3(){
            System.out.println("Single3: " + System.nanoTime());
        }
        
        public static synchronized Single3 getInstance(){
            if(instance == null){
                instance = new Single3();
            }
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    第三种:懒汉模式改良版(线程安全,使用了double-check,即check-加锁-check,目的是为了减少同步的开销)

    public class Single4 {
    
        private volatile static Single4 instance = null;
        java
        private Single4(){
            System.out.println("Single4: " + System.nanoTime());
        }
        
        public static Single4 getInstance(){
            if(instance == null){
                synchronized (Single4.class) {
                    if(instance == null){
                        instance = new Single4();
                    }
                }
            }
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    第四种:利用私有的内部工厂类(线程安全,内部类也可以换成内部接口,不过工厂类变量的作用于要改为public了。)

    public class Singleton {
        
        private Singleton(){
            System.out.println("Singleton: " + System.nanoTime());
        }
        
        public static Singleton getInstance(){
            return SingletonFactory.singletonInstance;
        }
        
        private static class SingletonFactory{
            private static Singleton singletonInstance = new Singleton();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
201、以下说法错误的是() 答案: C

A、数组是一个对象
B、数组不是一种原生类
C、数组的大小可以任意改变
D、在Java中,数组存储在堆中连续内存空间里
解析: 在java中,数组是一个对象, 不是一种原生类,对象所以存放在堆中,又因为数组特性,是连续的,只有C不对

202、 在异常处理中,如释放资源,关闭数据库、关闭文件应由( )语句来完成。 答案:C

A、try子句
B、catch子句
C、finally子句
D、throw子句
解析:C。finally子句一般是用来清理这些资源的。try-finally语句是Microsoft对C和C++语言的扩展,它能使32位的目标程序在异常出现时,有效保证一些资源能够被及时清除,这些资源的清除任务可以包括例如内存的释放,文件的关闭,文件句柄的释放等等。

Q: 为何C++不提供“finally”结构?
A: 因为C++提供了另一种机制,完全可以取代finally,而且这种机制几乎总要比finally工作得更好:就是——“分配资源即初始化”。(见《The C++ Programming Language》14.4节)基本的想法是,用一个 局部对象来封装一个资源,这样一来局部对象的析构函数 就可以自动释放资源。这样,程序员就不会“忘记释放资源”了。 [译注:因为C++的对象“生命周期”机制替他记住了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/790094
推荐阅读
相关标签