第九章:接口
接口和内部类为我们提供了一种接口和实现分离的更加结构化的方法。
一、抽象类和抽象方法(abstract)
抽象类:将所有导出类的共同部分抽取出来,作为一个公共的接口(方法)
优点:可以利用这个接口(抽象类)操作一系列类
特点:1、含有抽象方法的类,可以含有不抽象的具体实现方法,必定是抽象类(abstract),使用抽象限制。
2、当然抽象类,可以没有抽象方法。也无法创建对象(abstract)。
3、抽象类的导出类(子类)要创建对象,必须实现所有的抽象方法。
没有抽象方法的抽象类,无法创建对象:
abstract class Nogo1 {
Nogo1() {
System.out.println("Nogo1()"); }
}
abstract class Nogo2 {
}
class Go1 extends Nogo1 {
Go1() {
System.out.println("Go1()"); }
}
public class Ex2 {
public static void main(String[] args) {
// Nogo1 and Nogo2 不能被初始化
// Nogo1 ng1 = new Nogo1();
Nogo1 ng1 = new Go1();
// Nogo2 ng2 = new Nogo2();
// 但是Nogo1()构造函数在子实例化期间调用
Go1 g1 = new Go1();
}
}
子类覆盖抽象方法案例:
abstract class Dad {
protected abstract void print();
Dad() {
print(); }
}
class Son extends Dad {
private int i = 1;
@Override protected void print() {
println("Son.i = " + i); }
}
public class Ex3 {
public static void main(String[] args) {
/ **初始化过程:
* 1. Son的存储已分配并初始化为二进制零
* 2. Dad()被调用
* 3.在Dad()中调用的Son.print()(s.i = 0)
* 4.按顺序调用成员初始化程序(s.i = 1)
* 5.Son()的构造调用
** /
Son s = new Son();
s.print();
}
}
结果:
Son.i = 0
Son.i = 1
二、接口
接口:是一个完全抽象的类组成,所有的方法都没有具体实现
特点:1、继承具有局限性,接口解决了继承的局限性,单继承;接口可以多实现
2、接口可以使用public修饰(不使用具有包权限,也是默认public修饰类和方法),必须使用interface
3、接口中的域,有隐式的static和final修饰
4、接口和接口是继承关系,接口和类是实现关系
三、完全解耦
策略设计模式:根据传递参数不同,做出不同的的反应行为。如下案例
协变类型:覆盖的方法返回类型而非基类中的类型
class Processor {
public String name() {
return getClass().getSimpleName();
}
Object process(Object input) {
return input; } //object类型
}
class Upcase extends Processor {
@Override
String process(Object input) {
// 覆盖成了String类型,协变类型
return ((String)input).toUpperCase();
}
}
class Splitter extends Processor {
String process(Object input) {
// The split() argument divides a String into pieces:
return Arrays.toString(((String)input).split(" "));
}
}
public class Apply {
public static void process(Processor p, Object s) {
print("Using Processor " + p.name());
print(p.process(s));
}
public static String s =
"Disagreement with beliefs is by definition incorrect";
public static void main(String[] args) {
process(new Upcase(), s);
process(new Splitter(), s);
}
} /* Output:
Using Processor Upcase
DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT
Using Processor Splitter
[Disagreement, with, beliefs, is, by, definition, incorrect]
*///:~
四、java多重继承
通过向上转型成多个抽象基类型,这样方便以后扩展使用
interface CanFight {
void fight();
}
interface CanSwim {
void swim();
}
interface CanFly {
void fly();
}
class ActionCharacter {
public void fight() {
}
}
class Hero extends ActionCharacter
implements CanFight, CanSwim, CanFly {
public void swim() {
}
public void fly() {
}
}
public class Adventure {
public static void t(CanFight x) {
x.fight(); }//提升为接口类型
public static void u(CanSwim x) {
x.swim(); }
public static void v(CanFly x) {
x.fly(); }
public static void w(ActionCharacter x) {
x.fight(); }
public static void main(String[] args) {
Hero h = new Hero();
t(h); // Treat it as a CanFight
u(h); // Treat it as a CanSwim
v(h); // Treat it as a CanFly
w(h); // Treat it as an ActionCharacter
}
} ///:~
接口多重继承
interface CanDo {
void doIt();
}
interface CanDoMore extends CanDo {
void doMore();
}
interface CanDoFaster extends CanDo {
void doFaster();
}
interface CanDoMost extends CanDoMore, CanDoFaster {
void doMost();
}
class Doer implements CanDoMost {
public void doIt() {
}
public void doMore() {
}
public void doFaster() {
}
public void doMost() {
}
}
public class DiamondInheritance13 {
public static void main(String[] args) {
Doer d = new Doer();
((CanDoMore)d).doMore();
((CanDoFaster)d).doFaster();
((CanDo)d).doIt();
}
}
五、通过继承来扩展接口
1、接口扩展案例,接口可以多继承
interface Monster {
void menace();
}
interface DangerousMonster extends Monster {
//DangerousMonster通过继承实现对Monster的扩展
void destroy();
}
interface Lethal {
void kill();
}
class DragonZilla implements DangerousMonster {
public void menace() {
}
public void destroy() {
}
}
interface Vampire extends DangerousMonster, Lethal {
//接口可以extend多个接口,只可以extend单一类
void drinkBlood();
}
class VeryBadVampire implements Vampire {
public void menace() {
}
public void destroy() {
}
public void kill() {
}
public void drinkBlood() {
}
}
public class HorrorShow {
static void u(Monster b) {
b.menace(); }
static void v(DangerousMonster d) {
d.menace();
d.destroy();
}
static void w(Lethal l) {
l.kill(); }
public static void main(String[] args) {
DangerousMonster barney = new DragonZilla();
u(barney);
v(barney);
Vampire vlad = new VeryBadVampire();
u(vlad);
v(vlad);
w(vlad);
}
} ///:~
2、组合接口的名称冲突: 方法名一致,返回值不能不一样,java不允许
interface I1 {
void f(); }
interface I2 {
int f(int i); }
interface I3 {
int f(); }
class C {
public int f() {
return 1; } }
class C2 implements I1, I2 {
public void f() {
}
public int f(int i) {
return 1; } // overloaded 覆盖
}
class C3 extends C implements I2 {
public int f(int i) {
return 1; } // overloaded 覆盖
}
class C4 extends C implements I3 {
// Identical, no problem: 相同,不会出现问题
public int f() {
return 1; }
}
// 方法名一致,但是返回类型不同,重载中不允许出现(重载区别于参数的类型、顺序、个数):
//! class C5 extends C implements I1 {}
//! interface I4 extends I1, I3 {} ///:~
六、适配接口
1、
七、接口中的域
1、接口中的域默认有static 、final修饰,随着类的加载而初始化,存储在接口的静态存储区
public interface RandVals {
Random RAND = new Random(47);
int RANDOM_INT = RAND.nextInt(10);
long RANDOM_LONG = RAND.nextLong() * 10;
float RANDOM_FLOAT = RAND.nextLong() * 10;
double RANDOM_DOUBLE = RAND.nextDouble() * 10;
}
public class TestRandVals {
public static void main(String[] args) {
print(RandVals.RANDOM_INT);
print(RandVals.RANDOM_LONG);
print(RandVals.RANDOM_FLOAT);
print(RandVals.RANDOM_DOUBLE);
// RandVals.RANDOM_INT = 3; 这样会报错,由于是被static、final修饰无法再次被赋值
}
} /* Output:
8
-32032247016559954
-8.5939291E18
5.779976127815049
*///:
八、嵌套接口
1、接口嵌套
//: interfaces/nesting/NestingInterfaces.java
package interfaces.nesting;
class A {
interface B {
void f();
}
public class BImp implements B {
public void f() {
}
}
private class BImp2 implements B {
public void f() {
}
}
public interface C {
void f();
}
class CImp implements C {
public void f() {
}
}
private class CImp2 implements C {
public void f() {
}
}
private interface D {
void f();
}
private class DImp implements D {
public void f() {
}
}
public class DImp2 implements D {
public void f() {
}
}
public D getD() {
return new DImp2(); }
private D dRef;
public void receiveD(D d) {
dRef = d;
dRef.f();
}
}
interface E {
interface G {
void f();
}
// Redundant "public":
public interface H {
void f();
}
void g();
// Cannot be private within an interface: 接口的中方法定义为private将无法去具体实现
//! private interface I {}
}
public class NestingInterfaces {
public class BImp implements A.B {
public void f() {
}
}
class CImp implements A.C {
public void f() {
}
}
// Cannot implement a private interface except
// within that interface's defining class: A.D为私有类型
//! class DImp implements A.D {
//! public void f() {}
//! }
class EImp implements E {
public void g() {
}
}
class EGImp implements E.G {
public void f() {
}
}
class EImp2 implements E {
public void g() {
}
class EG implements G {
public void f() {
}
}
}
public static void main(String[] args) {
A a = new A();
// Can't access A.D: 因为他是private
//! A.D ad = a.getD();
// Doesn't return anything but A.D: ,除非强制转换成A.DImp2类型
//! A.DImp2 di2 = a.getD();
// Cannot access a member of the interface: 接口是私有,方法肯定无法访问
//! a.getD().f();
// Only another A can do anything with getD():
A a2 = new A();
a2.receiveD(a.getD());
}
} ///:~
九、接口与工厂
1、工厂设计模式
不利于构造器创建对象,而是工厂对象调用创建方法生成接口的某个实现类,代码与接口实现分离。
interface Game {
boolean move(); }
interface GameFactory {
Game getGame(); }
class Checkers implements Game {
private int moves = 0;
private static final int MOVES = 3;
public boolean move() {
print("Checkers move " + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory {
public Game getGame() {
return new Checkers(); }
}
class Chess implements Game {
private int moves = 0;
private static final int MOVES = 4;
public boolean move() {
print("Chess move " + moves);
return ++moves != MOVES;
}
}
class ChessFactory implements GameFactory {
public Game getGame() {
return new Chess(); }
}
public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGame();
while(s.move())
;
}
public static void main(String[] args) {
playGame(new CheckersFactory());
playGame(new ChessFactory());
}
} /* Output:
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*///:~
十、接口与抽象类的区别
区别 | 抽象类 | 接口 |
---|---|---|
修饰关键字 | abstract 修饰类,抽象类中可以没有抽象方法;有抽象方法的类,必须是使用abstract修饰 |
使用interface修饰,接口中的方法都是抽象的 |
成员变量 | 可以使用public**、private、final、protected和default,是用来描述一类事物的属性** | 有隐式的static和final修饰,因此只能初始化一次,在类加载时初始化,存储在接口的静态存储区。 |
成员方法 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符,因为这样可能导致无法实例化 |
构造器 | 有构造器,接口不能实例化,需要覆盖所有的抽象方法 | 无构造器,无法实例化,,需要覆盖所有的抽象方法 |
继承与实现 | 只能单继承,或实现多个接口(隐藏的多继承,A继承B,B继承C),类与接口只能是实现关系。 | 接口可以继承多个接口,接口与接口之间是继承关系。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
十-、接口与抽象类选择哪个使用
- 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
- 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
- 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
参考:https://blog.csdn.net/gongxiao1993/article/details/82055007