Java面试 4.2 面向对象(7-10)

4.2.7 重载和覆盖有什么区别

重载(overload)和覆盖(override)是 Java 多态性的不同表现方式。其中,重载是在一个类中多态性的一种表现,是指在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型。在使用重载时,需要注意以下几点:

1)重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序。

2)不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。

3)对于继承来说,如果基类方法的访问权限为 private,那么就不能在派生类对其重载;如果派生类也定义了一个同名的函数,这只是一个新的方法,不会达到重载的效果。

覆盖是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。在使用覆盖时需要注意以下几点:

1)派生类中的覆盖方法必须要和基类中被覆盖的方法有相同的函数名和参数。

2)派生类中的覆盖方法的返回值必须和基类中被覆盖白方法的返回值相同。

3)派生类中的覆盖方法所抛出的异常必须和基类(或是其子类)中被覆盖的方法所抛出的异常一致。

4)基类中被覆盖的方法不能为 private,否则其子类只是定义了一个方法,并没有对其覆盖。

重载与覆盖的区别主要有以下几个方面:

1)覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。

2)覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。

3)覆盖要求参数列表相同;重载要求参数列表不同。

4)覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。

4.2.8 抽象类(abstract class)与接口(interface)有什么异同

只要包含一个抽象方法的类就必须被声明为抽象类,抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。在实现时,必须包含相同的或者更低的访问级别(public→protected→private)。抽象类在使用的过程中不能被实例化,但是可以创建一个对象使其指向具体子类的一个实例。抽象类的子类为父类中的所有抽象方法提供具体的实现,否则它们也是抽象类。接口可以被看作抽象类的变体。接口中的所有方法都是抽象的,可以通过接口来间接地实现多重继承。接口中的成员变量都是 static final 类型。由于抽象类可以包含部分方法的实现,因此,在一些场合下抽象类比接口存在更多的优势。

接口与抽象类的相同点如下:

1)都不能被实例化。

2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能被实例化。

接口与抽象类的不同点如下:

1)接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。

2)接口需要实现(用 implements),但抽象类只能被继承(用 extends)。一个类可以实现多个接口,但一个类只能继承一个抽象类,因此使用接口可以间接地达到多重继承的目的。

3)接口强调特定功能的实现,其设计理念是「has-a」关系;而抽象类强调所属关系,其设计理念为「is-a」关系。

4)接口中定义的成员变量默认为 public static final,只能够有静态的不能被修改的数据成员,而且,必须给其赋初值,其所有成员方法都是 public、abstract 的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而且,抽象类中的成员变量默认为 default(本包可见),当然也可以被定义为 private、protected 和 public,这些成员变量可以在子类中被重新定义,也可以被重新赋值,抽象类中的抽象方法(其前有 abstract 修饰)不能用 private、static、synchronized、native 等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。所以,当功能需要累积时,用抽象类;不需要累积时,用接口。

5)接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。

简单点说,接口是一种特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作,但一般而言,抽象类多用于在同类事物中有无法具体描述的方法的场景,所以当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;而接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。

此外,接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的 main 方法。

常见笔试题:

1.下列关于接口的定义中,正确的是( )。

A.void methoda();B.public double methoda();

C.public final double methoda();D.static void methoda(double d1);

E.protected void methoda(double d1);F.int a;

G.int b=1;

答案:A、B、G。从上面的分析可知,接口中的方法只能用关键字 public 和 abstract 来修饰,因此选项 C、D、E 都是错误的。接口中的属性默认都为 public static final,由于属性被 fi-nal 修饰,因此它是常量,常量在定义时就必须初始化,因此 F 是错误的。

2.下列说法中,正确的是( )。

A.声明抽象方法大括号可有可无 B.声明抽象方法不可写出大括号

C.抽象方法有方法体 D.abstract 可修饰属性、方法和类

答案:B。抽象方法不能有方法体,同理也就不能有大括号。abstract 只能用来修饰类与方法,不能用来修饰属性。


4.2.10 如何获取父类的类名

Java 语言提供了获取类名的方法:getClass().getName(),开发人员可以调用这个方法来获取类名。

代码如下(示例 1)所示:

通过以上这个例子的运行结果是否可以得出一个结论:通过调用父类的 getClass().getName()方法来获取父类的类名是可行的呢?为了解答这个问题,首先来做一个实验,给出下面的程序(示例 2)。

为什么输出的结果不是「A」而是「Test」呢?主要原因在于 Java 语言中任何类都继承自 Object 类,getClass()方法在 Object 类中被定义为 final 与 native,子类不能覆盖该方法。因此 this.getClass()和 super.getClass()最终都调用的是 Object 中的 getClass()方法。而 Ob-ject 的 getClass()方法的释义是:返回此 Object 的运行时类。由于在示例 2 中实际运行的类是 Test 而不是 A,因此程序输出结果为 Test。

那么如何才能在子类中得到父类的名字呢?可以通过 Java 的反射机制,使用 getClass().getSuperclass().getName(),代码如下(示例 3)所示:


4.2.11 this 与 super 有什么区别

在 Java 语言中,this 用来指向当前实例对象,它的一个非常重要的作用就是用来区分对象的成员变量与方法的形参(当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量)。

为了能够对 this 有一个更好的认识,首先创建一个类 People,示例如下:

super 可以用来访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同名字时也会覆盖父类的方法或成员变量,要想访问父类的方法或成员变量只能通过 super 关键字来访问。

程序运行结果为:

Sub:f()

Base:f()

发布了105 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_40993412/article/details/104072442
4.2
今日推荐