抽象类和抽象方法:
抽象方法:只有声明而没有方法体。(使用abstract关键字)
abstract void f();
抽象类:包含抽象方法的类就叫做抽象类。如果一个类包含了一个或多个抽象方法,该类就必须被限定为抽象的,否则编译器会报错。
接口:
interface关键字产生一个完全抽象的类,允许创建者确定方法名、参数列表和返回类型,不提供任何具体实现。
interface不仅是一个极度抽象的类,它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现类似多重继承的变种特性。
创建接口:
想要创建一个接口,需要用interface关键字代替class关键字,可以添加public关键字(仅限于该接口在与其同名的文件中被定义),默认为包访问权限。
接口中也可以包含域,但这些域隐式地是static和final的。
接口中的方法默认是public的,即使不用public修饰。
当一个类实现一个接口时,在接口中定义的方法在重写的时候必须被定义为public的。
interface Intrument{
int VALUE = 5; //static&final
void play(String n); // Automatically public
void adjust();
}
class Wind implements Intrument{
public void play(String n){
System.out.println(n);
}
public void adjust(){
System.out.println("adjust()");
}
}
完全解耦
import java.util.*;
class Processor {
public String name() {
return getClass().getSimpleName();
}
Object process(Object input) {
return input;
}
}
class Upcase extends Processor {
String process(Object input) {
return ((String) input).toUpperCase();
}
}
class Downcase extends Processor {
String process(Object input) {
return ((String) input).toLowerCase();
}
}
class Splitter extends Processor {
String process(Object input) {
return Arrays.toString(((String) input).split(" "));
}
}
public class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Processor" + p.name());
System.out.println(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 Downcase(), s);
process(new Splitter(), s);
process(new Processor(), s);
}
}
/*
Using ProcessorUpcase
DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT
Using ProcessorDowncase
disagreement with beliefs is by definition incorrect
Using ProcessorSplitter
[Disagreement, with, beliefs, is, by, definition, incorrect]
Using ProcessorProcessor
Disagreement with beliefs is by definition incorrect
*/
Apply.process()方法可以接受任何类型的Process,并将其应用到一个Object对象上,然后打印结果。
像本例这样,创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为“策略设计模式”。
.
如果此时有一个类也Process具有相同的接口元素,但是并非继承自Processor,因此你不能将此类用于Apply.process()方法。
因为Apply.process()方法和Processor之间耦合过紧,Apply.process()的复用范围被限制。
所以,如果Processor是一个接口,限制就会变得松动。
import java.util.*;
interface Processor {
public String name();
Object process(Object input);
}
class Upcase implements Processor {
public String name() {
return getClass().getSimpleName();
}
public String process(Object input) {
return ((String) input).toUpperCase();
}
}
class Downcase implements Processor {
public String name() {
return getClass().getSimpleName();
}
public String process(Object input) {
return ((String) input).toLowerCase();
}
}
class Splitter implements Processor {
public String name() {
return getClass().getSimpleName();
}
public String process(Object input) {
return Arrays.toString(((String) input).split(" "));
}
}
public class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Processor" + p.name());
System.out.println(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 Downcase(), s);
process(new Splitter(), s);
}
}
/*
Using ProcessorUpcase
DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT
Using ProcessorDowncase
disagreement with beliefs is by definition incorrect
Using ProcessorSplitter
[Disagreement, with, beliefs, is, by, definition, incorrect]
*/
.
复用代码的第一种方式是客户端程序员遵循接口来编写他们自己的类。
但是有时候类已经被创建且不能修改,此时就需要用到“适配器设计模式”。
public class Filter {
public String name() {
return getClass().getSimpleName();
}
public Waveform process(Waveform input) {
return input;
}
public static void main(String[] args) {
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new Filter()), w);
}
}
class Waveform{
public String toString() {
return "wavaform";
}
}
class FilterAdapter implements Processor{
Filter filter;
public FilterAdapter(Filter filter) {
this.filter=filter;
}
public String name() {
return filter.name();
}
public Waveform process (Object input) {
return filter.process((Waveform)input);
}
}
**适配器模式:**适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。
适配器模式有三种:类适配器、对象适配器、接口适配器。
Java中的多重继承
在导出类中,不强制要求必须有一个是抽象的或者“具体的”(没有任何抽象方法的)基类。
如果要从一个非接口的类继承,那么只能从一个类去继承,其余元素都必须是接口。
需要将所有的接口名都置于implements关键字之后,用逗号将他们一一分开。
可以继承任意多个接口,并可以向上转型为每个接口,因为每个接口都是一个独立类型。
例:class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly{ ... }
将一个具体类和多个接口组合到一起的时候,具体类必须放在前面,后面跟着接口否则编译器会报错。
通过继承扩展接口
通过接口与接口之间的继承,可以实现扩展基类接口中的方法。,
接口之间的继承可以将extends关键字用于引用多个基类接口,只需将接口用逗号一一分隔开。
interface Monster{
void menace();
}
interface DangerousMoster extends Monster{
void destroy();
}
interface Lethal{
void kill();
}
interface Vampire extends DangerousMoster,Lethal{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
public void menace() {
System.out.println("wawawa");
}
public void destroy() {
System.out.println("boom");
}
public void kill() {
System.out.println("die");
}
public void drinkBlood() {
System.out.println("si si si");
}
}
public class HorrorShow {
public static void main(String[] args) {
VeryBadVampire v = new VeryBadVampire();
v.destroy();
v.drinkBlood();
v.drinkBlood();
v.kill();
}
}
/*
boom
si si si
si si si
die
*/
**组合接口时的名字冲突:**在打算组合不同接口中使用相同的方法名通常会造成代码可读性的混乱,请尽量避免这种情况,当同名且参数类型和个数相同但返回值类型不同的两个接口组合时编译器会报错。
接口中的域
任何放入接口中的域都自动是static和final的,所以接口就成为了一种便捷的用来创建常量组的工具。
Java SE5后,有了更加强大而灵活的enum关键字,使用接口来群组常量显得没什么意义了。
这些域在类第一次被加载时初始化,它们不是接口的一部分,它们的值被存储在该接口的静态存储区域内。
嵌套接口
接口可以嵌套在类或其他接口中。
class A {
interface B{
void f();
}
public class BImp implements B{
public void f() {};
}
public class BImp2 implements B{
public void f() {};
}
public interface C{
void f();
}
class CImp implements C{
public void f() {};
}
class CImp2 implements C{
public void f() {};
}
private interface D{
public void f();
}
public 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();
}
public interface H{
void f();
}
void g();
}
public class NestingInerfaces{
public class BImp implements A.B{
public void f() {};
}
class CImp implements A.C{
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 E.G{
public void f() {};
}
}
public static void main(String[] args) {
A a = new A();
A a2 = new A();
a2.receiveD(a.getD());
}
}
接口与工厂方法
工厂方法的结构:
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service gerService();
}
class Implementation1 implements Service {
public void method1() {
System.out.println("Implementation1 method1");
}
public void method2() {
System.out.println("Implementation1 method2");
}
}
class Implementation1Factory implements ServiceFactory {
public Service gerService() {
return new Implementation1();
}
}
class Implementation2 implements Service {
public void method1() {
System.out.println("Implementation2 method1");
}
public void method2() {
System.out.println("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory {
public Service gerService() {
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact) {
Service s = fact.gerService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}
}
/*
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*/