2018-7月Java试题整理

7-12日

1.在main()方法中给出的字节数组,如果将其显示到控制台上,需要()

  • 标准输出流System.out.println()
  • 建立字节输出流
  • 建立字节输入流
  • 标准输入流System.in.println()

解析:
输出到控制台,直接’System.out.println()’
out是“标准”输出流,Public static final PrintStream out
out是PrintStream类型,PrintStream是包装流,你传入什么,他就输出什么

2.事务隔离级别是由谁实现的?

  • Java应用程序
  • Hibernate
  • 数据库系统
  • JDBC驱动程序

解析:
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别;为了解决更新丢失,脏读,不可重读(包括虚读和幻读)等问题,在标准SQL规范中,定义了4个事务隔离级别:
未授权读取(read uncommitted)
授权读取(read committed)
可重复读取(repeatable read)
序列化(serializable)

3.在Java7中,下列那个说法是正确的

  • ConcurrentHashMap使用synchronized关键字保证线程安全
  • HashMap实现了Collection接口
  • Arrays.asList方法返回java.util.ArrayList对象
  • SimpleDateFormat对象是线程不安全的

解析:
HashMap在单线程中使用大大提高了,在多线程的情况下使用hashTable来确保安全。hashTable中使用synchronized关键字来实现安全机制,但是synchronized是对整张hash表进行锁定即让线程独享整张hash表,在安全同时造成了浪费concurrentHashMap采用分段加锁的机制来确保安全。
Array.asList()将一个数组转化为一个List对象,这个方法会返回一个ArrayList类型的对象,这个ArrayList类并非java.util.ArrayList类,而是Array类的静态内部类,用这个对象对咧进行CRUD操作,就会报UnsupportedOperationException异常
ConcurrentHashMap使用segment来分段和管理锁,segment继承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock来保证线程安全。

4.下列关于Java多线程的叙述正确的是()

  • 调用start()方法和run()方法都可以启动一个线程
  • CyclicBarrier和CountDownLatch都可以让一组线程等待其它线程
  • Callable类的call()方法可以返回值和抛出异常
  • 新建的线程调用start()方法就能立即进行运行状态

解析:
start()方法来启动线程,真正实现了多线程运行,调用run()方法,run()方法当作普通方法的方式调用
CyclicBarrier让一组线程等待其它线程;CountDownLatch让一组线程等待某个事件发生
Callable能够抛出check exception
start()方法让thread进去可运行状态(runnable),等待获取CPU的使用权限权。
CountDownLatch:允许一个或多个线程等待其它线程完成操作
CyclicBarrier:(同步屏障)让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会执行。

7-13

1.要使对象具有序列化能力,则其类应该实现如下哪个接口

  • java.io.Serializable
  • java.lang.Cloneable
  • java.lang.CharSequence
  • java.lang.Comparable

解析:
java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法,只是用于标志此接口的实现类可以被序列化与反序列化
java.lang.Cloneable接口是一个标志性接口,在接口内部没有定义任何属性与方法。以指示Object.clone方法可以合法地对该类实例进行按字段复制
java.lang.CharSequence接口对许多不同种类的char序列提供统一的只读访问接口。charSequence是char值得一个可读序列
java.lang.Comparable接口,此接口强制对实现它得每个类得对象进行整体排序,此序列被称为该类的自然排序

2.下列描述中,错误的是

  • SQL 语言又称为结构化查询语言
  • Java中“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
  • 面向对象开发中,引用传递意味着传递的并不是实际的对象,而是对象的引用,因此,外部对引用对象所作的改变不会反映到所引用的对象上
  • Java是强类型语言,JavaScript是弱类型语言
  • 面向对象的三大特点包括:封装,继承,多态。

解析:
引用代表引用的是实际的对象,对引用的修改就是对对象的修改,可以理解成两把钥匙可以打开同一扇门
引用传参保存的是一个地址,这个地址里保存的是变量的具体值,而引用类型作为参数的时候,是将变量保存的地址值赋值到参数变量里,这样它们都指向了同一个内容,这样改变参数的成员变量的话,那么相应的变量的成员也会改变。

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

  • 不会

解析:
Thread.sleep()和Object wait()都可以抛出InterruptException。这个异常是不能忽略的,因为他是一个检查异常(check exception)
check exception:指的是编译时异常,该类异常需要本函数处理,用try和catch处理,或者throws抛出异常,然后交给调用者去处理
runtime exception:指的是运行时异常,该类异常不必须本函数处理,当然也可以处理

4.以下代码执行后输出结果为

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;
         }
     }
 }
  • return value of getValue():1
  • return value of getValue():0
  • return value of getValue():0return value of getValue():1
  • return value of getValue():1return value of getValue():0

根据官方JVM规范:
如果try语句里有return,返回的是try语句块中变量值

详细过程如下:

  1. 如果有返回值,就把返回值保存到局部变量中
  2. 执行jsr指令跳到finally语句里执行
  3. 执行完finally语句后,返回之前保存在局部变量里的值

如果try,finally语句里均有return,忽略try的return,而使用finally的return
finally语句总是要执行的,不管出没出现异常,当finally语句中有return时,会覆盖try/catch语句块的return,所以一般不要在finally中加return语句。
return的两个作用:返回数据,结束方法运行。

5.下面有关Java swing的描述,说法错误的是

  • Swing是一个基于Java的跨平台MVC框架,使用单线程模式。
  • Swing是为了解决AWT存在的问题而新开发的包,它以AWT为基础的
  • Swing优化了AWT,运行速度比AWT快
  • Swing是一个基于组件的框架,所有的组件都是从javax.swing.JComponent类继承来的

解析:
Swing是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT所能够提供的所有功能,并且用纯粹的Java代码对AWT的功能进行了大幅度的扩充,AWT是基于本地方法的C/C++程序,其运行速度比较快,Swing是基于AWT的Java程序,其运行速度比较慢

6.__意味着一个操作在不同的类中可以有不同的实现方式

  • 多态性
  • 多继承
  • 类的组合
  • 类的复用

解析:
类的复用有两种方式:组成(has-a)和继承(is-a)

  1. 组成就是在新的类中直接创建旧类的对象,这里我们复用的只是代码的功能而不是它的形式
  2. 继承是在原有的类的基础上建立一个新类,新类具有旧类的形式,但也加入了一些新的特性

继承:指一个新的类继承原有类的基本特性,并增加了新的特性(Java不允许多继承,而C++可以)

多态性:指允许不同类的对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式

多态存在的三个必要条件:

  1. 要有继承
  2. 要有重写
  3. 父类引用指向子类对象(向上转型)

实现多态性的三种形式:

  1. 方法的重载
  2. 通过继承机制而产生方法覆盖
  3. 通过接口实现方法覆盖

多态的分类:
多态分为编译时多态和运行时多态,其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编译之后会变成两个不同的函数,在运行时谈不上多态。
而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们平常所说的多态性。

7.

关于方法重载:方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法,方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。

方法重载的具体规范:

  1. 方法名一定要相同
  2. 方法的参数表必须不同,包括参数的类型或个数,以此区分不同的方法体
  3. 方法的返回类型,修饰符可以相同,也可以不同

8.下面有关JVM内存,说法错误的是

  • 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的
  • 虚拟机描述的是Java方法执行的内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的
  • 方法区用于存储JVM加载的类信息,常量,静态变量,以及编译器编译后的代码等数据,是线程隔离的
  • 原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的

方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的的区域。在方法区中,存储了每个类的信息(包括类的名称,方法信息,字段信息),静态变量,常量以及编译器编译后的代码等。
概括来说,JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM每遇到一个线程,就会为其分配一个Program Counter Register(程序计数器),VM Stack(虚拟机栈)和Native Method Stack(本地方法栈),当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说只发生在Heap上)的原因。

JVM内存模型图
2018-7月Java试题整理_第1张图片

方法区存放了所加载的类的信息(名称,修饰符等),类中的静态变量,类中定义为final类型的常量,类中的Field信息,类中的方法信息,当开发人员在程序中通过Class对象中的getName,isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。
2018-7月Java试题整理_第2张图片

9.Consider the following code ‘String s = null’ Which code fragements cause an object of type NullPointerExeception to be thrown?

  • if((s!=null)&(s.length()>0))
  • if((s!=null)&&(s.length()>0))
  • if((s==null)|(s.length()==0))
  • if((s==null)||(s.length()==0))

解析:
s为null,因此只要调用了s.length()都会抛出空指针异常,因此这个题目主要考察if语句的后半部分会不会执行。
A:单个‘与’操作的符号&用在整数上时按位与,用在布尔型变量上跟&&功能类似,但是区别是无论前面是否为真,后面必定执行,因此抛出异常
B:‘与’操作,前半部分判断为假,后面不再执行
C:这里跟&和&&的区别类似,后面必定执行,因此抛出异常
D:‘或’语句,前面为真,整个结果必定为真,后面不执行

7-17

1.下列关于异常处理的描述中,错误的是

  • 程序运行时异常由Java虚拟机自动进行处理
  • 使用try-cathch-finally语句捕获异常
  • 可使用throw语句抛出异常
  • 捕获到的异常只能在当前方法中处理,不能在其它方法中处理

解析:
D:捕获到的异常不仅可以在当前方法中处理,还可以将异常抛给调用它的上一级方法来处理
A:运行时异常Java虚拟机会自动处理,只有当是检查时异常Java会强制性抛出异常,对异常进行处理。

2.在jdk1.8之前,下列哪一种叙述是正确的

  • abstract修饰符可修饰字段,方法和类
  • 抽象方法的body部分必须用一对大括号{}包住
  • 声明抽象方法,大括号可有可无
  • 抽象方法不可写出大括号

解析:
abstract修饰符用来修饰类和成员方法
1.用abstract修饰的类表示抽象类,抽象类位于继承树的抽象层,抽象类不能被实例化
2.用abstract修饰的方法表示抽象方法,抽象方法没有方法体。抽象方法用来描述系统具有什么功能,但不提供具体的实现。
Abstract是Java中的一个重要关键字,可以用来修饰一个类或者一个方法,修饰一个方法时,表示该方法只有特征签名,没有具体实现,而是把具体实现留给继承该类的子类,一个类中只要有一个abstract方法,那么这个类就要被声明为abstract,但是其中可以有非abstract方法。abstract类可以使得类得设计者能够创建方法的原型,而真正的实现留给使用这个类的人。
字段是指:成员变量和成员常量

3.Given

Java

//point X
public class Foo {
    public static void main(String[] args) throws Exception {

        PrintWriter out = new PrintWriter(
            new java.io.OutputStreamWriter(System.out), true);
        out.printIn(“Hello”);
    }
}
  • import java.io.PrintWriter;
  • include java.io.PrintWriter;
  • import java.io.OutputStreamWriter;
  • include java.io.OutputStreamWriter;
  • no statement is needed.

解析:
Java中没有include关键字,导包用import
在创建OutputStreamWriter的时候,使用的是类的全名称,所以不需要使用import

4.以下描述正确的是

  • 类不可以多继承而接口可以多实现
  • 抽象类自身可以定义成员而接口不可以
  • 抽象类和接口都不能被实例化
  • 一个类可以有多个基类和多个基接口

解析:

  1. Java支持单继承,却可以实现多个接口,A对D错
  2. 接口没有构造方法,所以不能实例化,抽象方法有构造方法,但是不是用来实例化的,是用来初始化的,C对
  3. 抽象类可以定义普通成员变量而接口不可以,但是抽象类和接口都可以定义静态成员变量,只是接口的静态成员变量要用static final public 来修饰,B错

5.以下不是修饰符final的作用的是

  • 修饰常量
  • 修饰不可被继承的类
  • 修饰不可变类
  • 修饰不可覆盖的方法

解析:
不可变类(Immutable Class)是一旦被实例化就不会改变自身状态(或值)的类
String就是一种典型的不可变类
不可变类的主要用途是在多线程环境下确保对象的线程安全
不可变类一般建议使用final来修饰(比如String就是final类),否则子类可以通过继承不可变类的方式,增加setter方法,从而改变对象的状态,破坏了不可变的约束

6.定义有StringBuffer s1 = new StringBuffer(10);s1.append(“1234”)则s1.length和s1.capacity()分别是多少

  • 4,10
  • 4,4
  • 10,10
  • 10,4

解析:
StringBuffer s = new StringBuffer(x);X为初始化容量长度。s.append(“Y”);“Y”表示长度为y的字符串;length始终返回当前长度即y;
对于s.capacity():

1.当y < x时,值为x

以下情况容器容量需要扩充

1.当 x < y < 2*x+2时,值为2*x+2
2.当y > 2*x+2时,值为y

7.下列正确的是

  • 形式参数可以被视为local variable
  • 形式参数可以被所有的字段修饰符修饰
  • 形式参数为方法被调用时,是真正被传递的参数
  • 形式参数不可以是对象

解析:
A:形式参数可被视为local variable,形参和局部变量一样都不能离开方法,都只有在方法内部才会发生作用,不会在方法外可见
B:对于形式参数只能用final修饰符,其他任何修饰符都会引起编译器错误,但是这个修饰符也有一定的限制,就是在方法中不能对参数做任何修改。不过一般情况下,一个方法的形参不用final修饰,只有在特殊情况下,那就是:方法内部类,一个方法内的内部类如果使用了这个方法的参数或者局部变量的话,这和参数或局部变量应该是final
C:形参的值在调用时根据调用者更改,实参则用自身的值更改形参的值(指针,引用皆在此列),也就是说真正被传递的是实参
D:方法的参数列表指定要传递给方法什么样的信息,采用的都是对象的形式。因此,在参数列表中必须指定每个所传递对象的类型及名字。像Java中任何传递对象的场合一样,这里传递的实际上也是引用,并且引用的类型必须正确

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


public class Test2
{
    public void add(Byte b)
    {
        b = b++;
    }
    public void test()
    {
        Byte a = 127;
        Byte b = 127;
        add(++a);
        System.out.print(a + " ");
        add(b);
        System.out.print(b + "");
    }
}
  • 127,127
  • 128,127
  • 129,129
  • 以上都不对

解析:
包装类的值都是final不可变的,对于++b或者b++,只是新创建了一个对象,然后把引用传给了原对象句柄,在函数中操作,只是形参的临时句柄改变了指向

7-18

1.下面哪个行为被打断不会导致interruptedException

  • Thread.join
  • Thread.sleep
  • Object.wait
  • CyclicBarrier.await
  • Thread.suspend

抛出InterruptedException的代表方法有:

  1. java.lang.Object 类的 wait 方法
  2. java.lang.Thread 类的 sleep 方法
  3. java.lang.Thread 类的 join 方法

说下CyclicBarrier是一个屏障类,它的await方法可以简单的理解为:等待多个线程同时到达之后才能继续进行,在此之前它就是这些线程的屏障,线程不能继续进行,而对于失败的同步尝试,CyclicBarrier使用了一种要么全部要么全不(all-or-none)的破坏模式:因为中断,失败或者超时等原因,导致线程过早的离开了屏障点,那么在该屏障点等待的其它所有线程也将通过BrokenBarrierException(如果它们几乎同时被中断,则用interruptedException)以反常的方式离开。因此它被中断也是可以抛出interruptedException的

2.关于下面代码 int[] x = new int[25]描述正确的是

  • x[25]存放了数据”\0”
  • x[24]存放了数据”\0”
  • 若访问x[25],程序将抛出异常
  • x[1]访问此数组的第一个元素

解析:
\0是空字符
A:不存在x[25] ,索引从0开始到length-1
B:x[24]存的是默认值0(Java中没有“\0”这一说)
C:超出内存 正确
D:第二元素

3.

解析:
同一个类内,private变量可以访问,由于x是static的,存储在类内,而不是对象内,所以++,–操作的是同一个变量

类变量即可以通过类来返回,也可以通过类的对象来访问。但通过类的对象来访问类变量时,实际不是访问该对象所拥有的变量,因为当系统创建该类的对象时,系统不会再为类变量分配内存,也不会再次对类变量进行初始化。也就是说,对象根本不拥有对应类的类变量,通过对象访问类变量只是一种假象,通过对象访问的依然是该类的类变量。

4.对文件名为Test.java的Java代码描述正确的是

class Person {
    String name = "No name";
    public Person(String nm) {
        name = nm;
    }
}
class Employee extends Person {
    String empID = "0000";
    public Employee(String id) {
        empID = id;
    }
}
public class Test {
    public static void main(String args[]) {
        Employee e = new Employee("123");
        System.out.println(e.empID);
    }
}
  • 输出:0000
  • 输出123
  • 编译报错
  • 输出 no name

解析:
父类没有无参的构造函数,所以子类需要在自己的构造函数中显式的调用父类的构造函数
添加super(“nm”),否则报错

class Person {
    String name = "No name";
    public Person(String nm) {
        name = nm;
    }

}
class Employee extends Person {
    public Employee(String nm) {
        super(nm);
        // TODO Auto-generated constructor stub
    }

    String empID = "0000";
}
public class Test {
    public static void main(String args[]) {
        Employee e = new Employee("123");
        System.out.println(e.empID);
    }
}

也就是:如果子类构造器没有显示地调用超类的构造器,则将自动地调用超类默认(没有参数)的构造器。如果超类没有不带参数的构造器,并且在子类的构造器中没有显式地调用超类的其它构造器,则Java编译器将报错。
使用super调用构造器的语句必须是子类构造器的第一条语句
——p153《Java核心技术卷I》

5.对如下代码段,可以放入到横线位置,使程序正常运行而不产生错误的选项是

class A{
    public A foo(){return this;}
}
class B extends A{
    public A foo(){
        return this;
    }
}
class C extends B {
    _______

}
  • public void foo(){}
  • public int foo(){return 1;}
  • public A foo(B b){return b;}
  • public A foo(){return A;}

子类重写父类方法遵循“两同两小一大”的规则

“两同”:方法名相同,形参列表相同
“两小”:子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相同
“一大”:子类方法的访问权限应比父类方法的访问权限更大或相等

注意:覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法一个是实例方法

6.阅读下列程序,选择哪一个是正确的输出结果

class HelloA{
public HelloA()
    {
        System.out.println("I’m A class ");
    }
    static
    {
    System.out.println("static A");
    }
}
public class HelloB extends HelloA{
    public HelloB()
    {
        System.out.println("I’m B class");
    }
    static{
        System.out.println("static B");
    }
    public static void main (String[] args){
        new HelloB();
    }
}
  • static A I’m A class static B I’m B class
  • I’m A class I’m B class static A static B
  • static A static B I’m A class I’m B class
  • I’m A class static A I’m B class static B

解析:静态优先,父类优先
类的初始化顺序是:

  1. 初始化父类中的静态成员变量和静态代码块
  2. 初始化子类中的静态成员变量和静态代码块
  3. 初始化父类中的普通成员变量和代码块,在执行父类中的构造方法
  4. 初始化子类中的普通成员变量和代码块,在执行子类中的构造方法

7.下列错误的是

  • 在类方法中可用this来调用本类的类方法
  • 在类方法中调用本类的类方法时可直接调用
  • 在类方法中只能调用本类中的类方法
  • 在类方法中绝对不能调用实例方法

解析:
A:类方法是指类中被static修饰的方法,无this指针
C:类方法是可以调用其它类的static方法的
D:可以在类方法中生成实例对象再调用实例方法,太绝对了,在类中申请一个类对象或者参数传递一个对象或指针都可以调用

成员方法又称为实例方法
静态方法又称为类方法

7-20

1.final方法等同与private方法

  • 正确
  • 错误

解析:
private方法只可以在类的内部使用,在类外部根本访问不到;而final方法可以在类外部访问,但是不可以重写该方法。
就是说可以使用该方法的功能但是不可以改变其功能

2.下列关于Java并发的说法正确的是

  • copyonwritearraylist适用于写多读少的并发场景
  • readwritelock适用于读多写少的并发场景
  • concurrenthashmap的写操作不需要加锁,读操作需要加锁
  • 只要在定义int类型的成员变量i的时候加上volatile关键字,那么多线程并发执行i++这样的操作的时候就是线程安全的了

解析:
CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存
ReadWriteLock当写操作时,其他线程无法读取或写入数据,而当读操作时,其它线程无法写入数据,但却可以读取数据。适用于读取远远大于写入的操作
ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。
Hash Table是对整个代码块加锁,而ConcurrentHashMap是使用分片锁,粒度较小,不用对整个代码块加锁,提高了读写速率;准确说Hash Map底层是数组+链表的结构,它的线程是不安全的,而Hash Table是在Hash Map的基础上,对整个哈希表(数组)加锁sychronized实现线程安全,而我们知道,方法访问数组中的数据,可能只涉及到数组的部分,对整个数组加锁会降低线程并发执行的效率,所以如果对数组分段加锁,使用segment分片锁,这样一个线程只会锁住数组的一片,其它线程仍可以访问数组的其它片进行写操作,具有这样的分片锁的机制就是**ConcurrentHashMap**

Volatile只能保证变量的安全,而不能保证线程的安全

3.Java8中,忽略内部接口的情况,不能用来修饰interface里的方法的有

解析:
Java8的接口方法可以有如下定义:
public,abstract,default,static,strictfp

4.对于一个已经不被任何变量引用的对象,当垃圾回收器准备回收该资源所占用的内存时,将自动调用该对象的哪个方法

  • finalize
  • notify
  • notifyAll
  • hashCode

解析:

Java回收机制是自发的,无需人为操作,finalize是这种机制执行时需要调用的函数,可以认为更改

在Java虚拟机的垃圾回收器看来,堆区中的每个对象都可能处于以下三个状态之一:

  1. 可触及状态:当一个对象被创建后,只要程序中还有引用变量引用它,那么它就始终处于可触及状态
  2. 可复活状态:当程序不再有任何变量引用该对象时,它就进入可复活状态。在这个状态中,垃圾回收器会准备释放它占用的内存,在释放之前,会调用它及其他处于可复活状态的对象的finalize()方法,这些finalize()方法有可能使该对象重新转到可触及状态
  3. 不可触及状态:当Java虚拟机执行完所有可复活对象的finalize()方法后,假如这些方法都没有使该对象转到可触及状态,那么该对象就进入不可触及状态,只有当对象处于不可触及状态,垃圾回收器才会真正回收它占用的内存

notify唤醒线程,与wait()和同步锁synchronized()方法配合使用

5.

Java中整型默认是int
浮点默认是double

6.Java虚拟机功能:

  1. 通过ClassLoader寻找和装载class文件
  2. 解释字节码成为指令并执行,提供class文件的运行环境
  3. 进行运行期间垃圾回收
  4. 提供与硬件交互的平台

7.volatile关键字的说法错误的是

  • 能保证线程安全
  • volatile关键字用在多线程中,可保证读取的可见性
  • JVM保证从主内存加载到线程工作内存的值是最新的
  • volatile能禁止进行指令重排序

解析:
出于运行速率的考虑,Java编译器会把经常访问的变量放到缓存(严格说应该是工作内存)中,读取变量则从缓存中读。但是在多线程编程中,内存中的值和缓存中的值可能会不一样。volatile用于限定变量只能从内存中读取,保证保证对所有线程而言,值都是一样的。但是volatile不能保证原子性,也就不能保证线程安全。

Java中volatile关键字的功能:
volatile是Java中的一个类型修饰符,它是被设计用来修饰被不同线程访问和修改的变量。如果不加入volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。

  1. 可见性:可见性指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。顺便一提,工作内存和主内存可以近似的理解成实际电脑中的高速缓存和主存,工作线程是线程独享的,主存是线程共享的
  2. 禁止指令重排序:禁止指令重排序优化。写代码的时候(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只能保证程序执行结果与源码相同,却不保证实际指令的顺序和源码相同。这在单线程中没什么,但是在多线程中,这种乱序可能导致严重的问题。volatile关键字就是从语义上解决这个问题。

8.Java中,StringBuilder和StringBuffer的区别,下面说法错误的是

  • StringBuffer是线程安全的
  • StringBuilder是非线程安全的
  • StringBuffer对String类型进行改变的时候其实都等同于生成了一个新的String对象,然后将指针指向新的String对象
  • 效率比较String

9.Java类加载器的说法:

  • 引导类加载器(bootstrap class loader):用来加载Java的核心库,使用原生代码来实现的
  • 扩展类加载器(extensions class loader):用来加载Java的扩展类
  • 系统加载器(system class loader):根据Java应用的类路径(CLASSPATH)来加载Java类
  • 用户自定义类加载器(user custom class loader):通过java.lang.ClassLoader的子类动态加载class文件

10.有这么一段程序,请问执行结果是什么?

public class Test{ 
    public String name="abc"; 
    public static void main(String[] args){ 
        Test test=new Test(); 
        Test testB=new Test(); 
        System.out.println(test.equals(testB)+","+test.name.equals(testB.name)); 
    } 
}
  • true,true
  • true,false
  • false,true
  • false,false

解析:
没有重写equals时,是直接用==判断的,而String中重写了equals方法。
简单说:比较地址值,但是String重写了,所以可以比较内容

11.

总结:如果finally块中有return语句的话,它将覆盖掉函数中其它return语句。

7-21

1.重写满足的规则:(两同两小一大)

  • 两同:方法名和形参列表一致
  • 两小:重写方法的返回值(引用类型)和抛出异常,要和被重写方法的返回值(引用类型)和抛出异常相同或者是其子类。一旦返回值是基本数据类型,那么重写方法和被重写方法必须相同,且不存在自动拆装箱的问题
  • 一大:重写方法的访问修饰符大于等于被重写方法的访问修饰符

2.下列关于对象序列化描述正确的是

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

解析:
能够对对象进行传输的只有ObjectOutputStream和ObjectInputStream这些以Object开头的流对象
transient修饰的变量在对象串化的时候并不会将所附的值保存到串中,串行化的对象从磁盘读取出来仍然是Null。即transient代表对象的临时数据

3.下面有关Java异常类的描述,说法错误的是

  • 异常的继承结构:基类为Throwable,Error和Exception继承Throwable,RuntimeException和IOException等继承Exception
  • 非RuntimeException一般是外部错误,必须被try{}catch语句所捕获
  • Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形,Error不需要捕捉
  • RuntimeException体系包括错误的类型转换,数组越界访问,试图访问空指针等,必须被try{}catch语句所捕获

解析:
运行时异常顾名思义就是程序在运行的时候出现异常,隐含的一个前提就是程序在编译时是检测不到一场的存在的,作者本人也并不知道是否自己的代码中含有运行时异常,所以根本也不可能提前使用try{}catch语句所捕获

4.

鲁棒性:即健壮性
程序设计语言中,数组元素在内存中是一个接着一个线性存放的,通过第一个元素就能访问随后的元素,这样的数组称之为“真数组”

5.欲构造ArrayList类的一个实例,此类实现了List接口,下列哪个方法是正确的

  • ArrayList myList=new Object()
  • List myList=new ArrayList()
  • ArrayList myList=new List()
  • List myList=new List()

解析:
属于面向接口编程,是Java语言的一大优点,ArrayList虽然是一个具体的类,按照ArrayList myList = new ArrayList;的确可以生成一个myList对象,而且编译也不会报错。但实际开发中不采用这样的方式即实际开发时都是 :接口名 xxx = new 接口某实现类()。这样便于:

  1. 便于程序规范化设计
  2. 便于团队协同开发
  3. 便于转换为组件
  4. 方便的代码复用,无需了解技术细节

6.

子父类存在同名成员时,子类中默认访问子类的成员,可通过super指定访问父类的成员,格式:super.xx
创建子类对象时,默认会调用父类的无参构造器,可通过super指定调用父类其它构造器,格式:super(yy)

7.jvm中垃圾回收分为scanvenge gc和full gc,其中full gc触发的条件可能有哪些
  • 栈空间满
  • 年轻代空间满
  • 老年代满
  • 持久代满
  • System.gc()

解析:

  1. 新生代:

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

  3. 持久代:持久代如果满了,将触发Full GC

7-22

1.下列代码片段中,存在编译错误的是:

byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2);  /*语句1*/
b6=b4+b5;    /*语句2*/
b8=(b1+b4);  /*语句3*/
b7=(b2+b5);  /*语句4*/
System.out.println(b3+b6);
  • 语句2
  • 语句1
  • 语句3
  • 语句4

解析:
Java表达式转型规则由低到高转换:

  1. 所有的byte,short,char类型的值将被提升为int型
  2. 如果有一个操作数是long型,计算结果是long型
  3. 如果有一个操作数是float型,计算结果是float型
  4. 如果有一个操作数是double型,计算结果是double型
  5. 被final修饰的变量不会自动改变类型,当2个final修饰相操作时,结果会根据左边变量的类型而转换

语句1:b3=(b1+b2);自动转为int,所以正确写法为b3=(byte)(b1+b2);或者将b3定义为int;
语句2:b6=b4+b5;b4、b5为final类型不会自动提升,所以和的类型视左边变量类型而定,即b6可以试任何数值类型
语句三:b8=(b1+b4);虽然b4不会自动提升,但b1仍会自动提升,所以结果需要强转,b8=(byte)(b1+b4);
语句四:b7=(b2+b5);同上。同时注意b7是final修饰,即只可以赋值一次,便不可再改变

2.下面代码输出结果是什么?

public class Test {
    public int aMethod(){
        static int i = 0;
        i++;
        return i;
    }
public static void main(String args[]){
    Test test = new Test();
    test.aMethod();
    int j = test.aMethod();
    System.out.println(j);
    }
}
  • 0
  • 1
  • 2
  • 编译失败

解析:
静态变量只能在类主体中定义,不能在方法中定义。
静态变量属于类所有而不属于方法。

3.

Java子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符要比父类的更大,也就是更开放,假如我父类是protected修饰的,其子类只能是protected或者public,绝不能是friendly(默认访问范围)或者private,当然使用private就不是继承了。还要注意的是,继承当中子类抛出的异常必须是父类抛出的异常的子类,或者子类抛出的异常要比父类抛出的异常要少

4.在try的括号里面有return一个值,在那里执行finally里的代码

  • 不执行finally代码
  • return前执行
  • return后执行

解析:
假设利用return语句从try语句块中退出,在方法返回前,finally子句的内容将被执行。如果finally子句中也有一个return语句,这个返回值将会覆盖原始的返回值。

public static void main(String[] args) {
        int k = f_test();
        System.out.println(k);
    }

    public static int f_test(){
        int a = 0;
        try{
            a = 1;
            return a;
        }
        finally{
            System.out.println("It is in final chunk.");
            a = 2;
            return a;
        }
    }

输出:
it is in final chunk
2

如果将return a;注释掉,将输出:
it is in final chunk
1

5.以下说法错误的是

  • 虚拟机中没有泛型,只有普通的类和普通的方法
  • 所有泛型类的类型参数在编译时都会被擦出
  • 创建泛型对象时请指明类型,让编译器尽早的做参数检查
  • 泛型的类型擦除机制意味着不能运行时动态获取List < T > 中T的实际类型

解析:
创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。
事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法,处理的方法就叫做类型变量T的擦除。
总结:

  1. 虚拟机中没有泛型,只有普通的类和方法
  2. 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换(类型擦除)
  3. 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。无论如果定义一个泛型类型,相应的都会有一个原始类型被自动提供,原始类型的名字就是擦除类型参数的泛型类型的名字。

6.

如果类没有构造方法,JVM会生成一个默认构造方法,如果定义了任意类型的构造方法,编译器都不会自动生成构造方法

7.有一个源代码,只包含import java.util.* ;这一个import语句,下面叙述正确的是

  • 只能写在源码的第一句
  • 可以访问java/util目录下及其子目录下的所有类
  • 能访问java/util目录下的所有类,不能访问java/util子目录下的所有类
  • 编译错误

解析:
在Java源文件中,import语句应位于package语句之后,所有类的定义之前,可以没有,也可以有多条,package语句必须放在第一行
B:因为其根目录和子目录下可能有同名类,若都能读取,则会混淆

8.

Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行
共同点:

  1. 都是在多线程环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回
  2. wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。如果线程A希望立刻结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join。则线程B会立即抛出InterruptedException,在catch(){}中直接return即可安全的结束线程。需要注意的是:InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一个线程调用interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InteruptedException。但是,一旦该线程进入到wait()/sleep()/join()后,就立刻抛出InterruptedException

不同点:

  1. 每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现线程的同步/sleep方法没有释放锁,而wait()方法释放了锁,使得其它线程可以使用同步控制块或者方法
  2. wait,notify和notifyAll只能在同步控制方法或同步控制块里面使用,而sleep可以在任何地方使用
  3. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
  4. sleep是线程类(Thread)的方法,导致此线程暂停指定时间,执行机会给其它线程,但是监控状态仍然保持,到最后会自动恢复。调用sleep不会释放对象锁
  5. wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

7-23

1.下面哪种方式可以终止当前线程的运行?

  • 当一个优先级高的线程进入就绪状态时
  • 抛出一个异常时
  • 当该线程调用sleep()方法时
  • 当创建一个新线程时

解析:
A:是抢占,不是终止
B:是终止
C:是暂停,不是终止
D:和A差不多

2.在JDK1.5的环境下,有如下四条语句,以下结果输出为false的是?

Integer i01 = 59;
int i02 = 59;
Integer i03 =Integer.valueOf(59);
Integer i04 = new Integer(59);
  • System.out.println(i01 == i02);
  • System.out.println(i01 == i03);
  • System.out.println(i03 == i04);
  • System.out.println(i02 == i04);

解析:
Integer i01 = 59的时候,会调用Integer的valueOf方法

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

这个方法就是返回一个Integer对象,只是在返回之前,做了一个判断,判断当前i的值是否在[-128,127]区间,且IntegerCache中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新对象。
在这里的话,因为程序初次运行,没有59,所以,直接返回一个新的对象
int i02=59,这是一个基本类型,存储在栈中
Integer i03 = Integer.valueOf(59),因为IntegerCache中已经存在此对象,所以,直接返回引用。
Integer i04=new Integer(59);直接创建一个新的对象

A:System. out .println(i01== i02);i01是Integer对象,i02是int,这里比较的不是地址,而是值。Integer会自动拆箱成int,然后进行值得比较,所以,为真。
B:System. out .println(i01== i03); 因为i03返回的是i01的引用,所以,为真。
C:System. out .println(i03==i04); 因为i04是重新创建的对象,所以i03,i04是指向不同的对象,所以,比较结果,为假。
D:System. out .println(i02== i04); 因为i02是基本类型,所以此时i04会自动拆箱,进行值比较,所以,为真。

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

public class Base
{
    private String baseName = "base";
    public Base()
    {
        callName();
    }

    public void callName()
    {
        System. out. println(baseName);
    }

    static class Sub extends Base
    {
        private String baseName = "sub";
        public void callName()
        {
            System. out. println (baseName) ;
        }
    }
    public static void main(String[] args)
    {
        Base b = new Sub();
    }
}
  • null
  • sub
  • base

解析:
new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为Null。
子类中定义了同名的baseName,会隐藏父类的baseName,所以这里输出的是子类的baseName,这时子类的额baseName还没有初始化。如果用super.baseName会打印出base。

4.

解析:构造方法不能被子类继承,所以用final修饰没有意义。构造方法用于创建一个新的对象,不能作为类的静态方法,所以用static修饰没有意义

5.

解析:一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java的这种序列化模式为开发者提供了很多便利,我们可以不必关心序列化的过程,只要这个类实现了Serilizable接口,这个类所有属性和方法都会自动序列化。
这个类的有些属性需要序列化,有些不需要被序列化
Java的transient关键字提供了便利。你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中
简单说:

  1. 在序列化的时候,被transient或static修饰的属性,不可以序列化
  2. 一个类可以被序列化,那么他的子类也可以被序列化
  3. 序列化可以实现深复制,而Object中的clone只是浅复制

6.

解析:两种方法的区别:

  1. start方法:
    用start方法来启动线程,是真正实现了多线程,通过调用Thread类的start()方法来启动一个线程,此时这个线程就处于就绪状态(可运行)状态,并没有运行,一旦得到CPU时间片,就开始执行run()方法,但要注意的是,此时无需等待run()方法执行完毕,即可继续执行下面的代码。所以run()方法并没有实现多线程。

  2. run方法:
    run方法只是类的一个普通方法而已,如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可以继续执行下面的代码。

7.下面关于程序编译说法正确的是?

  • java语言是编译型语言,会把java程序编译成二进制机器指令直接运行
  • java编译出来的目标文件与具体操作系统有关
  • java在运行时才进行翻译指令
  • java编译出来的目标文件,可以运行在任意jvm上

解析:
A:Java编译成的是字节码,再被各系统的jvm编译成本系统可以识别的机器码,这就是jvm一次编程多平台应用的跨平台性。
B:Java源文件生成的是class文件,与系统无关
C:注意字节码和机器码不是一回事,Java程序在运行时字节码才会被jvm翻译成机器码,所以说Java是解释性语言
D:注意JVM的版本

8.堆内存原理:

JVM堆内存分为两块:Permanent Space和Heap Space

  • Permanent Space即持久代,主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大
  • Heap ={Old + NEW={Eden,from,to}}。Old即年老代(Old Generation),New即年轻代(Young Generation)。年老代和年轻代的划分对GC影响比较大

年轻代:
所有新生成的对象首先都是放在年轻代。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代一般分为3个区,1个Eden区,两个Survivor区(from和to)
大部分对象在Eden区生成。当Eden区满时,还存活的的对象将复制到Survivor区(两个中的各一个),当一个Survivor区满时,此区的存活对象将被复制到另一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将可能被复制到年老代。
2个Survivor区是对称的,没有先后关系,所以同一个Survivor区中可能同时存在从Eden区中复制过来的对象,和从另一个Survivor区复制过来的对象;而复制到年老代的只有从另一个Survivor区过来的对象。而且,因为需要交换的原因,Survivor区至少有一个是空的。特殊情况下,根据需要Survivor区可以配置为多个的(多于2个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能
针对年轻代的垃圾回收即Young GC

年老代:
在年轻代中经历了N次(可配置)GC后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象
针对年老代的垃圾回收即Full GC

持久代:
用于存放静态类型数据。如Java Class,Method等,持久代对GC没有显著影响。但是有些应用可能动态生成或调用一些Class,例如Hibernate CGLib等,在这种时候往往需要设置一个比较大的持久代空间来存放这些运行过程中动态增加的类型

所以当一组对象生成时,内存申请过程如下:

  1. JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域
  2. 当Eden区空间足够的时候,内存申请结束,否则执行下一步
  3. JVM试图释放在Eden中所有不活跃(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中活跃的对象放入Survivor区
  4. Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时Survivor区中存活了一定次数的对象就会被移到年老代
  5. 当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)
  6. Full GC后,若Survivor区及年老代仍无法存放从Eden区复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“Out of Memory”

OOM(Out of Memory)异常一般有如下两种原因:

  1. 年老代溢出,表现为:java.lang.OutOfMemoryError:Javaheapspace
    这是最常见的情况,产生的原因可能是:设置的内存参数Xmx过小或者程序的内存泄漏及使用不当问题。
    例如循环上万次的字符串处理,创建上千万个对象,在一段代码内申请上百M甚至上G的内存。
    还有的时候虽然不会报内存溢出,却会使系统不间断的GC,也无法处理其他请求。这种情况下除了检查程序,打印堆内存的方法排查,还可以借助一些内存分析工具,比如MAT。

  2. 持久代溢出,表现为java.lang.OutOfMemoryError:PermGenspace
    通常由于持久代设置过小,动态加载了大量Java类而导致溢出
    解决方法唯有将参数 -XX:MaxPermSize 调大(一般256m能满足绝大多数应用程序需求)。将部分Java类放到容器共享区(例如Tomcat share lib )去加载的方法也是一个思路,但前提是容器里部署了多个应用,且这些应用有大量共享类库

7-24

1.

Collection:(只能存储引用类型,而且是单个存储)

  • List(有序,可重复)

    • LinkedList(非同步)
    • ArrayList(非同步),实现了可变大小的元素数组
    • Vector(同步)
      • Stack
  • Set (无序,不可重复)不允许有相同的元素

    • hashSet
    • treeSet(自动排序)

Map:(键无序不可重复)

  • HashTable(同步)实现一个Key-value映射的哈希表
  • HashMap(非同步)
  • WeakHashMap 改进的HashMap,实现了“弱引用”,如果一个key不被引用,则GC回收

2.方法通常存储在进程中的哪一区?

  • 堆区
  • 栈区
  • 全局区
  • 方法区

解析:
“进程的区”属于操作系统里面的

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

  1. 栈区:主要用来存放局部变量,传递参数,存放函数的返回地址。esp始终指向栈顶,栈中的数据越多,esp的值越小。
  2. 堆区:用于存放动态分配的对象,当你使用malloc和new等进行分配时,得到的空间就在堆中。动态分配得到的内存区域附带有分配信息,所以你能够free和delete它们。
  3. 数据区:全局,静态和常量是分配在数据区中的,数据区包括bss(未初始化数据区)和初始化数据区。
  4. 代码区:存放方法(class文件)

注意:

  1. 堆向高内存地址生长
  2. 栈向低内存地址生长
  3. 堆和栈相向而生,堆和栈之间有个临界点,称为stkbrk

一条进程在内存中的映射:
假设现在有一个程序,它的函数调用顺序如下:
main()->func_1->func_2->func_3,即:主函数main调用函数func_1;函数func_1调用func_2;函数func_2调用func_3
当一个程序被操作系统调入内存运行,其对应的进程在内存中的映射,如下

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

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

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

4.下面关于JVM内存,说法错误的是?

  • 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的。
  • Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的
  • 方法区用于存储JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,是线程隔离的
  • 原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的

解析:
运行时数据区包括:虚拟机栈区,堆区,方法区,本地方法栈,程序计数器

  • 虚拟机栈区:也就是我们常说的栈区,线程私有,存放基本类型,对象的引用和returnAdress,在编译期间完成分配
  • 堆区:Java堆区,也成为GC堆,所有线程共享,存放对象的实例和数组,Java堆是垃圾收集器管理的主要区域
  • 方法区:所有线程共享,存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。这个区域的内存回收目标主要是针对常量池的对象的回收和对类型的卸载。
  • 程序计数器:线程私有,每个线程都有自己独立的程序计数器,用来指示下一条指令的地址。

5.

Math.ceil:天花板数,向上取整
Math.floor:地板数,向下取整

6.下列哪个是错误的?

  • 一个文件只能有一个public class
  • 一个文件中可以有多个类
  • 一个类中可以有两个main方法
  • 若类中只含一个main方法,则必须是public

解析:
A:一个文件中,可以有多个public class

public class Main { public class Inner{

    }
}

即外部类为public,还可以有Public的内部类
B:一个文件中可以有多个类,可以是多个并列的类,也可以是外部类,内部类结合
C:一个类中,可以有多个main方法,这是重载。但是public static void main(String[] str)的方法只能有一个。
D:类中,可以有main方法,也可以没有main方法,而有一个main()方法的时候,也可以是任意访问权限。因为这个类不一定要执行,可以只是辅助类

7.Java中,下列哪一个正确?

  • class中的constructor不可省略
  • constructor必须与class同名,但方法不能与class同名
  • constructor在一个对象被new时执行
  • 一个class只能定义一个constructor

解析:
A:省略构造函数,编译器会自动生成
D:构造函数可以重载
B:方法是可以和类名同名的,和构造方法唯一的区别就是,构造方法没有返回值。如下代码:

public class TestConStructor
{
    public TestConStructor()
    {
        System.out.println("constructor");
    }
    public void TestConStructor()
    {
        System.out.println("not constructor");
}
public static void main(String[] args)
{
    TestConStructor testConStructor = new TestConStructor();
    System.out.println("main");
    testConStructor.TestConStructor();
}

8.对于文件的描述正确的是

  • 文本是以“.txt”为后缀名的文件,其他后缀名的文件是二进制文件
  • File类是Java中对文件进行读写操作的基本类
  • 无论文本文件还是二进制文件,读到文件末尾都会抛出EOFException异常
  • Java中对于文本文件和二进制文件,都可以当作二进制文件进行操作

解析:
A:文件分为文本文件和二进制文件,计算机只认识二进制,所以实际上都是二进制的不同解释方式。
B:File类是对文件整体或者文件属性操作的类,例如创建文件,删除文件,查看文件是否存在等功能,不能操作文件内容;文件内容是用IO流操作的
C:当输入过程中意外到达文件或流的末尾时,抛出EOFException异常。正常情况下读取到文件末尾时,返回一个特殊值表示文件读取完成,例如read()返回-1表示文件读取完成
D:参照A,不论是文本文件还是二进制文件,在计算机中都是以二进制形式存储的,所以都会当作二进制文件读取。

9.Java关键字:

Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等。关键字不能用作变量名,方法名,类名,包名和参数

true和false是boolean的变量值,是编译器赋予特定含义的,但并不是关键字。

2018-7月Java试题整理_第3张图片

10.以下代码将打印出:

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);
}
  • 编译错误
  • true,true
  • true,false
  • false,false

解析:
collection类型的集合(Array List,Linked List)只能装入对象类型的数据,该题中装入了0,是一个基本类型,但是JDK5以后提供了自动装箱与自动拆箱,所以int类型自动装箱变成为Integer类型,编译能够正常通过。
将list1的引用赋值给list2,那么list1和list2都将指向同一个堆内存空间。instanceof是Java关键字,用于判断一个对象是否属于某个特定类的实例,并且返回boolean类型的返回值。显然,list1.get(0)和list2.get(0)都属于Integer的实例。

11.有如下代码,请写出程序的输出结果:

public class Test
{
    public static void main(String[] args)
    {
        int x = 0;
        int y = 0;
        int k = 0;
        for (int z = 0; z < 5; z++) {
            if ((++x > 2) && (++y > 2) && (k++ > 2))
            {
                x++;
                ++y;
                k++;
            }
        }
        System.out.println(x + ”” +y + ”” +k);
    }
}
  • 432
  • 531
  • 421
  • 523

解析:

  1. z=0时候,执行++x > 2,不成立,&&后面就不执行了,此时 x=1,y=0,k=0;
  2. z=1时候,执行++x > 2,还不成立 ,&&后面就不执行了,此时 x=2,y=0,k=0;
  3. z=2时候, 执行++x > 2,成立,继续执行 ++y > 2, 不成立 , &&后面就不执行了, 此时 x=3,y=1,k=0;
  4. z=3时候,执行++x > 2,成立,继续执行++y > 2,不成立 , &&后面就不执行了, 此时 x=4,y=2,k=0;
  5. z=4 时候,执行++x > 2,成立,继续执行 ++y > 2, 成立 , 继续执行k++>2 ,不成立,此时仍没有进入for循环的语句中, 但此时 x=5,y=3,k=1;
  6. z=5时候,不满足条件了,整个循环结束,所以最好打印时候: x=5,y=3,k=1;

12.

八进制,以8为基数,逢8进1.所以8在八进制就是010,前面的0是为了和十进制区分,也叫转译符

7-25

1.应用程序的main方法中有以下语句,则输出的结果

String s1=new String( ” xyz ” );
String s2=new String( ” xyz ” );
Boolean b1=s1.equals(s2);
Boolean b2=(s1==s2);
System .out.print(b1+ ” ” +b2); 
  • true,false
  • false,true
  • true,true
  • false,false

解析:
String s1 = new String( ” xyz ”);//创建String类型的内容为xyz的s1对象
String s2 = new String( ” xyz ”);//创建String类型的内容为xyz的s2对象
Boolean b1 = s1.equals(s2);//比较s1对象和s2对象的内容相等,返回true
Boolean b2 = (s1==s2);//比较s1和s2两个对象的存储地址是否相等,明显两者分别存储在不同的地址,false。

2.下面哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换:

byte[] src,dst;
  • dst=String.fromBytes(src,”GBK”).getBytes(“UTF-8”)
  • dst=new String(src,”GBK”).getBytes(“UTF-8”)
  • dst=new String(“GBK”,src).getBytes()
  • dst=String.encode(String.decode(src,”GBK”)),”UTF-8” )

解析:
先解码在编码
用new String(src,”GBK”)解码得到字符串
用getBytes(“UTF-8”)得到UTF-8编码字节数组

3.关于匿名内部类叙述正确的是

  • 匿名内部类可以继承一个基类,不可以实现一个接口
  • 匿名内部类不可以定义构造器
  • 匿名内部类不能用于形参
  • 以上说法都不正确

解析:
匿名内部类的创建格式为:

new 父类构造器(参数列表)|实现接口(){
          //匿名内部类的类体实现
         }
  1. 使用匿名内部类时,必须继承一个类或实现一个接口
  2. 匿名内部类由于没有名字,因此不能定义构造方法
  3. 匿名内部类中不能含有静态成员变量和静态方法

4.以下声明合法的是

  • default String s
  • public final static native int w()
  • abstract double d
  • abstract final double hyperbolicCosine()

解析:
A:Java的访问权限有public,protected,private和default,default不能修饰变量
C:普通变量不能用abstract修饰,abstract一般修饰方法和类
D:被定义为abstract的类需要被子类继承,但是被修饰为final的类是不能被继承和改写的
native修饰方法简单说就是:一个Java方法调用了一个非Java代码的接口。定义native方法时,并不提供实现体,因为其实现体使用非Java语言在外面实现的。native可以和任何修饰符连用,abstract除外,因为native暗示这个方法是有实现体的,而abstract却显示指明了这个方法没有实现体

5.正确的是:

class Person {
    String name = "No name";
    public Person(String nm) {
        name = nm;
    }
}
class Employee extends Person {
    String empID = "0000";
    public Employee(String id) {
        empID = id;
    }
}
public class Test {
    public static void main(String args[]) {
        Employee e = new Employee("123");
        System.out.println(e.empID);
    }
}
  • 输出:0000
  • 输出:123
  • 编译报错
  • 输出:No Name

解析:
父类没有无参的构造函数,所以子类需要在自己的构造函数中显示调用父类的构造函数。
添加super("nm")否则报错

简单说:子类的构造方法总是先调用父类的构造方法,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类不带参数的构造方法。
而父类没有无参的构造函数,所以子类需要在自己的构造函数中显示的调用父类的构造函数

6.ArrayList list = new ArrayList(20),中list扩充了几次?

  • 0
  • 1
  • 2
  • 3

解析:
ArrayList的构造函数总共有三个:

  1. ArrayList()构造一个初始容量为10的空列表
  2. ArrayList(Collection < ? extends E > c)构造一个包含指定collection的元素的列表,这些元素是按照该collection的迭代器返回它们的顺序排列的
  3. ArrayList(int initialCapacity)构造一个具有指定初始容量的空列表

ArrayList的默认长度为10个,所以如果你往list里添加20个元素肯定要扩容两次(扩充一次是1.5倍,容量是15,还得扩充一次,也就是扩充两次)

7.在Java的多态调用中,new的是哪一个类就是调用的那个类的方法

解析:
Java多态有两种情况:重载和覆写
在覆写中,运用的是动态单分配,是根据new的类型确定对象,从而确定调用的方法
在重载中,运用的是静态单分配,根据静态类型确当对象,因此不是根据new的类型确定调用的方法。
普通方法:运用的是动态单分配,是根据new的类型确定对象,从而确定调用的方法
静态方法:运用的是静态多分派,即根据静态类型确定对象,因此不是根据New的类型确定调用的方法

8.

方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数类型或参数个数,原则如下:

  1. 方法名一定要相同
  2. 方法的参数表必须不同,包括参数的类型或个数,以此区分不同的方法体。
    • 如果参数个数不同,就不管它的参数类型了
    • 如果参数个数相同,那么参数的类型或参数的顺序必须不同
  3. 方法的返回类型,修饰符可以相同,也可不同

9.在Java中,标识符问题:

解析:
标识符由数字,字母和下划线,美元符号组成。在Java中是区分大小写的,而且还要求首位不能是数字。最重要的是,Java关键字不能当作Java标识符。

7-26

1.Java中关于继承的描述正确的是

  • 一个子类只能继承一个父类
  • 子类可以继承父类的构造方法
  • 继承具有传递性
  • 父类一般具有通用性,子类更具体

2.在Java中,下面关于String类和StringBuffer类的描述正确的是哪一个

  • StringBuffer类的对象调用toString()方法将返回String类型的结果
  • 两个类都有append()方法
  • 可以直接将字符串”test”赋值给声明的String类和StringBuffer类的变量
  • 两个类的实例的值都能被修改

解析:
B:String类没有append()方法
C:引用类型只有String可以直接赋值,其他的都要New出来
D:StringBuffer类可以直接改它的内容,不用重新分配地址;String对象/实例,是不可以被改变的。

String:是对象不是原始类型。为不可变对象,一旦被创建,就不能修改它的值。对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。String是final类,即不能被继承

StringBuffer:
是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象。他只能通过构造函数来建立,StringBuffer sb = new StringBuffer();
不能通过赋值符号对他进行赋值。sb = "welcome wo china//error
对象被建立以后,在内存中就会分配内存空间,并初始保存一个null,向StringBuffer中赋值的时候可以通过它的append()方法sb.append("hello");

字符串连接操作中StringBuffer的效率比String高

3.

checked exception:指的是编译时异常,该类异常需要本函数必须处理的,用try和catch处理,或者用throws抛出异常,然后交给调用者去处理异常
runtime exception:指的是运行时异常,该类异常不必须本函数处理,当然也可以处理

4.对抽象类的描述正确的是

  • 抽象类的方法都是抽象方法
  • 一个类可以继承多个抽象类
  • 抽象类不能有构造方法
  • 抽象类不能被实例化

解析:
抽象类有构造方法,但是不能new一个对象

5.Java类成员的访问控制权限

public>protected>default(同包)>private
2018-7月Java试题整理_第4张图片

5.创建数组,数组的命名

简单说:数组命名时名称与【】可以随意排列,但声明的二维数组中第一个中括号中必须要有值,它代表的是在该二维数组中有多少个一维数组
2018-7月Java试题整理_第5张图片

6.

JDK8开始,接口中可以定义有方法体的方法,方法必须被default和Static修饰。除此之外,其他方法都是抽象方法

7.说明输出结果:

package test;
import java.util.Date; 
public class SuperTest extends Date{ 
    private static final long serialVersionUID = 1L; 
    private void test(){ 
       System.out.println(super.getClass().getName()); 
    } 

    public static void main(String[]args){ 
       new SuperTest().test(); 
    } 
}
  • SuperTest
  • SuperTest.class
  • test.SuperTest
  • test.SuperTest.class

解析:
TestSuper和Data的getClass都没有重写,它们都是调用Object的getClass,而Object的getClass作用是返回的是运行时的类的名字。这个运行时的类就是当前类,所以

super.getClass().getName()

返回的是test.SuperTest,与Data类无关
要返回Data类的名字需要写super.getClass().getSuperclass()

getName():包名+类名

7-27

1.对于Java类型变量char c,short s,float f,double d表达式c*s+f+d的结果类型为

  • float
  • char
  • short
  • double

解析:
char 2字节,short 2字节,float 4字节,double 8字节
往精度高的转
低级向高级是隐式类型转换,高级向低级必须强制类型转换
byte < char < short < int < long < float < double

2.关于C++/Java类中static成员和对象成员的说法正确的是?

  • static 成员变量在对象构造时生成
  • static 成员函数在对象成员函数中无法调用
  • 虚成员函数不可能是static 成员函数
  • static 成员函数不能访问static 成员变量

解析:
A:static成员变量是在类加载的时候生成的
B:static成员函数即可以通过类名直接调用,也可以通过对象名进行调用
C:虚函数是C++中的,虚函数不可能是static
D:static成员函数可以访问static成员变量

3.以下关于Java语言异常处理描述正确的有?

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

解析:
A:throws关键字可以在方法上声明该方法要抛出的异常,然后在方法内部通过throw抛出异常对象
B:throw用于抛出异常

4.下面程序输出正确的是:

public class A implements B{
public static void main(String args[]){
    int i;
    A a1=new  A();
    i =a1.k;
    System.out.println("i="+i);
    }
}
interface B{
    int k=10;

}
  • i=0
  • i=10
  • 程序有编译错误
  • i=true

解析:
在接口里面的变量默认都是public static final的,他们都是公共的静态的最终的常量。相当于全局变量,可以直接省略修饰符。实现类可以直接访问接口中的变量。

5.Java异常解析:

2018-7月Java试题整理_第6张图片

都是Throwable的子类:

  1. Exception(异常):是程序本身可以处理的异常
  2. Error(错误):是程序无法处理的错误。这些错误表示故障发生于虚拟机自身,或者发生在虚拟机试图执行应用时,一般不需要程序处理
  3. 检查异常(编译器要求必须处置的异常):除了Error,RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查他,也就是说,当程序中可能出现这类异常,要么用try-catch捕获,要么用throws字句声明抛出它,否则编译不通过。
  4. 非检查异常(编译器不要求处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Rrror)。

6.以下程序的运行结果是:

2018-7月Java试题整理_第7张图片

  • footbar
  • barfoo
  • foobar或者barfoo
  • Bar
  • Foo
  • 程序无法正常运行

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

  1. start()方法来启动线程,真正实现了多线程的运行,这是无需等待run方法体代码执行完毕,可以直接继续执行下面的代码
  2. run()方法当作普通方法的调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可以继续执行下面的代码,这样就没有达到写线程的目的。

7.在Java中,对于不再使用的内存资源,如调用完成的方法,垃圾回收器会自动将其释放

  • 正确
  • 错误

    解析:
    Java虚拟机,对于方法的调用采用的是栈帧(方法调用和方法执行),调用则入栈,完成之后则出栈,是程序自动出栈释放,而不是GC释放
    总结下:
    JVM内存可简单分为三区:

    1. 堆区(Heap):用于存放所有对象,是线程共享的(注:数组也属于对象)
    2. 栈区(Stack):用于存放基本数据类型的数据和对象的引用,是线程私有的(分为:虚拟机栈和本地方法栈)
    3. 方法区(Method):用于存放类信息,常量,静态变量,编译后的字节码等,是线程共享的(也被称为非堆,即None-Heap)

垃圾回收器(GC)主要针对堆区。

7-28

1.given the following code,what will be the output?

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);
   }
}
  • 15,0,20
  • 15,0,15
  • 20,0,20
  • 0,15,20

解析:
引用会改变所指的地址的值,所以second中当v.i=20的时候,就把原来first中的v的i值改为了20.接下来又把v指向了新建的一个对象,所以在second中的v现在指的是新的对象val,i值为15
当执行完second后,在first中再次输出v.i的时候,应为前面second中已经把该位置的i的值改为了20,所以输出是20

7-29

1.

Java一个源程序只能有一个public类存在,且类名与文件名相同。Java程序是从main方法开始执行的,public为类加载器提供入口,然后找到public类中的main方法开始执行。如果存在多个public类,程序将不知道该从哪里执行
注意:内部类可以是public的,因为内部类是作为外部类的成员存在的。

2.如果一个接口Cup有个方法use(),有个类SmallCup实现接口Cup,则在类SmallCup中正确的都是

  • void use() { …}
  • protected void use() { …}
  • public void use() { …}
  • 以上语句都可以用在类SmallCup中

解析:
既然是实现接口,就要实现接口的所有方法,相当于重写方法,方法的重写需要满足:两同两小一大:方法名,参数列表相同;返回类型,抛出异常相同或小;访问权限相同或大。

3.

解析:
wait()必须要进行异常捕获
调用wait()或者notify()方法必须采用当前锁调用,即必须采用synchronized中 的对象

4.下列代码中的变量a,b,c分别在内存的__存储区存放

class A {
    private String a = “aa”;
    public boolean methodB() {
        String b = “bb”;
        final String c = “cc”;
    }
}
  • 堆区,栈区,栈区

解析:
a是类中的成员变量,存放在堆区
b,c都是方法中的局部变量,存放在栈区。

5.为什么有栈内存和堆内存之分?

解析:当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然而然销毁。因此,所有在方法中定义的局部变量都是放在栈内存中的;
在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候回收它。

6.下列关于包(package)的描述正确的是()

  • 包(package)是Java中描述操作系统对多个源代码文件组织的一种方式。
  • import语句将所对应的Java源文件拷贝到此处执行。
  • 包(package)是Eclipse组织Java项目特有的一种方式。
  • 定义在同一个包(package)内的类可以不经过import而直接相互使用。

解析:
A:为了更好地组织类,Java提供了包机制。包是类的容器,用于分隔类名空间,所有的示例都属于一个默认的无名包。Java中的包一般均包含相关的类,Java是跨平台的,所以Java中的包和操作系统没有任何关系,Java的包是用来组织文件的一种虚拟文件系统。
B:import语句并没有将对应的Java源文件拷贝到此处,仅仅是引入,告诉编译器有使用外部文件,编译的时候要去读取这个外部文件
C:Java提供的包机制与IDE没有关系
定义在用一个包(package)内的类可以不经过import而直接相互使用。

7.线程安全的集合类

解析:喂!SHE!
喂——vector
S——stack
H——hashtable
E——Enumeration

8.在Java语言中,下列关于字符集编码和国家化的问题,哪些是正确的?

  • 每个中文字符占用2个字节,每个英文字符占用1个字节
  • 假设数据库中的字符是以GBK编码的,那么显示数据库数据的网页也必须是GBK编码的。
  • Java的char类型,通常以UTF-16 Big Endian的方式保存一个字符。
  • 实现国际化应用常用的手段是利用ResourceBundle类

解析:
A:Java一律采用Unicode编码方式,每个字符无论中英文字符都占两个字节
B:不同的编码之间是可以转换的,如下:
将字符串S以其自身编码方式分解为字节数组,再将字节数组以你想要输出的编码方式重新编码为字符串。
String newUTF8Str = new String(oldGBKStr.getBytes("GBK"),"UTF-8");
C:正确,Java虚拟机中通常使用UTF-16的方式保存一个字符
D:正确,ResourceBundler能够依据Local的不同,选择性的读取与Local对应后缀的properties文件,以达到国际化目的。

9.

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值——每次都会从内存中读取。
而对该变量的修改,volatile并不提供原子性的保证。
由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况
多线程下计数器必须使用锁保护。

7-30

1.下列哪些语句关于Java内存回收的说明是正确的?

  • 程序员必须创建一个线程来释放内存
  • 内存回收程序负责释放无用内存
  • 内存回收程序允许程序员直接释放内存
  • 内存回收程序可以在指定的时间释放内存对象

A:垃圾回收程序是一般在堆上分配空间不够的时候会自己进行一次GC,程序员不需要也不能主动释放内存
B:Java的内存释放由垃圾回收程序进行管理,程序员不能直接进行释放
D:程序员可以调用System.gc()运行垃圾回收器,但不能指定时间。

2.以下代码执行后输出结果为?

public class Test
{
    public static Test t1 = new Test();
    {
         System.out.println("blockA");
    }
    static
    {
        System.out.println("blockB");
    }
    public static void main(String[] args)
    {
        Test t2 = new Test();
    }
 }
  • blockAblockBblockA
  • blockAblockAblockB
  • blockBblockBblockA
  • blockBblockAblockB

解析:
静态成员变量和静态代码块的优先级是相同的,所以,先定义的先执行。
静态块:程序走到静态块的位置就自动执行,且仅执行一次。
构造块:创建类对象(实例化)操作时就加载一次。

3.关于Java和C++的比较,下列哪个错误?

  • Java不支持指针,C/C++支持
  • Java程序不需要显式地关心内存释放,而C/C++需要
  • Java和C++一样,是纯编译型语言,因此它们的class都是在编译时静态联编(static binding)的
  • Java数组、字符串不可能溢出,C/C++数组、字符串则有可能溢出边界

解析:
C:Java不完全算是编译型语言,他编译的字节码文件运行时是解释执行的,其次,Java和C++的类也不都完全是静态绑定的,比如C++的虚函数,Java的父类引用子类对象等情况。
D:Java也可以数组溢出,溢出是会抛出异常,也就是ArrayIndexOutOfBoundsException。

4.代码String str = “123456a”;int i=Integer.parseInt(str);会报异常的是()

  • java.lang.NullPoninterException
  • java.lang.NumberFormatException
  • java.lang.RuntimeException
  • java.lang.ArrayindexOutOfBoundsException

解析:
非纯数字的字符串转换为Integer对象回报数字格式异常

5.

1.基本类型和基本类型封装型进行“==”运算符比较,基本类型封装型会自动拆箱变成基本类型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,显然返回true

 int a = 220;
 Integer b = 220;
 System.out.println(a==b);//true

2.两个Integer类型进行“==”比较,如果其值在-128至127,那么返回true,否则返回false,这跟Integer.valueOf()的缓冲对象有关

Integer c=3;
Integer h=3;
Integer e=321;
Integer f=321;
System.out.println(c==h);//true
System.out.println(e==f);//false

3.两个基本类型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true

Integer a=1;
Integer b=2;
Integer c=3;
System.out.println(c.equals(a+b));//true

4.基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转化为其封装类型,再进行3中的比较

int i=1;
int j = 2;
Integer c=3;
System.out.println(c.equals(i+j));//true

7-31

1.编译Java Application源程序文件将产生相应的字节码文件,这些字节码文件的扩展名为

  • Java
  • class
  • html
  • exe

解析:
Java源程序的后缀名为“.java”
经过编译后生成的字节码文件后缀名为“.class”

2.说法正确的是?

public class Test
{
    public int x;
    public static void main(String []args)
    {
        System. out. println("Value is" + x);
    }
}
  • 程序会打出 “Value is 0”
  • 程序会抛出 NullPointerException
  • 非静态变量不能够被静态方法引用
  • 编译器会抛出 “possible reference before assignment”的错误

非静态成员只能被类的实例化对象引用,因此这里在静态方法中访问x会造成编译错误。
当类加载时,static静态方法随着类加载而初始化,此时实例对象还未被创建,但是非静态非静态成员变量需要等到实例对象创建才会被初始化,故无法被引用

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

  • for循环逐一复制
  • System.arraycopy
  • Arrays.copyOf
  • 使用clone方法

解析:
A:for循环的话,很灵活,但是代码不够简介
B:System。arraycopy()源码。可以看到是native方法:native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C/C++)实现的文件中,
C:本质上是调用arraycopy方法,那么其效率必然是比不上arraycopy的
D:clone的话,返回的是Object【】,需要强制转化

4.关于继承的说法正确的是

  • 子类将继承父类所有的数据域和方法。
  • 子类将继承父类的其可见的数据域和方法。
  • 子类只继承父类public方法和数据域
  • 子类只继承父类的方法,而不继承数据域

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

5.Given the following code:

   import EnclosingOne.InsideOne
1.class Enclosingone
2.{
3.    public class InsideOne {}
4.
5.}
6.public class inertest
7.{
8.    public static void main(string[]args)
9.    {
10.        EnclosingOne eo = new EnclosingOne();
11.        //insert code here
12.    }
13.
14.}

Which statement at line 11 constructs an instance of the inner class?

  • InsideOne ei=eo.new InsideOne();
  • eo.InsideOne ei=eo.new InsideOne();
  • InsideOne ei=EnclosingOne.new InsideOne();
  • 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();//静态内部类对象
    }
}

你可能感兴趣的:(问题总结,Java)