抽象类和抽象方法
如果一个类提供一个通用的接口供不同子类继承, 它本身的实例化并没有任何意义, 那么可以使用abstract关键字限制其类为抽象类.
一个类只要出现abstract则必须为抽象类, 而抽象类中的抽象方法在子类中必须实现其定义.
abstract class A {
public void show() {
func();
}
public abstract void func();
}
public class B extends A{
public void func() {
System.out.println("B func");
}
public static void main(String[] args) {
B b = new B();
b.show();
}
}
接口
抽象类允许在类中定义方法. 但接口比抽象类更加的抽象: 它不提供任何具体实现, 只允许创建者确定方法名,参数列表和返回类型.
所以,interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能否被向上转型为多种基类的类型,来实现某种类似多重继承变种的特性.
使用关键字interface定义接口, 使用implements实现此接口
interface A {
void show();
}
class B implements A{
public void show() {
System.out.println("B show()");
}
}
public class C {
public static void func(A a) {
a.show();
}
public static void main(String[] args) {
B b = new B();
// B show()
func(b);
}
}
备注: 接口中所有方法默认为public权限, 而且必须为public.
我们可以通过反射机制来验证接口的类为public abstract:
import java.lang.reflect.*;
interface A {
void fun1();
void fun2();
}
class B implements A{
public void fun1() {
System.out.println("fun1");
}
public void fun2() {
System.out.println("fun2");
}
}
public class C {
public static void main(String[] args) {
try {
// output:
// public abstract void fun2()
// public abstract void fun1()
Class c1 = Class.forName("A");
Method[] methods = c1.getDeclaredMethods();
for (Method m: methods) {
Class retType = m.getReturnType();
String name = m.getName();
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0)
System.out.print(modifiers + " ");
System.out.print(retType.getName() + " " + name + "(");
Class[] paramTypes = m.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0) System.out.print(",");
System.out.print(paramTypes[j].getName());
}
System.out.println(")");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
完全解耦
继承有可能使得类与类之间过于紧密. 我们一般可以使用接口将接口和实现相分离.
一种实现的策略是: 定义1个接口A, 定义一个使用此接口的操作类B, 定义1个实现接口的类C, 在C中使用B, 定义N个操作类继承C, 则在C中由于存在向上转型, 则使用这N个操作类.
这种策略的一种扩展形式在于: 我们可以定义多个接口, 在同一个类中实现多个接口. 由于接口和实现可以完全分离, 这样达到完全的解耦.
interface A {
String name();
void show(String s);
}
class B {
public static void func(A a, String s) {
System.out.println(a.name());
a.show(s);
}
}
public class C implements A {
public String name() {
return getClass().getName();
}
public void show(String s) {
System.out.println("C " + s);
}
public static void main(String[] args) {
B.func(new C1(), "hello");
B.func(new C2(), "world");
}
}
class C1 extends C {
public void show(String s) {
System.out.println("C1 " + s);
}
}
class C2 extends C {
public void show(String s) {
System.out.println("C2 " + s);
}
}
Java中的多重继承
类通过实现多个接口来达到多重继承.
interface A {
void funA();
}
interface B extends A {
void funB();
}
interface C extends A {
void funC();
}
interface E extends B, C {
void funE();
}
public class D implements E {
public void funA() {
System.out.println("funA");
}
public void funB() {
System.out.println("funB");
}
public void funC() {
System.out.println("funC");
}
public void funE() {
System.out.println("funE");
}
public static void main(String[] args) {
D d = new D();
d.funA();
d.funB();
d.funC();
d.funE();
}
}
但使用多个接口会存在如下的情况: 方法的返回值不同导致继承的类无法进行分别(对于重载来说, 返回值不同的方法依旧为同一个方法.)
interface A {
int show();
}
interface B {
void show();
}
public class C implements A, B {
public int show() {
return 1;
}
public void show() {
}
public static void main(String[] args) {
// ERROR: int show() 和void show() 产生冲突
C c = new C();
}
}
出现这个问题,本身说明接口编写不够完善,需要修改接口.
适配接口
我们指定一个接口, 只要遵守此接口就可以调用此接口的其它方法.
例如针对Readable接口, 我们只要实现其read方法, 那么使用Scanner(其接受Readable接口)的其它方法(如hashNext, next)就可以读取其read的数据.
import java.nio.CharBuffer;
import java.util.Scanner;
import java.util.Random;
public class RandomWords implements Readable{
private static Random rand = new Random(47);
private static final char[] capitals =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers =
"abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels =
"aeiou".toCharArray();
private int count;
public RandomWords(int count) { this.count = count;}
public int read(CharBuffer cb) {
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());
}
}
}