美文网首页想法读书简友广场
Java 编程思想笔记六:接口和内部类

Java 编程思想笔记六:接口和内部类

作者: 红薯的Java私房菜 | 来源:发表于2022-07-24 17:49 被阅读0次

第9章《接口》和第10章《内部类》主要介绍了抽象类、接口、内部类、匿名类以及嵌套类等概念,以及它们的区别和联系。主要内容如下:


接口和内部类

1.抽象类(abstract)

抽象类也称抽象基类,用于表示所有导出类的共同部分,是普通类和接口间的中庸之道,用关键字 abstract 限定。例如我们之前的“乐器”例子中的 Instrument 类就可以定义为抽象类。

我们可以通过抽象类操作一系列导出类,然而创建抽象类对象则没有什么意义,为防止使用者创建抽象类对象做一些没有意义的事情,Java 提供了抽象方法机制,抽象方法只有声明没有方法体。以创建 Instrument 抽象类为例:

abstract class Instrument {         // 抽象类
    public abstract void play();    // 抽象方法
    public String what() { return "Instrument"; }   // 抽象类中的方法也可以包含方法定义
}

如果一个类包含一个或多个抽象方法,该类必须被限定为抽象类,否则编译会报错。

如果从一个抽象类继承,并想创建该导出类的对象,那么导出类必须要为基类中的所有抽象方法提供方法定义,否则导出类也是抽象类,必须用 abstract 关键字限定。

2.接口(interface)

2.1.接口概念

接口和抽象方法相比更向前迈进一步,interface 关键字会产生一个完全抽象的类,没有提供任何具体实现,只允许创建者确定方法名、参数列表和返回类型,没有任何方法体。以创建 Instrument 接口为例:

interface Instrument {         // 接口
    void play(Note n);
    String what();
}

注意,上面接口中 interface 前面没有加 public 关键字,说明具有包访问权限,该接口只能在同一个包中可用。接口中的方法没有使用 public 关键字限定,但是它们自动就是 public 的

要想让某个类遵循(实现)某个接口,需要用 implements 关键字:

class Wind implements Instrument {
    public void play(Note n) {
        print(this + ".play() " + n);
    }

    public String what() {
        return "Wind";
    }
}

2.2.几种常用设计模式

策略设计模式

创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,即被称为策略设计模式。通过接口即可实现,接着上面的例子,如果想要实现一个 “演奏乐曲” 的方法,不同的乐器演奏出的效果是不同的,可以这样设计:

// Wind 类上面已经实现了 Instrument 接口,这里忽略
class Stringed implements Instrument {
    public void play(Note n) {
        print(this + ".play() " + n);
    }

    public String what() {
        return "Stringed";
    }    
}

// 演奏乐曲
public class PlayMusic {
    String name;
    public void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }
}

public static void main(String[] args) {
    PlayMusic player = new PlayMusic();
    player.tune(new Wind());
    player.tune(new Stringed());
}

Wind.play() MIDDLE_C
Stringed.play() MIDDLE_C

策略模式和多态是一个思想,只不过多态是通过继承和方法重写实现的一种语言机制,而策略模式是一种算法,强调做一件事情的不同方法,方法间不能重复。

适配器设计模式

以榨汁机为例,榨汁机(Juicer)可以将水果(Fruits)榨成果汁:

// 水果
public class Fruits {
    private String name;
    private Fruites(String n) { name = n; }
    public string toString() { return "Fruits " + name; }
}

// 榨汁机
public interface Juicer {
    String work(Fruits f);
}

现在我们购买一个九阳榨汁机开始榨汁:

// 九阳榨汁机
public class JiuyangJuicer implements Juicer {
    public String work(Fruits f) { return "Jiuyang juicing: " f.toString; }
}

// 榨汁机开始榨汁
public class JuicerWord {
    JiuyangJuicer juicer = new JiuyangJuicer();
    String result = juicer.work(new Fruits("apple"));
    print(result);
}

Jiuyang juicing: apple

但是问题来了,现在插排只能插两孔插座的榨汁机(老式榨汁机 OldJuicer),九阳榨汁机是三孔的,现在怎么办?-- 我们可以买个适配器(JuicerAdapter):

public class JuicerAdapter implements Juicer {
    JiuyangJuicer juicer;
    public JuicerAdapter(JiuyangJuicer juicer) {
        this.juicer = juicer;
    }
    public String work(Fruits f) { juicer.work("apple"); }
}

public class JuicerAdapterWork {
    JiuyangJuicer juicer = new JiuyangJuicer();                 // 我们的九阳榨汁机
    JuicerAdapter juicerAdapter = new JuicerAdapter(juicer);    // 买的适配器
    String result = juicerAdapter.work(new Fruits("apple"));    // 通过适配器开始榨汁
    print(result);
}

2.3.多重继承

一个类只能继承自一个基类,但是可以继承自多个接口:

interface CanFight { void fight(); }
interface CanSwim { void swim(); }
class ActionCharacter { public void fight() {} }

class Hero extends ActionCharacter implements CanFight, CanSwim {
    public void fight() {}
    public void swim() {}
}

3.内部类

将一个类的定义置于另一个类内部,就是内部类。例如:

public class Parcel {
    class Contents {
        private int i = 11;
        public int value() { return i; }
    }
    class Destination {
        private String lable;
        Destination(String whereTo) {
            lable = whereTo;
        }
        String readLable() { return label; }
    }
    public Destination to(String s) {
        return new Destination(s);      // 返回内部类的引用
    }
    public Contents contents() {
        return new Contents();
    }
    public void ship(String dest) {     // 外围类的内部使用内部类
        Contents c = new Contents();
        Destination d = new Destination(dest);
        System.out.println(d.readLable());
    }
    public static void main(String[] args) {
        Parcel p = new Parcel();        
        p.ship("Tasmania");
        Parcel.Contents c = p.contents();   // 对外围类使用内部类
        Parcel.Destination d = p.to("Borneo");
    }
}

3.1.内部类的特性

1.可以访问外围对象的所有方法和字段,但外围对象不可以访问内部类的方法和元素;
2.如果内部类位于方法的作用域内(即局部内部类),对于外围类的对象是不可见的。

3.2.生成内部类对象

想要创建外围类对象,必须通过创建外围类实现。在拥有外围类之前是不可能创建内部类对象的。因为内部类对象会暗暗地连接到创建它的外围类对象上(但如果你创建的是嵌套类 -- 静态内部类,就不需要对外围类对象的引用)。

public class DotThis {
    void f() { System.out.println("DotThis.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();             // 1.生成外围类
        DotThis.Inner dti = dt.inner();         // 2.1.方法一:通过外围类生成内部类
        DotThis.Inner dtiN = dt.new Inner();    // 2.2.方法二:通过 .new 生成内部类
        dti.outer().f();                        // 3.内部类调用外围类的方法
    }
}

客户端无法访问 private 内部类,通过这种方式可以完全阻止任何依赖于类型的编码,并且完全隐藏实现的细节。

3.3.匿名类

匿名类是一种继承自某个类或者实现某个接口没有名字的类:

public class Parcel9 {
    public Destination destination(final String dest) {
        return new Destination() {
            private String lable = dest;
            public String readLable() { return lable; }
        };
    }
}

使用匿名类需要注意以下几点:
1.匿名类要使用一个外部定义的对象,为保证内部类和外围类参数的一致性,其参数引用必须是 final 的;
2.使用匿名类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
3.匿名类中是不能定义构造函数的;
4.匿部类中不能存在任何的静态成员变量和静态方法;
5.匿名类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效;
6.匿名类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

3.4.嵌套类

嵌套类是静态内部类,即嵌套类对象和外围类对象之间没有任何联系。所以与普通内部类相比嵌套类具有以下特点:

1.创建嵌套类对象前不需要外围类的对象;
2.不能从嵌套类对象中访问非静态的外围类对象;
3.普通内部类的字段和方法只能放在外部层次上,不能有 static 数据和 static 字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西。

例如可以使用嵌套类来放置我们的测试代码:

public class TestBed {
    public void f() { System.out.println("f()"); }
    public static class Tester {
        public static void main(String[] args) {    // 嵌套类
            TestBed t = new TestBed();
            t.f();
        }
    }
}

3.5.闭包

内部类这部分提到了闭包的概念,但是我并没有看懂,然后自己在网上看了一些帖子,感觉这个解释的很明白:

闭包能够将一个方法作为变量去存储 --> Java里将内部类对象向上转型为接口类型即可实现闭包!

3.6.局部内部类

局部内部类创建于方法体内部,可以访问外围类所有成员,但是外围成员不可以访问局部内部类。

interface ILog { void write(); }
public class LocalInnerClass {
    private int length =0;
    public ILog logger() {
        class InnerClass implements ILog {  // 局部内部类
            public void write(String message) {
                length = message.length();
                System.out.println("LocalInnerClass.InnerClass:" + length);
            }
        }
        return new InnerClass();
    }
}

3.7.内部类继承

class WithInner { class Inner() {} }

public class InheritInner extends WithInner.Inner {
    // InheritInner() {}    -- 编译错误
    InheritInner(WithInner wi) { wi.super(); }
}

首先继承时要指明外围类和内部类的关系,其次是构造内部类对象时必须使用 .super 提供指向外围类的引用。

相关文章

  • Java 编程思想笔记六:接口和内部类

    第9章《接口》和第10章《内部类》主要介绍了抽象类、接口、内部类、匿名类以及嵌套类等概念,以及它们的区别和联系。主...

  • 2018-08-06

    学习java编程思想的第一天 今天要把内部类看完。

  • Java编程思想学习笔记(8)

    Java编程思想学习笔记(8) Java多态 多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来。 同时...

  • PHP转JAVA的记录

    Java 数组 内部类 内部类的创建:内部类可以对包内其他类隐藏想实现一个接口时, 不想新建类文件 内部类可以访问...

  • java编程思想——接口

    接口与内部类为我们提供了一种接口与实现分离的更加结构化的方法。 1.抽象类与抽象方法 抽象类,作为普通的类和接口之...

  • Java编程思想笔记10.内部类

    点击进入我的博客 可以把一个类的定义放在另一个类的定义内部,这就是内部类。Java最晦涩的部分之一内部类看起来就像...

  • Java基础:内部类

    Java中有一种特殊的类,是写在类里面的,叫作内部类。内部类又分为成员内部类、局部内部类、静态内部类、接口内部类和...

  • Java编程思想笔记9.接口

    点击进入我的博客 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。 9.1抽象类和抽象方法 抽象方...

  • Java编程思想(九) 内部类

    将一个类的定义放在另一个类的定义内部就是内部类 1、创建内部类 典型的情况是,外部类有一个方法,该方法返回一个指向...

  • 2021-09-15 JAVA编程思想

    Java编程思想重点笔记(Java开发必看)[https://www.cnblogs.com/softwareof...

网友评论

    本文标题:Java 编程思想笔记六:接口和内部类

    本文链接:https://www.haomeiwen.com/subject/ckhwirtx.html