接口和内部类为我们提供了一种将接口与实现相分离的更加结构化的方法
抽象类和抽象接口
创建抽象类是希望通过这个接口操纵一系列的类
抽象类不一定包含抽象方法,包含抽象方法的类一定是抽象类
没有抽象方法的类定义为抽象类是为了阻止他实例化
如果一个类包含一个或者多个抽象方法,这个类必须被限定为抽象的
如果从一个抽象类继承,并且创建新建类的对象,就必须为基类中的所有抽象方法提供方法定义,如果不这样做那么这个导出类也是抽象类必须用abstract来声明
抽象类的所有方法并不需要都是抽象的,只需要将需要改变的方法设置为抽象方法即可
abstract class Instrument { //表示一个接口没有任何具体的实现内容
抽象类不一定包含抽象方法
包含抽象方法的类一定是抽象类
没有抽象方法的类定义为抽象类是为了阻止他实例化
private int i ;
public abstract void play(Note n); //仅有声明,并没有方法体
public String what(){ //抽象类中并不是所有的方法都是抽象方法
return "Instrument";
}
public abstract void adjust();
}
class Wind extends Instrument{
@Override
public void play(Note n) { //为基类中的所有抽象方法提供方法定义
System.out.println("Wind play " +n);
}
@Override
public void adjust() {}
public String what(){
return "Wind";
}
}
class Stringed extends Instrument{
@Override
public void play(Note n) { //为基类中的所有抽象方法提供方法定义
System.out.println("Stringed Play()" + n );
}
@Override
public void adjust() {}
public String what(){
return "Stringed";
}
}
public class Music4 {
static void tune(Instrument instrument){
instrument.play(Note.B_FLAT);
}
public static void main(String[] args) {
Instrument i1 = new Wind();
Instrument i2 = new Stringed();
tune(i1);
tune(i2);
}
}
抽象类是很有用的重构工具,因为他们使得我们可以很容易的将公共方法沿着层次结构向上移动
接口
接口定义需要interface关键字,这个关键字产生一个完全抽象的类,没有任何的具体的实现,允许创建者确定返回类型,方法名,参数列表,但是没有方法体
interface前面可以添加public关键字
接口中可以包含域,并且这些域隐式的是static和final类型的,接口中的方法必须是public权限的,不声明也是
interface Instrumento {
int VALUE = 5; //默认为static和final
void play(Note n); //接口里没有任何方法体
void adjust();
}
class Windo implements Instrumento{ //实现接口
@Override
public void play(Note n) {
System.out.println(this + " .play() " + n);
}
@Override
public void adjust() {
System.out.println(this + ".adjust");
}
@Override
public String toString() {
return "Windo";
}
}
class Percussion implements Instrumento{//实现接口
@Override
public void play(Note n) {
System.out.println(this + ".play() " + n);
}
@Override
public void adjust() {
System.out.println(this + " .adjust");
}
@Override
public String toString() {
return "Percussion";
}
}
class Brass extends Windo{ //继承关系
@Override
public String toString() {
return "Brass";
}
}
public class Music5 {
static void tune(Instrumento instrumento){
instrumento.play(Note.MIDDLE_C);
}
public static void main(String[] args) {
Instrumento instrumento1 = new Windo();
tune(instrumento1);
instrumento1.adjust();
Instrumento instrumento2 = new Percussion();
tune(instrumento2);
Instrumento instrumento3 = new Brass();
tune(instrumento3);
}
}
完全解耦
class Processor{
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class UpCase extends Processor{
String process(Object input){//返回类型是Strin,所以需要强转
return ((String)input).toUpperCase();
}
}
class DownCase extends Processor{
String process(Object input){
return ((String)input).toLowerCase();
}
}
public class Apply {
public static void process(Processor p , Object s){ //可以接受任何类型的Processor,并且将其应用在一个Object对象
//这样创建一个能够根据所传递的参数对象的不同而具有不同的行为
被称作"策略设计模式"但是只能接受Processor类型的
System.out.println("使用的方法是: " + p.name());
System.out.println(p.process(s));
//此时此时Apply和Processor过度耦合因为Apply只可以处理Processor这一类型的代码
}
public static String s = "Hello Word";
public static void main(String[] args) {
System.out.println(s);
process(new UpCase(),s);
process(new DownCase(),s);
}
}
此时的Apply.process方法只可以接受任何类型的Processor
如果现在有一个类看起来好像也可以使用Apply.process方法
public class Waveform {
private static long count;
private final long id = count++;
@Override
public String toString() {
return "Waveform" + id;
}
}
public class Filter {
public String name(){ //这里看到Filter里面的方法和上述代码中的Processor
//中的代码非常的类似 如何让他也可以适用Apply方法呢?
return getClass().getSimpleName();
}
public Waveform process(Waveform input){
return input;
}
}
public class HighPass extends Filter{
double cutoff;
public HighPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
public class LowPass extends Filter{
double cutoff;
public LowPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
首先因为Filter并不能直接使用Apply.process方法,因为他并不是继承Processor这个类的
因为里面的方法类似,我们可以将Processor改成一个接口
public interface Processor {
public String name();
Object process(Object input);
}
因为 name() 这个方法返回的是类型的名字,所有的类型都是通用的,此时可以用一个抽象类来将不变的name 方法设置成所有的导出类都一样,Process方法在所有的导出类里重写
public abstract class StringProcessor implements Processor{
@Override
public String name() {//定义不变的方法
return getClass().getSimpleName();
}
@Override
public abstract String process(Object input);//每个继承类都不同的方法用抽象方法
public static String s = "Hello World";
public static void main(String[] args) {
Apply.process(new UpCase(),s);
Apply.process(new DownCase(),s);
}
}
class UpCase extends StringProcessor {
public String process(Object input){//返回类型是String,所以需要强转
return ((String) input).toUpperCase();
}
}
class DownCase extends StringProcessor{
public String process(Object input){
return ((String)input).toLowerCase();
}
}
public class Apply {
public static void process(Processor p,Object s){
System.out.println("使用了 "+ p.name());
System.out.println(p.process(s));
}
}
此时我们就可以对Filter进行适配 (适配器模式)
class FilterAdapt implements Processor{ //实现Processor的接口
Filter filter;
public FilterAdapt(Filter filter){ //此处通过构造器的方式将Filter传过来
this.filter = filter;
}
public String name() { //此时暴露的接口还是Processor接口
//具体的实现由Filter进行处理
return filter.name();
}
public Waveform process(Object input) {
return filter.process((Waveform) input);//输入输出都应该是Waveform类型,所以这里应该进行强转
}
}
public class FilterProcessor {
public static void main(String[] args) {
Waveform waveform = new Waveform();
Apply.process(new FilterAdapt(new LowPass(2.0)),waveform);
Apply.process(new FilterAdapt(new HighPass(3.0)),waveform);
}
}
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{
@Override //Hero组合了具体类ActionCharacter和三个接口
//使用这种方式组合的时候这个具体类要放在前面后面跟实现接口
public void Swim(){}
@Override
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);//根源走的ActionCharacter中的fight方法
u(h);//根源走的Hero中的swim方法
v(h);//根源走的Hero中的fly方法
w(h);//根源走的ActionCharacter中的fight方法
}
}
通过继承来扩展接口
interface Monster{
void menace();
}
interface DangerousMonster extends Monster{ //直接继承Monster,并且增加一个新的方法
//并且在DragonZilla中实现
void destroy();
}
interface lethal{
void kill();
}
class DragonZilla implements DangerousMonster{
@Override
public void menace(){}
@Override
public void destroy(){}
}
interface Vampire extends DangerousMonster , lethal{//接口可以多继承
void drinkBlood();
}
class VeryBadVampire implements Vampire{
@Override
public void menace(){}
@Override
public void destroy(){}
@Override
public void kill(){}
@Override
public void drinkBlood(){}
}
public class HorrorShow {
static void u(Monster b){
b.menace();
System.out.println("b.menace");
}
static void v(DangerousMonster d){
d.destroy();
System.out.println("d.destroy");
d.menace();
System.out.println("d.menace");
}
static void w(lethal l){
l.kill();
System.out.println("l.kill");
}
public static void main(String[] args) {
DangerousMonster dangerousMonster = new DragonZilla();
u(dangerousMonster);
v(dangerousMonster);
Vampire vampire = new VeryBadVampire();
u(vampire);
v(vampire);
w(vampire);
}
}
组合接口时的命名冲突
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{ //多继承接口
@Override
public void f(){}
@Override
public int f(int i){return 1;}
}
class C3 implements I2{
@Override
public int f(int i){return 0;}
}
class C4 implements I3{
@Override
public int f(){return 0;}
}
/*class C5 extends I1,I3 { //重载方法仅通过返回值类型是区分不开的
@Override
public void f(){}}*/
/*interface I4 extends I1,I3{
@Override
default void f(){}}*/
public class InterfaceCollision {
}
接口中的域
放入接口中的任何域都是自动的是static和final的,但是现在有了枚举类型
嵌套接口
接口可以嵌套到类中或者其他接口中
class A {
interface B {void f();}
public class BImp implements B{
@Override
public void f(){}}
private class BImp2 implements B{
@Override
public void f(){}}
public interface C{void f();}
class CImp implements C{
@Override
public void f(){}}
private class CImp2 implements C{
@Override
public void f(){}}
private interface D{void f();}
private class DImp implements D{
@Override
public void f(){}}
public class DImp2 implements D{
@Override
public void f(){}}
public D getD(){
return new DImp2();
}
private D dRef;
public void receiveD (D d){
this.dRef = d;
dRef.f();
}
}
interface E{
interface G{void f();}}
interface H{void f();
void g();
}
public class NestingInterfaces {
public class BImp implements A.B{
@Override
public void f(){}}
class CImp implements A.C{ // 不可以实现一个私有的接口
@Override
public void f(){}}
// class DImp implements A.D{}
class EImp implements E{
public void g(){}}
class EGImp implements E.G{
@Override
public void f() {}}
class EImp2 implements E{
public void g(){};
class EG implements E.G{
@Override
public void f(){}}
}
public static void main(String[] args) {
A a = new A(); //无法访问A.D
//A.D ad = new a.getD();
A a2 = new A();
a2.receiveD(a.getD());
}
}
嵌套在另外一个接口中的接口自动的是public的,不能声明为private的
如果一个类中有一个private的接口,那么他只能被自身所用
接口与工厂
接口是可以多重继承的,生成遵循某个接口的对象的典型方式就是工厂设计模式,这和直接调用构造器是不同的,我们在工厂对象上调用的是创建方法,而这个工厂对象将生成接口的某个实现的对象,理论上通过这种方式,代码将完全的和接口实现分离
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Imp1 implements Service{
Imp1(){}
@Override
public void method1(){
System.out.println("Imp method1");
}
@Override
public void method2(){
System.out.println("Imp method2");
}
}
class ImpFac implements ServiceFactory{
@Override
public Service getService() {
return new Imp1();//接口工厂的实现类中返回了一个接口的实现类
}
}
class Imp2 implements Service{
Imp2(){}
@Override
public void method1() {
System.out.println("Imp2 method1");
}
@Override
public void method2() {
System.out.println("Imp2 method2");
}
}
class Imp2Fac implements ServiceFactory{
@Override
public Service getService() {
return new Imp2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new ImpFac());
serviceConsumer(new Imp2Fac());
}
}