那些暗藏杀机的java基础题
一、有Test1,Test2类定义如下:
public class Test1 {
protected int method1(int a, int b){
return 222;
}
public static void main(String[] args) {
System.out.println(new Test2().method1(1,1));
}
}
class Test2 extends Test1{
//插入代码
}
请问下面插入Test2中合法的代码的是( )
A. public int method1(int a, int b){return 0;} //重写。输出0
B. private int method1(int a, int b){return 0;} //想重写但是降低了访问权限。编译错误
C. private int method1(int a, long b){return 0;} //重载。输出222
D. private short method1(int a, long b){return 0;}//重载。输出222
E. static protected int method1(int a,int b){return 0;} //非静态方法不能重写为静态方法,反之亦然,编译错误
答案:
ACD
这一道题其实考察了好几个java基础知识点:
面向对象的特性:封装,继承,多态,抽象(这里没有考到)
- 封装:java 权限修饰词从低到高分别是:private default protected publiic
当前类使用 | 同一个包的其他类使用 | 不同包的子类使用 | 不同包的非子类使用 | |
---|---|---|---|---|
private | √ | |||
default | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
-
继承:
-
- java 的 extends 关键字只能有一个父类,仅支持单继承
-
- 子类只继承父类中的非private 成员变量
-
- 子类成员变量和父类成员变量同名时,子类成员变量被覆盖
-
- 子类只继承父类中的非private 成员方法
-
- 子类成员方法和父类的成员方法同名时,父类成员方法被子类成员方法覆盖
-
-
多态:重载和重写
-
- 重载:同一类中,同名方法的参数个数不同 或 参数类型不同,或 参数的顺序不同。(注意:只有返回值不同不算重载)
-
- 重写(方法覆盖):子类重写的方法与父类的方法要具有相同方法名,相同方法参数,相同返回类型
- 子类覆盖方法不能缩小父类方法的访问权限(子类成员方法应当比起父类对应的成员方法具有相同或者更高的访问控制方式)
- 同一个类中方法只能被重载,不能被覆盖
- 父类的静态方法不能被子类覆盖为非静态方法,反之亦然
- 父类的私有方法不能被覆盖(继承的特性很清楚了)
- final修饰的方法不能被覆盖
- (补充一个点:平常我们重写代码时加的注解@Override,不是一个强制需要的注解,也就是说,没有这个注解的话,代码依旧能够实现重载)
-
二、下面代码运行后输出结果为:
public class Test1 {
static public char c = 65;
public static void main(String[] args){
switch (c){
default:
System.out.print("default");
break;
case 'A':
System.out.print('A');
case 'B':
System.out.print("B");
break;
case 'C':
System.out.print("C");
break;
}
}
}
答案:
AB
这一道题考点如下:
- switch 后面支持的内容:byte、char、short、int、枚举,String(jdk1.7加入)。
- default 选项在于case找不到匹配时执行,并且会往下执行。(题目中:如果default没有break语句,并且c 不为ABC中一个 ,将会输出defaultAB)
- ASSIC码的常用范围:6590对应大写的AZ, 97122对应小写的AZ
三、下面代码运行后输出结果为:
public class Test1 extends Thread{
static String s = "Hello";
public static void main(String[] args) {
Test1 t = new Test1();
t.say(" in Main");
System.out.println(s);
}
public void say(String s){ //入参的 s = " in Main"
s = s + " in Say"; // 本行执行完毕 s = " in Main in Say",这里的s是可以理解为形参,不是静态变量那个s
start();
}
public void run(){
for (int i = 1; i < 5; i++){
s = s + " " + i;
}
System.out.println(s);
}
}
答案:
Hello
Hello 1 2 3 4
这道题考点如下:
-
java中的值传递和引用传递 & 赋值运算符(=)的作用:
这里可以去看一下问题的高赞回答 Java 到底是值传递还是引用传递? -
static关键字:修饰的类成员(变量和方法),在各个类的实例之间都是共享的,都指向同一块内存。static修饰的变量会存在JVM的 静态存储区 中。因为共享一份内存,所以static变量值一旦被修改,则其他对象均对修改可见,故不是线程安全。
(平常我们使用经常是加上final static 来定义一个常量,并且也是通过类名来引用该常量,可能会忽略了其实也可以通过实例来引用static变量和方法)- 静态方法中不能访问非静态变量和方法
- 静态方法中不能使用super和this关键字
-
for循环语句的执行顺序,这个主要是考你看题细不细心。
四、下面代码运行后输出结果为
public class Test1 {
{
System.out.println(i);
}
static int i = 5;
static {
Test1 t = new Test1(); //①
t.i = 8;
i = i + 10;
}
static {
i = i/5;
}
public static void main(String[] args) {
A ab = new B(); //②
ab = new B(); //③
System.out.println(Test1.i + (new Test1().i >4 ? 11.0 :16)); //④
}
}
class A {
static {
System.out.print("A");
}
public A(){
System.out.print("a");
}
{
System.out.print("1");
}
}
class B extends A{
static {
System.out.print("B");
}
public B(){
System.out.print("b");
}
{
System.out.print("2");
}
}
答案:
5
AB1a2b1a2b3
19.0
这题主要考的是Java中代码的执行顺序,涉及到的有:
静态代码块(在类加载的时候执行),非静态代码块,子类构造方法,父类构造方法。
答案解析:
- 代码①:
- 首先执行的是Test1的静态代码块①,但是由于①用到了Test1的构造函数,进行了实例化。所以此时会执行Test1的非静态代码块(非静态代码块在类实例化的时候会被调用,并且是在构造方法之前调用),输出此时的i,也就是5。
- 当Test1的静态代码块执行完的时候,i经历了5->8->18->3这样一个变化。进入main方法前i的值为3
然后就开始执行main方法。
- 代码②:
- 这里加载类的时候,首先加载了父类A,再加载了子类B,静态代码块在加载的时候执行,因此会先输出AB。
- 然后在实例化B的时候,子类B有构造方法,创建子类对象时,先执行父类的构造方法,再执行子类的构造方法。因此这时候先执行A的构造方法(先实例化A),但是A中还有非静态代码块,所以要在A的构造方法前先执行。因此这里输出1a
- 然后实例化B,输出2b
- 代码③:
- 由于静态代码块只会在类加载的时候执行一次 ,所以这个时候只会输出实例化A和B,不会去执行A和B的静态代码块,输出1a2b
- 代码④:
- 括号里有new Test1(),所以会执行代码①,也就是输出此时i的值3。
- 剩下的就是三目运算符的判断了,3 + 16.0就是19.0,这里要注意的是int隐式转换成double类型(默认小数类型)。?右边有double和int两个类型,则默认结果是强类型double
总的来说执行顺序是:
静态代码块->非静态代码块->构造方法
实例化子类时:
父类静态代码块->子类静态代码块->父类非静态代码块->子类非静态代码块->父类构造方法->子类构造方法
拓展:
构造方法的继承性:
- 按继承关系,构造按方法是从顶向下调用的
- 如果子类没有构造方法,将默认调用父类的无参构造方法。如果父类没有无参构造方法,则报错
- 如果子类有构造方法,那么创建子类对象的时候,先执行父类的构造方法,再执行子类的构造方法
- 如果子类有构造方法,但是子类的构造方法中没有使用super关键字,则系统默认执行该构造方法时会产生super()代码,即构造方法会调用父类无参构造方法
- 对于父类中包含参数的构造方法,子类可以通过在自己的构造方法中使用super来引用,而且必须是子类构造方法中的第一条语句
五、下面代码运行后输出结果为
public class Test1 {
public static void main(String[] args) {
StringBuffer a = new StringBuffer("a");
StringBuffer b = new StringBuffer("b");
operte(a,b);
System.out.println(a+","+b);
}
private static void operte(StringBuffer m, StringBuffer n) {
m.append(n);
n = m;
}
}
答案:
ab,b
考点: 这里其实和第三题的内容有些想象,考的是java中的引用传递和赋值运算符=的作用。具体可以看第三题的解析
六、下面代码运行后输出结果为:
public class Test1 {
static boolean show(char c){
System.out.print(c);
return true;
}
public static void main(String[] args) {
int i=0;
for (show('A');show('B') && (i<2);show ('C')){
i++;
show('D');
}
}
}
答案:
ABDCBDCB
这题主要也是考对for语句的熟悉程度,还有要看清符号。