Java基础查缺补漏04

继续我的复习刷题

接口方法可以使用abstract修饰

问题:

java接口的方法修饰符可以为?(忽略内部接口)

A. private
B. protected
C. final
D. abstract

正确答案: D 你的答案: D (正确)


虽然说接口中的方法都是抽象的,平时不写abstract,但是是可以使用abstract修饰的,例如:

public interface TestInterface {
    abstract void method1();
}

这段代码没有任何问题,但Idea会好心提示:Modifier 'abstract' is redundant for interface methods(即这个修饰符是多余的)

<init>方法是怎么组成的

问题:

在创建派生类对象,构造函数的执行顺序()

A. 基类构造函数,派生类对象成员构造函数,派生类本身的构造函数
B. 派生类本身的构造函数,基类构造函数,对象成员构造函数
C. 基类构造函数,派生类本身的构造函数,派生类对象成员构造函数
D. 对象成员构造函数,基类构造函数,派生类本身的构造函数

正确答案: A 你的答案: C (错误)


这道题我不太理解所谓的对象成员构造函数是什么,后面想了一下应该是指如果成员字段是一个对象的话,调用的构造函数吧。

那么这其实就涉及<init>这个方法的知识点了。

<cinit>这个方法的组成特别好记:就是静态字段赋值和静态代码块从上到下连接构成的。

然而<init>这个方法呢?

// 成员字段的类别
class ChildrenClass {
    public ChildrenClass(){
        System.out.println("成员字段的赋值");
    }
}

class BaseClass{
    public BaseClass(){
        System.out.println("父类的构造函数");
    }

    {
        System.out.println("父类的非静态域");
    }
}

public class TestConstructor2 extends BaseClass{
    public TestConstructor2(){
        System.out.println("自身的构造函数");
    }

    {
        System.out.println("自身的非静态域");
    }

    public ChildrenClass childrenClass = new ChildrenClass();

    public static void main(String[] args) {
        TestConstructor2 constructor2 = new TestConstructor2();
    }
}

先看一下这段代码,输出是什么?

父类的非静态域
父类的构造函数
自身的非静态域
成员字段的赋值
自身的构造函数

再看一下字节码:

---------调用父类的init方法-------------
 0 aload_0
 1 invokespecial #1 <com/rhett/javafoundation/BaseClass.<init>>
---------非静态域方法------------------
 4 getstatic #2 <java/lang/System.out>
 7 ldc #3 <自身的非静态域>
 9 invokevirtual #4 <java/io/PrintStream.println>
---------成员字段的赋值-----------------
12 aload_0
13 new #5 <com/rhett/javafoundation/ChildrenClass>
16 dup
17 invokespecial #6 <com/rhett/javafoundation/ChildrenClass.<init>>
20 putfield #7 <com/rhett/javafoundation/TestConstructor2.childrenClass>
---------自身的构造函数-----------------
23 getstatic #2 <java/lang/System.out>
26 ldc #8 <自身的构造函数>
28 invokevirtual #4 <java/io/PrintStream.println>
31 return

可以看到,顺序是这样的:

  1. 调用父类的方法
  2. 非静态域方法+成员字段的赋值(经实测,这两个的顺序就是代码中书写的顺序从上到下构成的)
  3. 自身的构造函数

字符串相加会触发从字符串常量池中取值吗

题目:

有以下代码片段:

String str1="hello";
String str2="he"+ new String("llo");
System.out.println(str1==str2);

请问输出的结果是:

A. true
B. 都不对
C. null
D. false

正确答案: D 你的答案: A (错误)


字符串字面量的机制,我已经在String s = new String("123");创建了几个String对象?中谈过了,然而这道题目我还是选错了,主要是没有认真思考,像这样的字符串加法,是不存在编译时优化的,内部机制还是通过使用StringBuilder去实现的字符串拼接,最终结果和字符串常量池中的对象肯定是不同的。

那什么情况下会出现编译时优化呢?就是修改为下面这段代码:

String str1="hello";
String str2="he"+"llo";
System.out.println(str1==str2);

就会输出为true了。

Java的自动转型规则

题目:

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);

下列代码片段中,存在编译错误的语句是()

A. 语句2
B. 语句1
C. 语句3
D. 语句4

正确答案: B C D 你的答案: D (错误)


这道题涉及一个知识点,我之前确实不知道:(来自牛客网用户:Pandora)

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

第一点这个规则大概是因为没有对应的字节码操作指令,但我确实不知道会自动转为int。

因此:

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

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e5%9f%ba%e7%a1%80%e6%9f%a5%e7%bc%ba%e8%a1%a5%e6%bc%8f04/

发表评论

电子邮件地址不会被公开。