🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## [接口适配](https://lingcoder.gitee.io/onjava8/#/book/10-Interfaces?id=%e6%8e%a5%e5%8f%a3%e9%80%82%e9%85%8d) 接口最吸引人的原因之一是相同的接口可以有多个实现。在简单情况下体现在一个方法接受接口作为参数,该接口的实现和传递对象则取决于方法的使用者。 因此,接口的一种常见用法是前面提到的*策略*设计模式。编写一个方法执行某些操作并接受一个指定的接口作为参数。可以说:“只要对象遵循接口,就可以调用方法” ,这使得方法更加灵活,通用,并更具可复用性。 例如,类**Scanner**的构造器接受的是一个**Readable**接口(在“字符串”一章中学习更多相关内容)。你会发现**Readable**没有用作 Java 标准库中其他任何方法的参数——它是单独为**Scanner**创建的,因此**Scanner**没有将其参数限制为某个特定类。通过这种方式,**Scanner**可以与更多的类型协作。如果你创建了一个新类并想让**Scanner**作用于它,就让它实现**Readable**接口,像这样: ~~~ // interfaces/RandomStrings.java // Implementing an interface to conform to a method import java.nio.*; import java.util.*; public class RandomStrings 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 RandomStrings(int count) { this.count = count; } @Override public int read(CharBuffer cb) { if (count-- == 0) { return -1; // indicates end of input } 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; // Number of characters appended } public static void main(String[] args) { Scanner s = new Scanner(new RandomStrings(10)); while (s.hasNext()) { System.out.println(s.next()); } } } ~~~ 输出: ~~~ Yazeruyac Fowenucor Goeazimom Raeuuacio Nuoadesiw Hageaikux Ruqicibui Numasetih Kuuuuozog Waqizeyoy ~~~ **Readable**接口只需要实现`read()`方法(注意`@Override`注解的突出方法)。在`read()`方法里,将输入内容添加到**CharBuffer**参数中(有多种方法可以实现,查看**CharBuffer**文档),或在没有输入时返回**\-1**。 假设你有一个类没有实现**Readable**接口,怎样才能让**Scanner**作用于它呢?下面是一个产生随机浮点数的例子: ~~~ // interfaces/RandomDoubles.java import java.util.*; public interface RandomDoubles { Random RAND = new Random(47); default double next() { return RAND.nextDouble(); } static void main(String[] args) { RandomDoubles rd = new RandomDoubles(){}; for (int i = 0; i < 7; i++) { System.out.println(rd.next() + " "); } } } ~~~ 输出: ~~~ 0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964 ~~~ 我们可以再次使用适配器模式,但这里适配器类可以实现两个接口。因此,通过关键字**interface**提供的多继承,我们可以创建一个既是**RandomDoubles**,又是**Readable**的类: ~~~ // interfaces/AdaptedRandomDoubles.java // creating an adapter with inheritance import java.nio.*; import java.util.*; public class AdaptedRandomDoubles implements RandomDoubles, Readable { private int count; public AdaptedRandomDoubles(int count) { this.count = count; } @Override public int read(CharBuffer cb) { 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() + " "); } } } ~~~ 输出: ~~~ 0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964 ~~~ 因为你可以以这种方式在已有类中增加新接口,所以这就意味着一个接受接口类型的方法提供了一种让任何类都可以与该方法进行适配的方式。这就是使用接口而不是类的强大之处。