大家好!今天我继续回顾 Java 开发者面试问题。
29. return 可以在构造函数中使用吗?
是的,但只有return关键字右侧没有值。您可以使用返回;作为构造函数中的辅助语句,用于紧急终止(中断)进一步代码的执行并完成对象的初始化。例如,假设我们有一个Cat类,如果一只Cat无家可归(isHomeless = true,那么我们想要终止初始化并且不填写其他字段(毕竟,它们对我们来说是未知的,因为猫无家可归) :public Cat(int age, String name, boolean isHomeless) {
if (isHomeless){
this.isHomeless = isHomeless;
return;
}
this.isHomeless = isHomeless;
this.age = age;
this.name = name;
}
但如果我们谈论的是具体值,那么return关键字就不能返回特定值,因为:
- 当你声明一个构造函数时,你不会有像返回类型这样的东西;
- 通常,构造函数在实例化期间被隐式调用;
- 构造函数不是方法:它是一个单独的机制,其唯一目的是初始化实例变量,即我们使用 new运算符来创建对象。
30. 构造函数可以抛出异常吗?
构造函数处理异常的方式与方法相同。方法允许我们通过在方法头中写入throws <ExceptionType>来抛出异常。构造函数允许我们做同样的事情。当我们继承并定义子类的构造函数时,我们可以扩大异常类型 - 例如,IOException -> Exception(但反之则不然)。让我们使用Cat类的构造函数作为构造函数抛出异常的示例。假设当我们创建一个对象时,我们想从控制台输入名称和年龄:public Cat() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
this.name = reader.readLine();
this.age = Integer.parseInt(reader.readLine());
}
由于reader.readLine()抛出 IOException,我们将其作为可能抛出的异常写入标头中。
31. 类头的元素是什么?写一个例子
为了说明构成类头的元素,让我们看一个小模式:- 强制元素出现在括号 <> 中
- 可选元素位于 {} 中
public final class Lion extends Cat implements WildAnimal
32. 方法头的元素是什么?写一个例子
在考虑构成方法头的元素时,让我们再次考虑一个小模式:- 强制元素出现在括号 <> 中
- 可选元素位于 {} 中
public static void main(String[] args) throws IOException
33. 如果基类中尚未定义默认构造函数(但定义了不同的构造函数),则在子类中创建默认构造函数
我不确定我完全理解这个问题,但这也许意味着我们在父类中有一些像这样的构造函数:public Cat(int age, String name) {
this.age = age;
this.name = name;
}
在这种情况下,在父类中,我们肯定需要定义一个构造函数来初始化父类(即调用父构造函数):
public class Lion extends Cat {
public Lion(int age, String name) {
super(age, name);
}
}
34.什么时候使用this关键字?
在 Java 中,这有两种不同的含义。1. 它是对当前对象的引用,例如this.age = 9。也就是说,this指的是使用它的对象以及带有this 的代码所指的对象。主要目的是提高代码可读性并避免歧义。例如,如果实例字段和方法参数具有相同的名称:public void setName(String name) {
this.name = name;
}
也就是说,this.name是对象的字段,而name是方法参数。this引用不能在静态方法中使用。2. 在构造函数中,this可以像方法一样被调用,例如this(value)。在这种情况下,它将调用同一类的另一个构造函数。基本上,您可以在创建对象的过程中调用两个构造函数:
public Cat(int age, String name) {
this(name);
this.age = age;
}
public Cat(String name) {
this.name = name;
}
当调用第一个构造函数创建Cat对象时,两个实例字段都将成功初始化。这里有一些细微差别:
- this()仅适用于构造函数。
- 对另一个构造函数的引用必须位于构造函数块(主体)的第一行。这意味着构造函数不能调用其类的多个(其他)构造函数。
35.什么是初始化器?
据我了解,这个问题是关于普通和静态初始化块的。让我们首先记住什么是初始化。初始化是字段的创建、激活、准备和定义。准备程序或组件以供使用。你会记得,当你创建一个对象时,类变量可以在声明时立即初始化:class Cat {
private int age = 9;
private String name = "Tom";
或者通过构造函数事后设置:
class Cat {
private int age;
private String name;
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
但还有另一种方法:您可以使用初始化块设置实例变量,该初始化块在类中 采用大括号{} 的形式,没有名称(如无名方法或构造函数):
class Cat {
private int age;
private String name;
{
age = 10;
name = "Tom";
}
初始化块是创建对象时加载的一段代码。此类块通常用于执行加载类时所需的某些复杂计算。这些计算的结果可以设置为变量的值。除了普通的初始化块之外,还有静态的初始化块。它们看起来相同,但在左大括号前面 有static关键字:
class Cat {
private static int age;
private static String name;
static{
age = 10;
name = "Tom";
}
此块与前一个块相同。但是,如果普通对象在初始化每个对象时执行,则静态对象仅在类加载时执行一次。通常,某些复杂的计算是在静态块中执行的,用于初始化静态类变量。同样的限制也适用于静态方法的静态块:不能使用非静态数据,例如静态块中 对当前对象 ( this ) 的引用。现在我们可以查看类(及其父类)的初始化顺序,以便更好地理解何时调用初始化块。
36.给定一个扩展Parent的公共Child类,写出该对象的初始化顺序
当加载Child类时,初始化顺序如下:- 父类的静态类字段。
- 父类的静态初始化块。
- Сchild类的静态字段。
- Child类的静态初始化块。
- 父类的非静态字段。
- 父类的非静态初始化块。
- 父类构造函数。
- Сhild类的非静态字段。
- Сhild类的非静态初始化块。
- Сchild类的构造函数。
37.你知道类(对象)之间有哪些关系?
Java 中有两种变量:原始类型和对成熟对象的引用。- IS-A关系
Lion IS-A Cat
(但不是每只猫都是狮子)接口也存在同样的情况。如果Lion类实现了WildAnimal接口,那么它们也存在关系:
Lion IS-A WildAnimal
- HAS-A关系
Car HAS-A Passenger
反之亦然:如果Passenger引用了Car,那么关系如下:
Passenger HAS-A Car
38.你知道哪些关联对象关系?
聚合和组合只不过是关联的特殊情况。 聚合是一种关系,其中一个对象是另一个对象的一部分。例如,乘客可能位于汽车内。更重要的是,可能有多名乘客,或者根本没有乘客(如果我们谈论的是特斯拉,可能没有司机)。例如:public class Car {
private List passengers = new ArrayList<>();
void setPassenger(Passenger passenger) {
passengers.add(passenger);
}
void move() {
for (Passenger passenger : passengers) {
System.out.println("Transporting passenger - " + passenger.toString());
}
passengers.clear();
}
}
换句话说,乘客数量(任何数量)对我们来说并不重要:Car类的功能不依赖于此。聚合还意味着当另一个对象使用一个对象时,第一个对象可以被其他对象使用。例如,同一个学生可能同时参加针织俱乐部和摇滚乐队,并同时参加西班牙语课程。正如你可以想象的,聚合是类之间更松散的关联关系。 组合是一种更紧密的关系,其中一个对象不仅是另一个对象的一部分,而且一个对象的工作非常依赖于另一个对象。例如,汽车有发动机。发动机可以在没有汽车的情况下存在,但离开汽车就毫无用处。没有发动机汽车就无法工作:
public class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
void startMoving() {
engine.start();
...
}
组合还意味着当另一个对象使用一个对象时,第一个对象不能属于任何其他对象。回到我们的例子,一台发动机只能属于一辆汽车,不能同时属于两辆或更多汽车。我想今天的内容就足够了,所以我们就到此为止。
GO TO FULL VERSION