您的位置:首页 > 其它

复杂的类继承体系结构和类资源名称冲突解决

2016-01-22 22:07 357 查看

一、扩展的类继承体系结构

在前面“第一到七章”中介绍的类继承体系结构围绕“具体类”,因而是特殊的简单的形式。现在将“具体类,抽象类,接口”都考虑在内,可得到类继承体系结构的一般的复杂的形式。

首先定义一个概念:从某个最顶层父类到某个最底层子类的一条路径被称为“继承路径”。有且只有3种类型继承路径:1)最顶层父类是Object,最底层子类是具体类,中间是具体类或者抽象类;2)最顶层父类是Object,最底层子类是抽象类,中间是具体类或者抽象类;3)整条继承路径中都为接口。分别如图1,图2,图3所示。假如现在给定一条“继承路径”,那么这条“继承路径”必定是上述3种类型“继承路径”之一。据此可知,“第一到七章”中介绍的类继承体系结构其实是这里所述的“第1种继承路径”的特例而已:即最顶层父类是Object,最底层子类是具体类,中间是具体类。

图1



图2



图3



另外,如下所示代码并不是表示第4种“继承路径”,而只是图4所表示的继承路径(属于第1种继承路径)和图5所表示的继承路径(属于第3种继承路径)的复合而已。

public class A implements IA {
}

interface IA {
}


图4



图5



另外称两条继承路径的交点类为汇点类。如下代码包含如图6所示类继承体系结构,其中有两条继承路径,这两条继承路径的汇点类为具体类A。

public class A extends C implements IIA {
}

class B {
}

class C extends B {
}

interface IA {
}

interface IIA extends IA {
}


图6



“继承路径”之间的复合可得到复杂的类继承体系结构,如图7,8,9所示。

图7



图8



图9



二、编译通过条件——类资源名称冲突解决

在复杂的类继承体系结构中,很容易出现包含两个或者两个以上相同类资源名称的类资源的情况,这些类资源相互之间得满足一定条件,否则整个类继承体系结构可能不能通过编译。

3.1、类资源名称

对于数据成员(一般数据成员,静态数据成员)来说,类资源名称是指变量名称(跟变量类型,“static”修饰符等无关);对于方法(一般方法,静态方法)来说,类资源名称是指方法签名,即方法名和参数列表(跟返回类型,“static”修饰符等无关)。

3.2、需要满足的条件

具有相同类资源名称的两个类资源之间的关系有3种可能:处于同一个类中,处于同一条“继承路径”和处于不同条“继承路径”。接下来分别针对“数据成员”和“方法”来介绍需要满足的条件。

注意:

在两条“继承路径”的汇点类处完成是否满足条件的判断(即是否通过编译的判断),接下来,对于处于下面直接紧邻层次的并且与汇点类处于同一条“继承路径”的类来说,关注的只是汇点类处的最终效果,对于这个类来说,可以认为在汇点类处汇聚的两条“继承路径”在汇点类处完成了“合并”。因此,多条“继承路径”的复合(即复杂的类继承体系结构)最后逻辑上相当于一条“继承路径”而已。

比如有如下类继承体系结构:

public class D extends C {
}

class A {
public int f() {
return 10;
}
}

interface IA {
int f();
}

class B extends A implements IA {
}

interface IB {
int g();
}

class C extends B implements IB {
public int g() {
return 20;
}
}


上述描述的示意图如图10所示。

图10



3.2.1、数据成员

1、处于同一个类中

不能通过编译。如下所示。

public class A {
int a = 10;

static float a = 20;

int b = 20;

double b = 30;
}


2、处于同一条“继承路径”

可通过编译。如下所示。

public class A extends PA {
float a = 20;

int b = 30;
}

class PA {
static int a = 10;

int b = 40;
}


3、处于不同条“继承路径”

在汇点类处完成是否通过编译的判断:可通过编译。如下所示(汇点类是具体类A)。

public class A extends PA implements IA{
float a = 20;

int b = 30;
}

class PA {
static int a = 10;

int b = 40;
}

interface IA {
int a = 30;

int b = 50;
}


3.2.2、方法

方法分为“一般方法”和“静态方法”,“一般方法”中又包括“抽象方法”(是指由“abstract”修饰符修饰的方法,注意在接口中的“一般方法”默认都由“public abstract”修饰符组合修饰)。

方法之间有一个“覆盖”关系,覆盖是指:假如现在有一个A方法和B方法,要使得B方法覆盖A方法。那么A方法和B方法需要满足以下几个条件:

A方法和B方法要么都是静态方法,要么都是一般方法

B方法的访问权限修饰符大于等于A方法的访问权限修饰符

B方法的返回类型要么是A方法返回类型的子类,要么与A方法返回类型一致

另外,如果最终子类是“具体类”,那么“抽象方法”必须被一般具体方法覆盖。

1、处于同一个类中

不能通过编译。如下所示。

public abstract class A {
int f() {
return 10;
}

int f() {
return 20;
}

int g() {
return 10;
}

static int g() {
return 10;
}

int h() {
return 10;
}

abstract int h();

static int j() {
return 10;
}

static int j() {
return 20;
}

static int k() {
return 10;
}

abstract int k();

abstract int l();

abstract int l();
}


2、处于同一条“继承路径”

可通过编译,但是处于不同层次的具有相同类资源名称的两个方法需要满足“覆盖”关系(下面层次的方法覆盖上面层次的方法),即要遵循“覆盖”关系的3个条件。此外,如果最终子类是“具体类”,那么“抽象方法”必须被一般具体方法覆盖。如下所示。

public abstract class A extends PA {
static int f() {
return 10;
}

ReturnType g() {
return null;
}

int h() {
return 10;
}

static ReturnType j() {
return null;
}

static int k() {
return 10;
}
}

class PA {
int f() {
return 10;
}

ExtendedReturnType g() {
return null;
}

public int h() {
return 10;
}

static ExtendedReturnType j() {
return null;
}

public static int k() {
return 10;
}
}

class ReturnType {
}

class ExtendedReturnType extends ReturnType {
}


3、处于不同条“继承路径”

经过分析可知,其中一条“继承路径”必为第3种类型继承路径,接下来分为两种情况进行介绍:另外一条“继承路径”是第3种类型继承路径;另外一条“继承路径”是第1或者2种类型继承路径。

另外,首先定义“代表方法”的概念:在一条“继承路径”中,如果存在多个具有相同类资源名称的方法,那么最下面层次的方法是“代表方法”,它能够代表该条继承路径中所有具有“与其相同类资源名称”的方法。

1)另外一条“继承路径”是第3种类型继承路径

在汇点类处完成是否通过编译的判断,此时,汇点类是接口。需要满足的条件:相同类资源名称的两个代表方法需要达到一个状态,在该种状态下,存在一个方法能够同时覆盖这两个代表方法。现在这两个代表方法都为由“public abstract”修饰符组合修饰的方法,另外只要满足“两方法的返回类型一致或者其中一个返回类型是另外一个返回类型的子类”的条件,那么就必定存在一个方法能够同时覆盖这两个代表方法。因为汇点类是“接口”,因而“抽象方法”无需被一般具体方法覆盖。如下所示(汇点类是接口A)。

public interface A extends IA, IIA {
// 对于“g()”方法没有编译错误,g()方法无需被一般具体方法覆盖
// 对于“f()”方法有编译错误
}

interface IA {
int f();

ReturnType g();
}

interface IIIA {
ReturnType g();
}

interface IIA extends IIIA {
float f();

ExtendedReturnType g();
}

class ReturnType {
}

class ExtendedReturnType extends ReturnType {
}


2)另外一条“继承路径”是第1或者2种类型继承路径

在汇点类处完成是否通过编译的判断,此时,汇点类是具体类或者抽象类。如果另外一条“继承路径”(第1或者2种类型继承路径)的代表方法是抽象方法,那么需要满足的条件跟上小节“另外一条‘继承路径’是第3种类型继承路径 ”一致。因为是“抽象方法”,因而无需被一般具体方法覆盖。如下所示(汇点类是抽象类D)。

/**
* 能够通过编译
*/
public class E extends D {
public ExtendedReturnType f() {
return null;
}
}

abstract class A {
abstract ExtendedReturnType f();
}

abstract class B extends A {
}

abstract class C extends B {
}

abstract class D extends C implements IC {
}

interface IC {
ReturnType f();
}

class ReturnType {
}

class ExtendedReturnType extends ReturnType {
}


如果另外一条“继承路径”(第1或者2种类型继承路径)的代表方法是非抽象方法(静态方法或者一般具体方法),那么需要满足的条件是该非抽象方法覆盖另外一条“继承路径”的代表方法(即接口中的“抽象方法”),也就是需要遵循覆盖的3个条件。因此最后该“抽象方法”会被一般具体方法覆盖。如下所示(汇点类是具体类D)。

public class E extends D {

}

class A {
/**
* 提示静态f()方法不能覆盖IC接口中的f()方法
*
* @return
*/
public static int f() {
return 10;
}

/**
* 提示访问权限修饰符“变弱”
*
* @return
*/
int g() {
return 10;
}

/**
* 提示返回类型不匹配
*
* @return
*/
public ReturnType j() {
return null;
}
}

class B extends A {
}

class C extends B {
}

class D extends C implements IC {
}

interface IC {
int f();

int g();

ExtendedReturnType j();
}

class ReturnType {
}

class ExtendedReturnType extends ReturnType {
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: