- 例1:下面哪一项说法是正确的?
A.在一个子类中,一个方法不是public的就不能被重载
B.覆盖一个方法只需要满足相同的方法名和参数类型就可以了
C.覆盖一个方法必须要有相同的方法名参数和返回类型
D.一个覆盖的方法必须有相同的方法名、参数名和参数类型
答:答案是C。对于在同一个可访问区内被声明的几个具有不同的参数列(参数的类型、个数、顺序不同)的同名函数,程序会根据不同的参数列来确定具体调用哪个函数,这种机制即使重载,重载不关心函数的返回值。覆盖是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须同父类中对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同,当派生类对象调用子类中该同名函数时会自动调用子类中覆盖版本,而不是父类中的被覆盖的函数版本。
- 重载的特征:
(1)相同的范围(在同一个类中)
(2)函数名字相同
(3)参数不同 - 覆盖的特征:
(1)不同的范围(分别位于父类和子类)
(2)函数名字相同
(3)参数相同
- 例2:关于函数重载,下列说法错误的是?
A.重载函数的函数名必须相同
B.重载函数必须在参数个数或类型上有所不同
C.重载函数的返回值必须相同
D.重载函数的函数体可以有所不同
答:答案是C。重载是指编写一个与已有函数同名但是参数表不同的函数,函数的重载与函数的返回值是无关的。
- 例3:下面的说法中哪项是正确的?
A.静态方法不能被覆盖成非静态的方法
B.静态方法不能被声明成私有的
C.私有的方法不能被重载
D.一个重载的方法在父类中不通过检查不能抛异常
答:此题选A。静态方法是不能被覆盖的。
- 例4:关于继承表述错误的是?
A.继承是一种通过扩展一个已有对象的实现,从而获得新功能的复用方法
B.父类可以显示地捕捉那些公共属性和方法;子类则通过附加属性和方法来进行实现的扩展
C.继承会破坏封装性,因为会将父类的实现暴露给子类
D.继承本质上是“黑盒复用”,对父类的修改不会影响到子类
答:此题选D。继承是指子类的对象可以使用仅对父类的对象有效的方法或者属性,它使得这些方法和属性就好像是由子类自己定义的一样。在继承结构中,父类的内部细节对子类是可见的。所以,通过继承的代码复用是一种“白盒复用”。
- 例5:下面的代码输出?
public class B extends A {
public static void prt() {
System.out.println("2");
}
public B() {
System.out.println("B");
}
public static void main(String[] args) {
A a = new B();
a = new A();
}
}
class A {
public static void prt() {
System.out.println("1");
}
public A() {
System.out.println("A");
}
}
说明:这里要注意的是,静态方法我们需要调用才会执行。而在构造B
对象时,由于B
继承A
,所以先需要执行A
的构造方法。
- 例6:下列代码的输出结果是?
class ClassA {
public void printValue(){
System.out.println("classA");
}
}
class ClassB extends ClassA{
public void printValue(){
System.out.println("classB");
}
}
public class Test{
public static void main(String[] args) {
ClassB objectB = new ClassB();
objectB.printValue();//这里是对象objectB调用的方法,当然是输出classB
ClassA as = (ClassA) objectB;
as.printValue();//这里as本来就是ClassB的一个实例,当然也是输出ClassB
as = new ClassA();
as.printValue();//这里才是ClassA调用方法,输出classA
}
}
说明:相关的说明在代码中已经写明。
- 例7:下面代码输出是?
public class Test{
public static void main(String[] args) {
Father father = new Father();
Father child = new Child();
System.out.println(father.getName());
System.out.println(child.getName());
}
}
class Father{
public static String getName(){
return "Father";
}
}
class Child extends Father{
public static String getName(){
return "Child";
}
}
答:这里输出 Father Father
。这里要注意,静态方法是不能覆盖的,同时它们在内存中的地址空间是固定的,而这里的两个静态方法在内存中占用不同的空间,至于具体执行哪一个,则要看是由哪个类来调用的,因为是静态方法,而且两个引用都是father
对象的,所以输出 Father Father
。
例8:下面代码的运行结果?
public class Tester{
public static void main(String[] args) {
go(new MyBase());
}
public static void go(Base b){
b.add(8);
}
}
class Base{
int i ;
Base(){
add(1);
System.out.println(i);
}
void add(int v){
i += v;
System.out.println(i);
}
void print(){
System.out.println(i);
}
}
class MyBase extends Base{
public MyBase() {
add(2);
}
void add(int v){
i += v * 2;
System.out.println(i);
}
}
说明:首先实例化对象MyBase
,而此对象继承Base
对象,所以首先执行方法MyBase()
,于是先执行方法add
,但是要注意的是这个方法是在新建MyBase
对象时调用的,将会首先查找MyBase
类中是否有此方法,所以首先打印出的是2,2。此时父类的构造函数运行完毕,执行子类的构造函数,于是i=6
。之后再执行add
方法,所以输出22。
例9:匿名内部类(
Anonymous Inner Class
)是否可以extends
其他类,是否可以implements
其他接口?
答:匿名内部类是没有名字的内部类,不能继承其他类,但是一个内部类可以作为一个接口,由另一个内部类实现。例10:下列关于抽象类说法错误的是?
A.抽象类中可以不存在任何抽象的方法
B.抽象类可以被抽象类所继承,结果仍然是抽象类
C.抽象类不能同时又是密封的
D.如果一个非抽象类从抽象类中派生,不一定要通过覆盖来实现抽象成员的继承
E.抽象类允许被申明
说明:一个抽象类要注意一下几点:
(1)抽象类只能作为其他类的父类,它不能被实例化,而且对抽象类不能使用
new
操作符。抽象类如果含有抽象的变量或值,则它们要么是null
类型,要么包含了对非抽象类的实例的引用。(2)抽象类允许包含抽象成员,但这不是必须的(可以允许一个抽象类中没有任何抽象成员);抽象类中可以有非抽象方法。抽象类中即使所有的方法都实现了,只要在类前边加上
abstract
,它依然是抽象类。(3)抽象类不能同时又是封闭的(
final
),因为抽象类是用来作为父类被继承的,如果是final
则不能被继承了。(4)如果一个非抽象类从抽象类中派生,则其必须通过覆盖来实现所有继承而来的抽象成员。同时必须实现抽象方法。
(5)抽象类可以被抽象类所继承,结果仍然是抽象类。同时和非抽象类继承抽象类不同,可以不实现继承的抽象类的抽象方法。
(6)抽象类允许被声明。
例11:接口的概念
接口中只有常量和抽象方法,其中常量总是public static final
,写与不写都是。其方法不能是private
,必须是public abstract
,写不写都是public abstract
,支持多继承。