第一题
1.题目:
2.解析:
首先,我们来分析Hello1
类的结构和给定代码的执行流程:
Hello1
类中有两个成员变量,一个静态的a
和一个非静态的b
。静态变量a
属于类本身,而非静态变量b
属于类的每一个实例(对象)。
Hello1
类的构造器对成员变量b
进行了初始化,将其值设置为b+a
。因为a
是静态的,它的值在所有实例之间是共享的。
add
方法分别将a
和b
的值加1。
接下来,我们根据提供的代码段逐步分析:
-
Hello1 h1=new Hello1();
这一步创建了一个Hello1
类的实例h1
。在构造器中,b
的值被初始化为b+a
,即3+3=6
。所以h1.b
的值为6。静态变量a
的值在构造过程中没有被改变,仍然是3。 -
h1.add();
调用h1
对象的add
方法,a
的值加1变为4,h1.b
的值加1变为7。 -
Hello1 h2=new Hello1();
这一步创建了另一个Hello1
类的实例h2
。在构造器中,b
的值再次被初始化为b+a
,但此时a
的值已经是4(因为上一步h1.add()
改变了a
的值),所以h2.b
的值为3+4=7
。静态变量a
的值在构造过程中依然没有被改变,仍然是4。 -
h2.add();
调用h2
对象的add
方法,a
的值再加1变为5,h2.b
的值加1变为8。 -
System.out.println("h1.a="+h1.a+" h2.b="+h2.b);
打印h1.a
和h2.b
的值。因为a
是静态的,所以所有实例共享它的值,这里h1.a
和Hello1.a
以及h2.a
都是5。而h2.b
的值在上一步已经被更新为8。
所以,最终的输出结果为:
h1.a=5 h2.b=8 |
注意:虽然代码中写的是h1.a
,但实际上因为a
是静态的,你也可以直接通过类名Hello1.a
来访问它,结果是一样的。这里写h1.a
只是表明是通过h1
这个对象来访问静态变量a
,但实际上访问的是类级别的变量。
3.收获:
静态变量不会变,非静态变量是每个类的对象
第二题:
1.题目:
2.解析:
在Java中,类的访问权限控制是通过修饰符来决定的。在您提供的代码中,类C有三个成员变量:
private int a=3;
:这个变量是私有的,只能被类C自身访问。double b=4.5;
:这个变量没有明确的访问修饰符,因此它的访问权限是默认的(也称为包级访问权限),意味着它只能被同一个包内的其他类访问。protected int c=5;
:这个变量是受保护的,可以被类C自身、同一个包内的其他类以及子类(无论子类是否在同一个包内)访问。
类D和类C在同一个包(com
)中,因此类D可以访问类C中具有包级访问权限的变量和受保护的变量。
基于上述分析:
- 类D不能访问
a
,因为a
是私有的。 - 类D可以访问
b
,因为b
具有包级访问权限。 - 类D可以访问
c
,因为c
是受保护的。
因此,正确答案是:
C. 不能访问a,可以访问b和c。
3.收获:
private让变量变为私有的
第三题:
1.题目:
2.解析:
执行以下代码:
A a1 = new B(); | |
a1.print(); |
首先,A a1 = new B();
这行代码创建了一个 B
类的实例,并将其引用赋值给了 A
类型的变量 a1
。由于 B
是 A
的子类,所以这是合法的。
接下来,调用 a1.print();
。这里有几个关键点需要注意:
- 变量
a1
的类型是A
,但是实际上它引用的是一个B
类的对象。 - 在 Java 中,如果子类重写(override)了父类的方法,那么当使用子类对象调用该方法时,将执行子类中的方法实现。
- 在这个例子中,
B
类重写了A
类中的print
方法。
因此,当调用 a1.print();
时,实际执行的是 B
类中的 print
方法,而不是 A
类中的 print
方法。
B
类中的 print
方法只打印 a
的值,并没有对其进行自增操作。B
类中的 a
是 B
类自己的成员变量,其值为 5
(由于 int a = 5;
在 B
类中被定义)。
所以,输出结果为:
a=5 |
因此,正确答案是 C. a=5
3.收获:
将子类赋值给父类
A a1 = new B()
第四题:
1.题目:
2.解析:
在Java中,当一个类继承自另一个类时,子类可以通过调用super()
来调用父类的构造函数。这是子类构造函数中初始化父类部分所必需的。
在类B中,构造函数需要调用父类A的构造函数来初始化从A继承的字段a
和b
。由于A的构造函数接受两个int类型的参数,因此需要在B的构造函数中使用super(a, b);
来调用它。
接下来,子类B还需要初始化自己的字段c
,这可以通过this.c = c;
来完成。
因此,完整的B类构造函数应该如下所示:
class B extends A {
private double c;
public B(int a, int b, double c) {
super(a, b); // 调用父类A的构造函数
this.c = c; // 初始化子类B的字段c
}
}
选项A中的super.A(a,b);
是不正确的,因为调用父类构造函数的正确语法是super(参数列表);
,而不是super.类名(参数列表);
。
选项B中的A(a,b);
也是不正确的,因为这不是调用父类构造函数的正确语法。而且,this.b=b;
在这里是多余的,因为父类构造函数已经初始化了b
。
选项C也是错误的,因为它试图通过super(a);
只传递一个参数给父类构造函数,而父类A的构造函数需要两个参数。此外,this.b=b;
同样是多余的。
3.收获:
子类继承父类:使用super函数继承需要的属性
第五题放一放