续 接口
9.2 接口
- Interface关键字使抽象的概念更向前迈进了一步.abstract关键字允许人们在类中创建一个或多个没有任何定义的方法--提供了接口部分,但是没有提供任何相应的具体实现,这些实现是由类的继承者创建的.
Interface这个关键字产生了一个完全抽象的类,他根本就没有提供任何具体实现.他允许创建者确定方法名 参数列表和返回类型,但是没有任何方法体.接口只提供了形式,而未提供任何具体实现.
- interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性.
- 就像类一样,可以在interface关键字前面添加public关键字,如果不添加public关机找你,则它只有包访问权限,这样它就只能在同一个包内可用.接口也可以包含域,但是这些域隐式地是static和final的.
- 可以选择在接口中显式地方法声明为public的,但即使你不这么做,他们也是public的.
9.3完全耦合
- 用代码来解释一下耦合关系(刚开始没有看懂第二天又看才看懂)
//看两点
//1. class Processor 而不是 interface Processor(现象:完全耦合.造成应用领域太小)
//2. //如果Process是一个接口,那么这些限制就会变得松动,是的你可以复用结构该接口的Apply.process().
class Processor{//public interface Processor{String name(); Object process(Object input);}
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){
// The split() argument divides a String into pieces;
return Arrays.toString(((String)input).split(" "));
}
}
//现在我们发现了一组电子滤波器 看起来是和上面的差不多,但是我们不能够取用主方法里面的Apply.process()方法
//那么通过下面的代码就可以看出来 这样写代码的复用性太差.
public class Waveform {
private static long counter;
private final long id = counter++;
public String toString(){
return "Waveform "+ id;
}
}
public class Filter {
public String name(){
return getClass().getSimpleName();
}
public Waveform process(Waveform input){
return input;
}
}
public class LowPass extends Filter {
double cutoff;
public LowPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;//Dummy processing
}
}
public class HighPass extends Filter {
double cutoff;
public HighPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
public class BandPass extends Filter {
double lowCutoff,highCutoff;
public BandPass(double lowCut,double highCut){
lowCutoff = lowCut;
highCutoff = highCut;
}
public Waveform Process(Waveform input){
return input;
}
}
//这样,创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式
public class Apply {
public static void process (Processor p,Object s){
print("Using Processor " + p.name());
print(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);
}
}
- 解耦 适配器模式
class FilterAdapter implements Process{
Filter filter;
public FilterAdapter(Filter filter){
this.filter = filter;
}
public String name(){
return filter.name();
}
public Waveform process (Object input){
return filter.process((Waveform)input);
}
}
public class FilterProcess{
public static void main(String[] args){
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)),w);
Apply.process(new FilterAdapter(new HighPass(2.0)),w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)),w);
}
}
9.4Java中的多重继承
- 注意一点implements关键字之后,可以继承多个接口,并可以向上转型为每个接口.
9.5通过继承来扩展接口
interface Monster{
void mence();
}
interface DangeousMonster extends Monster{
void destroy();
}
9.7接口中的域
- 接口中的域隐式地是static和final的
9.9接口与工厂(难点与重点)可以说是必知必会的东西
- 文字描述:接口时实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式.
- 这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象.理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现.
package cn.itcast.zhuofai730.demo9_9;
import java.util.ServiceConfigurationError;
import static cn.itcast.zhuofai730.util.Print.print;
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
Implementation1(){}//Package access
public void method1(){print("Implementation1 method1");}
public void method2(){
print("Implementation method2");
}
}
class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implementation1();
}
}
class Implementation2 implements Service{
Implementation2(){}//Pakage access
@Override
public void method1() {
print("Implementation2 method1");
}
@Override
public void method2() {
print("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementation2();
}
}
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());
//Implementations are completely interchangeable;
serviceConsumer(new Implementation2Factory());
}
}
number two program
package cn.itcast.zhuofai730.demo9_9;
import static cn.itcast.zhuofai730.util.Print.print;
interface Game{boolean move();}
interface GameFactory {Game getGame();}
class Checkers implements Game{
private int moves = 0;
private static final int MOVES = 3;
public boolean move(){
print("Checker move" + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory{
public Game getGame(){
return new Checkers();
}
}
class Chess implements Game{
private int moves = 0;
private static final int MOVES = 4;
public boolean move(){
print("Chess move "+ moves);
return ++moves != MOVES;
}
}
class ChessFactory implements GameFactory{
public Game getGame(){
return new Chess();
}
}
public class Games {
public static void playGame(GameFactory factory){
Game s = factory.getGame();
while(s.move())
;
}
public static void main(String[] args) {
playGame(new CheckersFactory());
playGame(new ChessFactory());
}
}
内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类
内部类是一种非常有用的特性,因为他允许你把一些逻辑相关的泪组织在一起,并控制位于内部的类的可视性,然而必须要了解,内部类与组合是完全不同的概念,这一点很重要.
10.1创建内部类
- 如果想从外从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须像在main()方法中那样,具体指明这个对象的类型:OuterClassName.InnerClassName.
10.2链接到外部类
- 当生成一个内部类对象时,此对象与制造它的外围对象(enclosing object)之间就有了一种联系,使用它能访问其外围对象的所有成员,而不需要任何条件.
- 当外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用.然后你在访问此外围类的成员时,就是用那个引用来选择外围类的成员.
//这个例子可以和10.3一起来看
//利用外部方法来创建内部类对象
//Selector selector = sequence.selector();
//相当于this.newSequenceSelector();
interface Selector{
}
public class Sequence {
public void add(Object x){}
private class SequenceSelector implements Selector{}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args){
Sequence sequence = new Sequence(10);
Selector selector = sequence.selector();
}
}
10.3使用.this与.new
内部类就像一个方法一样用外部类"."外部类调用
- 如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this.
//DotThis.this;返回一个外部类的引用,前面讲了
//>当外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用.
//所以利用DotThis.this可以获取DotThis对象
public class DotThis {
void f(){
System.out.println("DoThis.f()");
}
public class Inner{
public DotThis outer(){
return DotThis.this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f();
}
}
- 创建其某个内部类的对象.实现此目的,你必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法.
public class DotNew {
public class Inner{}
public static void main(String[] args) {
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
}
- 在拥有外部类对象之前是不可能创建内部类对象的.这是因为内部类对象会暗暗地连接到创建它的外部类对象上.但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部类对象的引用.
10.4内部类与向上转型
- 当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的.)这是因为此内部类--某个接口的实现--能够完全不可见,并且不可用.所得到的知识指向基类或接口的引用,使用能够很方便地隐藏实现细节.
public interface Contents {
int value();
}
public interface Destination {
String readLabel();
}
class Parcel4{
private class PContents implements Contents{
private int i = 11;
@Override
public int value() {
return i;
}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
public Destination destination(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
}
public class TestParcel {
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Contents c = p.contents();
Destination d = p.destination("Tasmania");
}
}
10.5 在方法和作用域内的内部类
- 声明定义内部类的两个理由
- 你实现了某类型的接口,于是可以创建并返回对其的引用.
- 你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类时公共可用的.
- 定义类的方式
- 一个定义在方法中的类
- 一个定义在作用域内的类,此作用域在方法的内部.
- 一个实现了接口的匿名类
- 一个匿名类,它扩展了有非默认构造器的类
- 一个匿名类,他执行字段初始化
- 一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
10.6匿名内部类
//两个知识点
//1. 如果基类需要一个有参数的构造器,只需要简单地传递合适的参数给基类的构造器即可
//2. 尽管Wrapping只是一个具有具体实现的普通类,但它还是被其导出类当作公共"接口"来使用
public class Wrapping {
private int i;
public Wrapping(int x){
i = x;
}
public int value(){
return i;
}
}
public class Parcel8 {
public Wrapping wrapping(int x){
return new Wrapping(x){
public int value(){
return super.value() * 47;
}
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
- 如果定义一个匿名内部类,并且希望它使用一个在他其他外部定义的对象,那么编译器会要求其参数引用是final的.
10.7嵌套类
- 如果不需要内部类对象与外围类对象之间有联系,那么可以将内部类声明为static.
- 理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象.然而,当内部类时static时,就不是这样了.
- 嵌套类意味着:
- 要创建嵌套类的对象,并不需要其外围类的对象.
- 不能从嵌套类的对象中访问非静态的外围类对象.
- 嵌套类与普通的内部类还有一个区别.普通内部类的字段与方法,只能放在累的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类.但是嵌套类可以包含所有东西.
网友评论