接口
1.接口中方法属性
在接口中可以显式的将方法声明为public,但即使不这么做,它们也是public的,否则,它们将只能得到默认的包访问权限,这样在方法被继承的过程中,其可访问权限就被降低了,这是Java编译器所不允许的.
2.策略设计模式
这类方法包含所要执行的算法中固定不变的部分,而"策略"包含变化的部分.策略就是传进去的参数它包含所要执行的代码.在下面这个例子中,Processor对象就是一个策略,在main()中可以看到有三种不同类型的策略应用到了String类型的s对象上:
package day11;
import java.util.Arrays;
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){ //接收一个Processor的子类,并获取子类名称,然后运用子类的多态性.
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s)); //用子类对应的处理字符串的process方法来处理返回一个字符串.
}
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);
}
}
3.向上转型实现接口类
当实现了接口的子类被创建时,它可以被向上转型为每一个接口.
例如:
package day11;
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{ //ActionCharacter中已经实现了CanFight,无需再重复实现
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 hero = new Hero();
t(hero); //hero对象向上转型为CanFight对象
u(hero); //hero对象向上转型为CanSwim对象
v(hero); //hero对象向上转型为CanFly对象
w(hero); //hero对象向上转型为ActionCharater对象,但这次是继承关系的向上转型
}
}
4.什么时候使用接口
如果知道某事物应该成为一个基类,那么第一选择应该是使它成为一个接口.
5.extends引用多接口
一般来说,extends只可用于单一类,但是可以引用多个基类接口,只需要用逗号将接口名一一隔开即可.其次,对接口实例化可以通过已经实现了接口的子类进行实例化后向上转型:
例如:
代码中各接口和类的继承关系如下:
package day11;
interface Monster{
void menace();
}
interface DangerousMonster extends Monster{
void destroy();
}
interface Lethal{
void kill();
}
class DragonZilla implements DangerousMonster{
public void menace(){} //实现
public void destroy(){} //实现
}
interface Vampire extends DangerousMonster,Lethal{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
@Override public void menace() { } //实现
@Override public void destroy() { } //实现
@Override public void kill() { } //实现
@Override public void drinkBlood() { } //实现
}
public class HorrorShow {
static void u(Monster b){b.menace();}
static void v(DangerousMonster d){
d.menace();
d.destroy();
}
static void w(Lethal l){l.kill();}
public static void main(String[] args){
DangerousMonster barney = new DragonZilla();//实现接口类
u(barney);
v(barney);
Vampire vlad = new VeryBadVampire(); //实现接口类
u(vlad);
v(vlad);
w(vlad);
}
}
6.接口的策略设计模式
接口的一种常见用法就是前面提到的策略设计模式,此时你编写一个执行某些操作的方法,而该方法接受一个同样是你指定的接口.你主要就是要声明:"你可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口."这使得你的方法更加灵活、通用,并且具有复用性.
例如Scanner类的构造器接受的就是一个Readable接口,Readable没有用作Java标准类库中其他任何方法的参数,它是单独为Scanner创建的,以使得Scanner不必将其参数限制为某个特定类,通过这种方式,Scanner可以作用于更多的类型.如要你要创建一个新的类并且想让Scanner作用于它,那么久可以像下面这样:
package day11;
import java.nio.*;
import java.util.*;
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;}
//Readable接口值要求实现read()方法,在read()内部,将输入内容添加到CharBuffer参数中,或者在没有任何输入时返回-1;
public int read(CharBuffer cb){
//每读走一个单词,count就-1.直到为0就停止读取生成的随机单词.
if(count-- == 0){
return -1;
}
//rand.nextInt(int bound)返回int值介于0和指定值之间的随机一个数
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) {
//设置10次取值.执行10次read(),读出10个单词.
Scanner s = new Scanner(new RandomWords(10));
//输出这10个单词.
while (s.hasNext()) {
System.out.println(s.next());
}
}
}
另外,假如有一个还未实现Readable的类,怎样才能让Scanner作用于它呢?下面这个产生随机浮点数的例子可以说明:
例中原本有一个RandomDoubles类但未实现Readable接口,通过implements Readable类和继承原RandomDoubles类我们可以形成一个新类,这个新类就既是Random-Doubles又是Readable.这就也就一种适配器模式.
package day11;
import java.nio.*;
import java.util.*;
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;}
//Readable接口值要求实现read()方法,在read()内部,将输入内容添加到CharBuffer参数中,或者在没有任何输入时返回-1;
public int read(CharBuffer cb){
if(count-- == 0){
return -1;
}
//rand.nextInt(int bound)返回int值介于0和指定值之间的随机一个数
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) {
//设置10次取值.执行10次read(),读出10个单词.
Scanner s = new Scanner(new RandomWords(10));
//输出这10个单词.
while (s.hasNext()) {
System.out.println(s.next());
}
}
}