[读书笔记]Java编程思想第9章之接口
Posted Spring-_-Bear
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[读书笔记]Java编程思想第9章之接口相关的知识,希望对你有一定的参考价值。
- Java提供了一个叫做抽象方法的机制,这种方法是不完整的;仅有声明而没有方法体。包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。如果从一个抽象类继承,并想创建该导出类的对象,那么就必须为基类中的所有抽象方法提供方法定义。如果不这样做,那么导出类便也是抽象类,且编译器会强制要求我们用abstract这个关键字来限定这个类。抽象的类不可以创建对象。
- abstract关键字允许人们在类中创建一个或多个没有任何定义的方法-提供了接口部分,但是没有提供任何相应的具体实现,这些实现是由此类的继承者创建的。interface这个关键字产生一个完全抽象的类,它根本就没有提供任何实现。接口也可以包含域,但是这些域隐式地势static和final的。当要实现一个接口时,在接口中被定义的方法必须被定义是public的。
- 向如下示例一般,创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。此例中,Processor对象就是一个策略,在main()中可以看到有三种不同类型的策略应用到了String类型的s对象上。
package thinkinginjava.charpenter9;
import java.util.Arrays;
/**
* @author Spring-_-Bear
* @version 2021/10/2 10:11
*/
public class Apply {
public static void process(Processor p, Object o) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(o));
}
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 {
@Override
String process(Object input) {
return ((String) input).toUpperCase();
}
}
class Downcase extends Processor {
@Override
String process(Object input) {
return ((String) input).toLowerCase();
}
}
class Splitter extends Processor {
@Override
String process(Object input) {
/**
* The split() argument divides a String into pieces:
*/
return Arrays.toString(((String) input).split(" "));
}
}
- 适配器设计模式:适配器的代码将接受你所拥有的接口,并产生你所需要的接口。将接口从具体实现中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具可复用性。
- Java中的多重继承:如果要从一个非接口的类继承,那么只能从一个类去继承。其余的基元素都必须是接口。需要将所有的接口名都置于implements关键字之后,用逗号隔开。
- 使用接口的核心原因:为了能够向上转型为多个基类型(以及由此而带来的灵活性)。然而,使用接口的第二个原因确实却是与使用抽象类相同:防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口。
- 通过继承类扩展接口:通过继承,可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合多个接口。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 10:12
*/
public class Adventure {
public static void t(CanFight canFight){
canFight.fight();
}
public static void u(CanSwim canSwim) {
canSwim.swim();
}
public static void v(CanFly canFly){
canFly.fly();
}
public static void w(ActionCharacter actionCharacter){
actionCharacter.fight();
}
public static void main(String[] args) {
Hero hero = new Hero();
t(hero);
u(hero);
v(hero);
w(hero);
}
}
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
public void swim() {
}
@Override
public void fight() {
super.fight();
}
@Override
public void fly() {
}
}
- 接口中的任何域都自动是static和final的,所以接口就成为了一种很便捷的用来创建常量组的工具。在接口中定义的域不能是"空final",但是可以被非常量表达式初始化。既然域是static的,它们就可以在类第一次被加载时初始化。当然,这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域内。
- 接口可以嵌套在类或其他接口中。当实现某个接口时,并不需要实现嵌套在其内部的任何接口。
10.接口与工厂:接口是实现多重继承的途径,而生成遵循某个对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 11:26
*/
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service service = fact.getService();
service.method1();
service.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}
}
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
Implementation1() {
}
@Override
public void method1() {
System.out.println("Implementation1.method1()");
}
@Override
public void method2() {
System.out.println("Implementation2.method2()");
}
}
class Implementation1Factory implements ServiceFactory{
@Override
public Service getService() {
return new Implementation1();
}
}
class Implementation2 implements Service{
Implementation2(){}
@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 Implementation2();
}
}
为什么我们想要添加这种额外级别的间接性呢?一个常见的原因是想要创建框架。
练习1: 修改第8章练习9中的Rodent,使其成为一个抽象类。只要有可能,就将Rodent的方法声明为抽象方法。
练习2: 创建一个不包含任何抽象方法的抽象类,并验证我们不能为该类创建任何实例。
练习3: 创建一个基类,让它包含抽象方法print(),并在导出类中覆盖该方法。覆盖后的方法版本可以打印导出类中定义的某个整型变量的值。在定义该变量之处,赋予它非零值。在基类的构造器中调用这个方法。现在,在main()方法中,创建一个导出类对象,然后调用它的print方法。请解释发生的情形。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 11:47
*/
public class HpPrinter extends Printer {
private int temp = 88;
@Override
void print(){
System.out.println("The values of temp is " + temp);
}
public static void main(String[] args) {
HpPrinter printer = new HpPrinter();
printer.print();
}
}
abstract class Printer {
Printer() {
print();
}
abstract void print();
}。
练习4: 创建一个不包含任何方法的抽象类,从它那里导出一个类,并添加一个方法。创建一个静态方法,它可以接受指向基类的引用,将其向下转型到导出类,然后再调用该静态方法。在main()中,展示它的运行情况。然后,为基类中的方法加上abstract声明,这样就不再需要进行向下转型。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 12:38
*/
public class Dog extends Animal {
void eat() {
System.out.println("Dog.eat()");
}
static void method(Animal animal) {
((Dog) animal).eat();
}
public static void main(String[] args) {
Animal dog = new Dog();
Dog.method(dog);
}
}
abstract class Animal {
}
练习5: 在某个包内创建一个接口,内含三个方法,然后在另一个包中实现此接口。
练习6: 证明接口内所有的方法都自动是public的。
练习7: 修改第8章中的练习9,使Rodent成为一个接口。
练习8: 在polymorphism.Sandwich.java中,创建接口FastFood并添加合适的方法,然后修改Sandwich以实现FastFood接口。
练习9: 重构Music5.java,将在Wind、Percussion和Stringed中的公共方法移入一个抽象中。
练习10: 修改Music5.java,添加Playable接口。将play()的声明从Instrument中移到Playable中。通过将Playable包括在Implements列表中,把Playable添加到导出类中。修改tune(),使它接受Playable而不是Instrument作为参数。
练习11: 创建一个类,它有一个方法用于接受一个String类型的参数,生成的结果是将该参数中每一对字符进行互换。对该类进行适配,使得它可以用于interfaceprocessor.Apply.process()。
练习12: 在Adventure.java中,按照其他接口的样式,增加一个CanClimb接口。
练习13: 创建一个接口,并从该接口继承两个接口,然后从后面两个接口多重继承第二个接口。
练习14: 创建三个接口,每个接口都包含两个方法。继承出一个接口,它组合了这三个接口并添加了一个新方法。创建一个实现了该新接口并且继承了某个具体类的类。现在编写四个方法,每一个都接受这四个接口之一作为参数。在main()方法中,创建这个类的对象,并将其传递给这四个方法。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 15:25
*/
public class Person extends Animal implements Behavior {
@Override
public void forward() {
System.out.println("Person.forward()");
}
@Override
public void back() {
System.out.println("Person.back()");
}
@Override
public void chew() {
System.out.println("Person.chew()");
}
@Override
public void gulping() {
System.out.println("Person.gulping()");
}
@Override
public void loud() {
System.out.println("Person.loud()");
}
@Override
public void low() {
System.out.println("Person.low()");
}
@Override
public void drink() {
System.out.println("Person.drink()");
}
@Override
void smell() {
System.out.println("Person.smell()");
}
public static void move(Move move) {
move.back();
move.forward();
}
public static void eat(Eat eat) {
eat.chew();
eat.gulping();
}
public static void speak(Speak speak) {
speak.loud();
speak.low();
}
public static void behavior(Behavior behavior) {
behavior.drink();
}
public static void main(String[] args) {
Person person = new Person();
move(person);
eat(person);
speak(person);
behavior(person);
}
}
interface Move {
void forward();
void back();
}
interface Eat {
void chew();
void gulping();
}
interface Speak {
void loud();
void low();
}
interface Behavior extends Move, Eat, Speak {
void drink();
}
class Animal {
Animal() {
System.out.println("Animal constructor");
}
void smell() {
System.out.println("Animal.smell()");
}
}
练习15: 将前一个练习修改为:创建一个抽象类,并将其继承到一个导出类。
练习16: 创建一个类,它将生成一个char序列,适配这个类,使其可以成为Scanner对象的一种输入。
练习17: 证明在接口中的域隐式地是static和final的。
练习18: 创建一个Cycle接口及其Unicycle、Bicycle和Tricycle实现。对每种类型的Cycle都创建相应的工厂,然后编写代码使用这些工厂。
package thinkinginjava.charpenter9;
/**
* @author Spring-_-Bear
* @version 2021/10/3 15:45
*/
public class FactoryMode {
public static void cycleConsumer(CycleFactory cycleFactory) {
Cycle cycle = cycleFactory.getCycle();
cycle.back();
cycle.forward();
}
public static void main(String[] args) {
cycleConsumer(new BicycleFactory());
cycleConsumer(new UnicycleFactory());
cycleConsumer(new TricycleFactory());
}
}
interface Cycle {
void back();
void forward();
}
interface CycleFactory {
Cycle getCycle();
}
class Unicycle implements Cycle {
@Override
public void back() {
System.out.println("Unicycle.back()");
}
@Override
public void forward() {
System.out.println("Unicycle.forward()");
}
}
class Bicycle implements Cycle {
@Override
public void back() {
System.out.println("Bicycle.back()");
}
@Override
public void forward() {
System.out.println("Bicycle.back()");
}
}
class Tricycle implements Cycle {
@Override
public void back() {
System.out.println("Tricycle.back()");
}
@Override
public void forward() {
以上是关于[读书笔记]Java编程思想第9章之接口的主要内容,如果未能解决你的问题,请参考以下文章