1、下面有关java实例变量,局部变量,类变量和final变量的说法,错误的是?
A. 实例变量指的是类中定义的变量,即成员变量,如果没有初始化,会有默认值。
B. 局部变量指的是在方法中定义的变量,如果没有初始化,会有默认值
C. 类变量指的是用static修饰的属性
D. final变量指的是用final 修饰的变量
答案: B
解析:
- 定义在类中的变量是类的成员变量,也叫实例变量,可以不进行初始化,Java 会自动进行初始化。如果是基本数据类型,如 int,则会默认初始化为 0;如果是引用数据类型,默认初始化为 null。
- 局部变量是定义在方法中的变量,Java 虚拟机不会对其进行初始化,所以编程者必须在使用该变量之前给它赋值,否则编译时会报错。
- 被 static 关键字修饰的变量是静态的,静态变量随着类的加载而加载,所以也被称为类变量。
- 被 final 修饰的变量是常量。
2、关于下面的程序 Test.java 说法正确的是( )。
public class Test {
static String x = "1";
static int y = 1;
public static void main(String args[]) {
static int z = 2;
System.out.println(x + y + z);
}
}
A. 3
B. 112
C. 13
D. 程序有编译错误
答案: D
解析:
static int z = 2; 报错。被 static 修饰的变量称为静态变量,也叫类变量,属于整个类;而局部变量属于方法,只在该方法内有效,所以不能用 static 修饰局部变量。
另外,对比下面的几句代码,
System.out.println(1 + 2 + "3");// 33
System.out.println(1 + (2 + "3"));// 123
System.out.println("1" + 2 + 3);// 123
System.out.println(1 + "2" + 3);// 123
如果没有括号,系统会按照从左到右的顺序依次执行 “+” 运算。因此 1+2+“3” 会先执行1+2,其结果 3 再与 “3” 相加,即为 33。
3、说明程序输出结果。
package algorithms.com.guan.javajicu;
public class Inc {
public static void main(String[] args) {
Inc inc = new Inc();
int i = 0;
inc.fermin(i);
i= i ++;
System.out.println(i);
}
void fermin(int i){
i++;
}
}
A. 0
B. 1
C. 2
D. 3
答案: A
解析:
首先,i++ 也是一个表达式,是有返回值的,返回值就是 i 自增前的值。因此执行 i = i++ 后,虽然 i 自增为 1,但是 i++ 的返回值(0)又给 i 重新赋值了;
其次,fermin(int i) 方法的形参 i 只在方法内有效,改变的是方法自己的 i,不会影响方法外的 i 。
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;
}
}
}
A. return value of getValue(): 1
B. return value of getValue(): 0
C. return value of getValue(): 0return value of getValue(): 1
D. return value of getValue(): 1return value of getValue(): 0
答案: A
解析:
根据官方的JVM规范:
如果 try 语句里有 return,返回的是 try 语句块中的变量值。
详细执行过程如下:
- 如果有返回值,就把返回值保存到局部变量中;
- 执行 jsr 指令跳到 finally 语句里执行;
- 执行完 finally 语句后,返回之前保存在局部变量表里的值。
如果 try,finally 语句里均有 return,忽略 try 的 return,而使用 finally 的 return。
5、非抽象类实现接口后,必须实现接口中的所有抽象方法,除了abstract外,方法头必须完全一致.
正确
错误
答案: 错误
解析:
方法头指:修饰符+返回类型 +方法名(形参列表)
关于接口和其实现类,有两同两小一大原则:
- 方法名相同;
- 参数类型相同;
- 子类返回类型小于等于父类方法返回类型;
- 子类抛出异常小于等于父类方法抛出异常;
- 子类访问权限大于等于父类方法访问权限。
6、有如下一段代码,请选择其运行结果()
public class StringDemo{
private static final String MESSAGE="taobao";
public static void main(String [] args) {
String a ="tao"+"bao";
String b="tao";
String c="bao";
System.out.println(a==MESSAGE);
System.out.println((b+c)==MESSAGE);
}
}
A. true true
B. false false
C. true false
D. false true
答案: C
解析:
这题是在考编译器的优化,hotspot 中编译时 “tao”+“bao” 将直接变成 “taobao”,b+c 则不会优化,因为不知道在之前的步骤中 bc 会不会发生改变,而针对 b+c 则是用语法糖,新建一个 StringBuilder 来处理。
7、下面代码的输出是什么?
public class Base
{
private String baseName = "base";
public Base()
{
callName();
}
public void callName()
{
System. out. println(baseName);
}
static class Sub extends Base
{
private String baseName = "sub";
public void callName()
{
System. out. println (baseName) ;
}
}
public static void main(String[] args)
{
Base b = new Sub();
}
}
A. null
B. sub
C. base
答案: A
解析:
本题与内部类没有关系。
- 执行 Base b = new Sub();时,由于多态 b 编译时表现为 Base 类特性,运行时表现为 Sub 类特性,所以 Base b = new Sub();不管是哪种状态都会调用 Base 构造器执行 callName() 方法;
- 执行方法时,由于多态表现为子类特性,所以会先在子类是否有 callName();
而此时子类尚未初始化(执行完父类构造器后才会开始执行子类),如果有就执行,没有再去父类寻找。
8、假定Base b = new Derived(); 调用执行b.methodOne()后,输出结果是什么?
public class Base
{
public void methodOne() // (2)
{
System.out.print("A");
methodTwo();
}
public void methodTwo() // (4)
{
System.out.print("B");
}
}
public class Derived extends Base
{
public void methodOne() // (1)
{
super.methodOne();
System.out.print("C");
}
public void methodTwo() // (3)
{
super.methodTwo();
System.out.print("D");
}
}
A. ABDC
B. AB
C. ABCD
D. ABC
答案: A
解析:
用多态创建子类对象(向上转型),则在调用一个父类的被子类重写的方法时,不管是在子类中调用还是在父类中调用,不被 super 调用都是调用子类方法,只有用 super 调用时才是调用父类的方法。上面代码执行的调用顺序如注释所示。
9、在开发中使用泛型取代非泛型的数据类型(比如用ArrayList取代ArrayList),程序的运行时性能会变得更好。()
A. 正确
B. 错误
答案: B
解析:
泛型仅仅是 Java 的语法糖,它不会影响 Java 虚拟机生成的汇编代码,在编译阶段,虚拟机就会把泛型的类型擦除,还原成没有泛型的代码,顶多编译速度稍微慢一些,执行速度是完全没有什么区别的。
10、对文件名为 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);
}
}
A. 输出:0000
B. 输出:123
C. 编译报错
D. 输出:No name
答案: C
解析:
子类的构造方法总是先调用父类的构造方法。如果子类的构造方法没有显式地调用父类的构造方法,那么默认调用父类地无参构造方法。
本题中,父类没有无参构造方法,所以子类需要在自己的构造方法中显式地调用父类的构造方法,不然编译器会报错。