建立通用接口的目的是:使子类继承从而不同的子类可以用不同的方式表示此接口。通用接口建立起一种基本的形式,以此表示所有子类的共同部分。可以称这种的类为抽象类,创建抽象类是希望通过这个通用接口操纵一系列。
定义抽象方法,仅有声明而没有方法体,比如abstract void f();
,包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的
抽象类不能初始化对象,否则会报编译期错误,如果从一个抽象类继承,并创建子类的对象,子类在创建时必须实现抽象类提供的方法定义。如果不这么做,那么子类也是抽象类,编译器会强制要求用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);
}
public String what(){
return "Wind";
}
public void adjust(){}
}
class Percussion extends Instrument{
@Override
public void play(Note n) {
System.out.println("Percussion.play()" + n);
}
public String what(){
return "Percussion";
}
public void adjust(){}
}
class Stringed extends Instrument{
@Override
public void play(Note n) {
System.out.println("Stringed.play()" + n);
}
public String what(){
return "Stringed";
}
public void adjust(){}
}
class Brass extends Wind{
public void play(Note n) {
System.out.println("Brass.play()" + n);
}
public String what(){
return "Brass";
}
}
class Woodwind extends Wind{
public void play(Note n) {
System.out.println("Woodwind.play()" + n);
}
public String what(){
return "Woodwind";
}
}
public class Music4 {
static void tune(Instrument i){
i.play(Note.MIDDLE_C);
}
static void tuneAll(Instrument[] e){
for(Instrument i : e){
tune(i);
}
}
public static void main(String[] args) {
Instrument[] orchestra = {
new Wind(),
new Percussion(),
new Stringed(),
new Brass(),
new Woodwind()
};
tuneAll(orchestra);
}
}
interface关键字产生一个完全抽象的类,方法不提供任何具体实现。它允许创建者确定方法名、参数列表和返回类型,但是没有任何方法提。接口只提供了形式,而未提供任何具体实现
创建接口类,需要interface关键字来替代class关键字。可以在interface关键字前面添加public关键字(但仅限于该接口在其同名的文件中被定义)。如果不添加public关键字,则它只具有包访问权限,这样它就只能在同一个包内可用。在接口中可以显式地将方法声明为public的,但即使不这么做,它们也是public的。接口也可以包含域,但是这些域隐式地是static 和final的。
一个类实现某个特定接口(或者是一组接口),需要使用implements关键字,一个类实现了某个接口后,这个类就成为一个普通的类,就可以用常规的方式使用继承这个类的方法或扩展这个类的方法
interface Instrument{
int VALUE = 5;
void play(Note n);
abstract void adjust();
}
class Wind implements Instrument{
public void play(Note n) {
System.out.println(this + ".play()" + n);
}
@Override
public String toString() {
return "Wind";
}
public void adjust(){}
}
class Percussion implements Instrument{
public void play(Note n) {
System.out.println(this + ".play()" + n);
}
@Override
public String toString() {
return "Percussion";
}
public void adjust(){}
}
class Stringed implements Instrument{
public void play(Note n) {
System.out.println(this + ".play()" + n);
}
@Override
public String toString() {
return "PercusStringedsion";
}
public void adjust(){}
}
class Brass extends Wind{
@Override
public String toString() {
return "Brass";
}
}
class Woodwind extends Wind{
@Override
public String toString() {
return "Woodwind";
}
}
public class Music5 {
static void tune(Instrument i){
i.play(Note.MIDDLE_C);
}
static void tuneAll(Instrument[] e){
for(Instrument i : e){
tune(i);
}
}
public static void main(String[] args) {
Instrument[] orchestra = {
new Wind(),
new Percussion(),
new Stringed(),
new Brass(),
new Woodwind()
};
tuneAll(orchestra);
}
}
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);
}
}
上述例子中:Apply.process()方法接受任何类型的Processor,并将接受的Object对象s传递给Processor的process方法处理,然后打印结果。这样创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而策略包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。这里,Processor对象就是一个策略,在main()方法中可以看到有三种不同类型的策略应用到了String类型的s对象上
spilt()方法是String类的一部分,它接受String类型的对象,并以传递进来的参数作为边界,将String对象分隔开,然后返回一个数组[]。它在这里被用来当作创建String数组的快捷方式
子类继承非接口和多个接口:class A extends B implements Inter1,Inter2,Inter3{}
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);
u(h);
v(h);
w(h);
}
}
Hero组合了具体类ActionCharacter和接口CanFight、CanSwim、CanFly。当通过这种方式将一个具体类和多个接口组合到一起时,具体类必须放在前面,后面跟着的才是接口。Hero中没有显式地提供fight()的定义,由于在父类ActionCharacter存在fight()的定义,
通过继承,可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。这两种情况都可以获得新的接口
interface Monster{
void manace();
}
interface DangerousMonster extends Monster{ // 通过继承在新接口中添加新的方法声明
void destory();
}
interface Lethal{
void kill();
}
class DragonZilla implements DangerousMonster{
@Override
public void manace() {}
@Override
public void destory() {}
}
interface Vampire extends DangerousMonster,Lethal{ // 通过继承在新接口中组合数个接口
void drinkBlood();
}
class VeryBadVampire implements Vampire{
@Override
public void manace() {
}
@Override
public void destory() {
}
@Override
public void kill() {
}
@Override
public void drinkBlood() {
}
}
public class HarrorShow {
}
接口最吸引人的原因之一就是允许同一个接口具有多个不同的具体实现。它的体现形式通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取决于方法的使用者。因此接口的一种常见用法就是 策略设计模式,编写一个执行某些操作的方法,而该方法接受一个同样是你指定的接口。
因为放入接口中的任何域都自动是statice和final的,所以接口成为了一种很便捷的用来常见常量组的工具。Java中标识具有常量初始化值的static final时,会使用大写字母的风格(标识符中用下划线来分隔多个单词)。接口中的域自动是public。但JavaSE5后,可以使用更加强大而灵活的enum关键字。
在接口中定义的域不能是“空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.nextFloat() * 10;
double RANDOM_DOUBLE = RAND.nextDouble() * 10;
}
域是static的,它们就可以在类第一次加载时被初始化,这发生在任何域首次被访问。并且这些域并不是接口的一部分,它们的值被存储在该接口的静态存储区域内
public class TestRandVals {
public static void main(String[] args) {
System.out.println(RandVals.RANDOM_INT);
System.out.println(RandVals.RANDOM_LONG);
System.out.println(RandVals.RANDOM_FLOAT);
System.out.println(RandVals.RANDOM_DOUBLE);
}
}
生成遵循某个接口的对象的典型方式就是工厂方法设计模式,在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现。
interface Service{
void method1();
void method2();
}
class Implementalion1 implements Service{
Implementalion1(){}
@Override
public void method1() {
System.out.println("Implementalion1 method1");
}
@Override
public void method2() {
System.out.println("Implementalion1 method2");
}
}
class Implementalion2 implements Service{
Implementalion2(){}
@Override
public void method1() {
System.out.println("Implementalion2 method1");
}
@Override
public void method2() {
System.out.println("Implementalion2 method2");
}
}
interface ServiceFactory{
Service getService();
}
class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implementalion1();
}
}
class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementalion2();
}
}
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());
}
}