12、内部类(多继承)
文章分类:Java编程
首先,要清楚继承的目的是为了复用。Java只能继承一个类,不支持多继承。即没有extends Class1,Class2的语句形式。但我们可以通过内部类现模拟这一实现。
java的非静态内部类可以使用外部类的所有成员方法和变量。这给继承多个类的同名成员并共享带来可能。同时非匿名内部类可以继承一个父类和实现多个接口,因此外部类想要多继承的类可以分别由内部类继承,并进行Override或者直接复用。然后外部类通过创建内部类的对象来使用该内部对象的方法和成员,从而达到复用的目的,这样外部内就具有多个父类的所有特征。这里的多继承可以说是外部类继承自一个内部类对象,而不是类,内部类 is in a 外部类,外部内的所有行为都是通过内部类对象动态获得的。
下面是采用组合多个内部类的方式模拟多继承的实例(基于对象层面,即组合多个内部类对象):
- abstract class Mobile {
- public abstract void call();
- }
- // MP3播放器
- abstract class Mp3Palyer {
- public abstract void play();
- }
- // 智能手机
- class SmartPhone {
- private Mobile mb = new SmartMobile();
- private Mp3Palyer mp3 = new PhoneMp3();
- public Mobile getMobile() {
- return mb;
- }
- public Mp3Palyer getMp3() {
- return mp3;
- }
- public class SmartMobile extends Mobile {
- @Override
- // 不同的智能机有的call方式
- public void call() {
- System.out.println("Call phone!");
- }
- }
- public class PhoneMp3 extends Mp3Palyer {
- @Override
- // 不同的智能机有的play方式
- public void play() {
- System.out.println("Play music!");
- }
- }
- }
- public class MutiImpTest1 {
- static void call(Mobile m) {
- m.call();
- }
- static void play(Mp3Palyer p) {
- p.play();
- }
- public static void main(String[] args) {
- SmartPhone sp = new SmartPhone();
- call(sp.getMobile());// 智能手机具有手机功能
- play(sp.getMp3());// 又具有Mp3的功能
- }
- }
//手机
abstract class Mobile {
public abstract void call();
}
// MP3播放器
abstract class Mp3Palyer {
public abstract void play();
}
// 智能手机
class SmartPhone {
private Mobile mb = new SmartMobile();
private Mp3Palyer mp3 = new PhoneMp3();
public Mobile getMobile() {
return mb;
}
public Mp3Palyer getMp3() {
return mp3;
}
public class SmartMobile extends Mobile {
@Override
// 不同的智能机有的call方式
public void call() {
System.out.println("Call phone!");
}
}
public class PhoneMp3 extends Mp3Palyer {
@Override
// 不同的智能机有的play方式
public void play() {
System.out.println("Play music!");
}
}
}
public class MutiImpTest1 {
static void call(Mobile m) {
m.call();
}
static void play(Mp3Palyer p) {
p.play();
}
public static void main(String[] args) {
SmartPhone sp = new SmartPhone();
call(sp.getMobile());// 智能手机具有手机功能
play(sp.getMp3());// 又具有Mp3的功能
}
}
下面采用继承与匿名内部类的方式模拟(一个是类层面的,一个是对象层面,即外部类首先继承一个类,然后通过引用内部类对象来继承另外一个类):
- //手机
- abstract class Mobile {
- public abstract void call();
- }
- // MP3播放器
- abstract class Mp3Palyer {
- public abstract void play();
- }
- // 智能手机,继承自Mobile
- class SmartMobile extends Mobile {
- @Override
- // 不同的智能机有的call方式
- public void call() {
- System.out.println("Call phone!");
- }
- // 智能手机也有播放音乐的功能
- public Mp3Palyer getMp3() {
- return new Mp3Palyer() {
- @Override
- // 不同的智能机有的play方式
- public void play() {
- System.out.println("Play music!");
- }
- };
- }
- }
- public class MutiImpTest2 {
- static void call(Mobile m) {
- m.call();
- }
- static void play(Mp3Palyer p) {
- p.play();
- }
- public static void main(String[] args) {
- // 现在智能手机即是手机类型,又具有Mp3的功能
- SmartMobile sp = new SmartMobile();
- call(sp);// 智能手机即是手机类型
- play(sp.getMp3());// 又具有Mp3的功能
- }
- }
//手机
abstract class Mobile {
public abstract void call();
}
// MP3播放器
abstract class Mp3Palyer {
public abstract void play();
}
// 智能手机,继承自Mobile
class SmartMobile extends Mobile {
@Override
// 不同的智能机有的call方式
public void call() {
System.out.println("Call phone!");
}
// 智能手机也有播放音乐的功能
public Mp3Palyer getMp3() {
return new Mp3Palyer() {
@Override
// 不同的智能机有的play方式
public void play() {
System.out.println("Play music!");
}
};
}
}
public class MutiImpTest2 {
static void call(Mobile m) {
m.call();
}
static void play(Mp3Palyer p) {
p.play();
}
public static void main(String[] args) {
// 现在智能手机即是手机类型,又具有Mp3的功能
SmartMobile sp = new SmartMobile();
call(sp);// 智能手机即是手机类型
play(sp.getMp3());// 又具有Mp3的功能
}
}
上面的多继承是站在外部类的角度来看的,即它们是通过外部类引用内部类来达到多态与复用的目的。反过来,内部类继承了一个类,同时拥有了外部类的所有成员方法和属性,我们是否可以认为内部类集成了两个类呢?——一个是类层面的,一个是对象层面的(因为非静态内部类使用前一定有外部类的对象来创建它,它持有外部类某个对象的引用)。如果外部类还继承了其他类呢?内部类还是可以访问其他类的方法与属性。现在从内部类的角度来模拟多继承:
- //智能机抽象类
- abstract class SmartMobile {
- public abstract void call();
- public void play() {
- System.out.println("Play music!");
- }
- }
- // 手机
- class Mobile {
- /*
- * 该方法是私有的,与SmartMobile类中方法同名,所以
- * Mobile不能直接继承自SmartMobile,因为重写时不能
- * 缩小访问权限,所以只能使用一个内部类来重写。
- */
- private void call() {
- System.out.println("Call phone!");
- }
- public SmartMobile getSmartMobileImp() {
- // 智能机的实现,好比多继承(继承外部类与SmartMobile)
- return new SmartMobile() {
- // 调用“继承”自外部类的相应方法来实现call
- public void call() {
- // 回调外部类真真的实现
- Mobile.this.call();
- }
- };
- }
- }
- public class MutiImpTest3 {
- static void call(SmartMobile m) {
- m.call();
- }
- static void play(SmartMobile p) {
- p.play();
- }
- public static void main(String[] args) {
- // 智能机即是手机也是Mp3播放器
- SmartMobile sp = new Mobile().getSmartMobileImp();
- call(sp);// 智能机即是手机
- play(sp);// 也是是Mp3播放器
- }
- }
//智能机抽象类
abstract class SmartMobile {
public abstract void call();
public void play() {
System.out.println("Play music!");
}
}
// 手机
class Mobile {
/*
* 该方法是私有的,与SmartMobile类中方法同名,所以
* Mobile不能直接继承自SmartMobile,因为重写时不能
* 缩小访问权限,所以只能使用一个内部类来重写。
*/
private void call() {
System.out.println("Call phone!");
}
public SmartMobile getSmartMobileImp() {
// 智能机的实现,好比多继承(继承外部类与SmartMobile)
return new SmartMobile() {
// 调用“继承”自外部类的相应方法来实现call
public void call() {
// 回调外部类真真的实现
Mobile.this.call();
}
};
}
}
public class MutiImpTest3 {
static void call(SmartMobile m) {
m.call();
}
static void play(SmartMobile p) {
p.play();
}
public static void main(String[] args) {
// 智能机即是手机也是Mp3播放器
SmartMobile sp = new Mobile().getSmartMobileImp();
call(sp);// 智能机即是手机
play(sp);// 也是是Mp3播放器
}
}
另外,从上面程序可看出内部类的另一作用:如果你想继承一个类或实现一个接口,但是这个接口或类中的一个方法和你构想的这个类中的一个方法的名称,参数相同,但访问权限缩小了或者是在继承时不想覆盖签名相同但功能不同的方法,所以你不能直接继承与实现它,你应该怎么办?这时候,你可以建一个内部类继承这个类或实现这个接口(当然你可以修改访问权限是可以的)。由于内部类对外部类的所有内容都是可访问的,内部类可以通过调用外部类的这个方法来重写那个类或接口。上面的Mobile类中的call方法就是这种情况,所以你不能直接让Mobile去继承SmartMobile,固只能采用内部类来达到重写的目的。