9.1 抽象类和抽象方法
抽象方法:仅有声明而没有方法体。
抽象类:包含抽象方法的类。实际不包含抽象方法的类也可以声明为抽象类,只是不能创建该类的对象而已。
abstract class className
abstract ReturnType methodName(ArgType arg);
9.2 接口
interface关键字表示创建接口,这是一个完全抽象的类,不含任何具体实现。
implements表示该类实现某一接口,这个类必须实现接口定义的每个抽象方法。
9.3 完全解耦
一个方法如果以接口类型作为传入参数的类型,则可编写可复用性较高的代码。
策略设计模式,能创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,例如:
public class Apply {
/**
* 根据传入参数对象的不同,而采取不同的行为
* @param p Processor对象,即策略
* @param s
*/
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);
}
}
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(" "));
}
}
在上面的代码中,Apply.process()方法接受的是Processor类型的参数(包括其本身的对象以及子类的对象)。但是如果存在另外一个类Filter,它具有与Processor相同的接口元素(就是相同的方法)。
public class Filter {
public String name(){
return getClass().getSimpleName();
}
public Waveform process(Waveform input){
return input;
}
}
但是,显然我们不能将Filter类型以及其子类类型的对象作为参数传入到Apply.process()方法中。这其实对代码的复用还是有限制。
如果将Processor定义成接口,然后让客户端程序员遵循接口的定义来编写相应的类,这是能修改现有类的情况。
在不能修改现有类的情况下,可以考虑使用适配器设计模式。例如:
class FilterAdapter implements IProcessor{
Filter filter;
public FilterAdapter(Filter filter){
this.filter = filter;
}
@Override
public String name() {
return filter.name();
}
@Override
public Object process(Object input) {
return filter.process((Waveform) input);
}
}
创建一个适配器类,同时将原有类Filter的对象作为一个成员对象,在实现接口的方法时,调用Filter对象的对应方法即可,其实就是代理。
9.4 Java中的多重继承
Java类只能继承一个父类,但可以实现多个接口,通过这种方式来达到多重继承的目的。
使用接口的原因:
1) 禁止程序员使用该类创建对象,与抽象类相同;
2) 可以向上转型成为多个类型(因为多实现的缘故),这一点与抽象类不同,继承自抽象类的类的对象,只能向上转型成为抽象类类型,灵活性不如接口。
9.5 通过继承来扩展接口
接口之间可以存在继承关系,并且可以通过extends关键字继承多个接口。
9.5.1 组合接口时的名字冲突
当接口之间存在继承关系时,应避免方法名相同的情况,以防止接口冲突的出现,同时提高代码的可读性。
public class InterfaceCollision {
}
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 extends C implements I2{
@Override
public int f(int i) {
return 1;
}
}
/**
* 方法相同
*/
class C4 extends C implements I3{
public int f(){
return 1;
}
}
/**
* 接口冲突
*/
//class C5 extends C implements I1{}
/**
* 接口冲突
*/
//interface I4 extends I1, I3{}
9.6 适配接口
在策略模式中,可以将方法的参数类型设置为接口。
例如Scanner类的构造器的参数类型就是Readable接口类型。
package com.mzm.chapter09;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.Random;
import java.util.Scanner;
public class RandomWords implements Readable {
private static Random rand = new Random(47);
private static final char[] capitals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers = "abcdefghijklmnopqrsrtuvwxyz".toCharArray();
private static final char[] vowels = "aeiou".toCharArray();
private int count;
public RandomWords(int count){
this.count = count;
}
@Override
public int read(CharBuffer cb) throws IOException {
if(count-- == 0){
//表示已到末尾
return -1;
}
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i = 0; i < 4; i++){
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
//返回追加的字符数
return 10;
}
public static void main(String[] args){
Scanner s = new Scanner(new RandomWords(10));
while(s.hasNext()){
System.out.println(s.next());
}
}
}
如果存在一个类,它没有实现Readable接口,但又想将相应的对象作为参数传入Scanner的构造器中,可以采用适配器设计模式。
package com.mzm.chapter09;
import java.util.Random;
public class RandomDoubles {
private static Random rand = new Random(47);
public double next(){
return rand.nextDouble();
}
public static void main(String[] args){
RandomDoubles rd = new RandomDoubles();
for(int i = 0; i < 7; i++){
System.out.print(rd.next() + " ");
}
}
}
package com.mzm.chapter09;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.Scanner;
public class AdaptedRandomDoubles extends RandomDoubles implements Readable {
private int count;
public AdaptedRandomDoubles(int count){
this.count = count;
}
@Override
public int read(CharBuffer cb) throws IOException {
if(count-- == 0){
return -1;
}
String result = Double.toString(next()) + " ";
cb.append(result);
return result.length();
}
public static void main(String[] args){
Scanner s = new Scanner(new AdaptedRandomDoubles(7));
while(s.hasNextDouble()){
System.out.print(s.nextDouble() + " ");
}
}
}
即创建一个适配器类,继承自现有类,同时实现相应的接口方法。
9.7 接口中的域
接口中的域(成员变量)都是隐式声明为static和final的。
9.7.1 初始化接口中的域
在接口中定义的域不能是空final,并且在类第一次加载时初始化。
9.8 嵌套接口
接口可以嵌套在类或其他接口中。
package com.mzm.chapter09;
public class NestingInterfaces {
public class BImp implements A.B{
@Override
public void f() {
}
}
public class CImp implements A.C{
@Override
public void f() {
}
}
//D是private
//class DImp implements A.D{}
class EImp implements E{
@Override
public void g() {
}
}
class EGImp implements E.G{
@Override
public void f() {
}
}
class EGImp2 implements E{
@Override
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 = a.getD();
//只能返回A.D类型,而a.getD()是返回D类型
//A.DImp2 di2 = a.getD();
//不能访问f()
//a.getD().f();
//只有另外一个A类型的对象能操作getD()方法。
A a2 = new A();
a2.receiveD(a.getD());
}
}
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){
dRef = d;
dRef.f();
}
}
interface E{
interface G{
void f();
}
public interface H{
void f();
}
void g();
//不能声明为private
//private interface I{}
}
9.9 接口与工厂
工厂方法设计模式:在工厂对象上调用创建方法,生成接口的某个实现的对象,这样可以将代码完全与接口的实现分离,方便替换实现。
package com.mzm.chapter09;
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 Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}
}
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implentation1 implements Service{
Implentation1(){
}
@Override
public void method1() {
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
System.out.println("Implementation1 method2");
}
}
class Implementation1Factory implements ServiceFactory{
@Override
public Service getService() {
return new Implentation1();
}
}
class Implentation2 implements Service{
Implentation2(){
}
@Override
public void method1() {
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
System.out.println("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory{
@Override
public Service getService() {
return new Implentation2();
}
}