Java cheatsheet (V)

5.1. 内部类

一般的调用形式如下:

内部类有如下几点特性:

  1. 在另一个类的定义内部被定义;
  2. 生成一个内部类的对象时,它就与生成它的外部类的对象产生一个关联;
  3. 内部类拥有其外围类所有元素的访问权;
  4. 内部类的对象只能在与其外围类对象相关联的情况下才能被创建;
import java.util.*;

interface CanDisplay {
    void display();
}

public class Program {
    private String content = "This is an Outer object.";
    private class Inner implements CanDisplay {
        @Override
        public void display() {
            System.out.println(content);
        }
    }
    public Inner getDisplayer() {
        return new Inner();
    }
    public static void main(String[] args) {
        Program obj = new Program();
        Inner displayer = obj.getDisplayer();
        displayer.display();
    }
}

5.2. .this.new

.this 用于在内部类中获取外部类的引用:

class Outer {
    public class Inner {
        public Outer outer() {
            return Outer.this;
        }
    }
    public Inner inner() {
        return new Inner();
    } 
}

.new 基于一个外部类的对象创建一个与其关联的内部类对象:

class Outer {
    public class Inner {}
}

public class Program {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
    }
}

5.3. 使用 private 内部类实现接口以隐藏实现

可以在内部类中实现一个接口,然后在外部类的方法中通过这个接口类型返回内部类的引用。

这种情况下,内部类对使用者是完全隐藏的,但是可以通过这种方式来获取满足特定接口的内部对象引用。

import java.util.*;

interface CanDisplay {
    void display();
}

class Outer {
    private String content = "This is an Outer object.";
    private class Inner implements CanDisplay {
        @Override
        public void display() {
            System.out.println(content);
        }
    }
    public CanDisplay getDisplayer() {
        return new Inner();
    }
}

public class Program {
    public static void main(String[] args) {
        Outer obj = new Outer();
        CanDisplay displayer = obj.getDisplayer();
        displayer.display();
    }
}

5.4. 在函数及任意作用域中定义内部类

这种情况,内部类会被编译,但是在作用域(花括号)之外,不能调用。

这个类不能被调用,但是如果这个内部类实现了接口并且返回,则对象仍然是存在的。

细节略。

5.5. 匿名内部类

如果有这样一种定义:

import java.util.*;

class Base {
    int content;
    public Base(String s) {
        content = s;
    }
};

public class Program {
    class Inner extends Base {
        private int i = 11;
        private String str;
        public Inner(String s) {
            str = s;
        }
        public int value() { return i; }
    }
    public Base inner(String s) {
        return new Inner(s);
    }
    public static void main(String[] args) {
        Program outer = new Program();
        Base inner = outer.inner("Hello");
    }
}

我们可以用如下的匿名内部类的写法这样来写:

import java.util.*;

class Base {
    int content;
    public Base(String s) {
        content = s;
    }
};

public class Program {
    public Base inner(String s) {
        return new Base(s) {
            private int i = 11;
            private String str;
            public int value() { return i; }
            {  // 内部实例初始化
                str = s;
            }
        };
    }
    public static void main(String[] args) {
        Program outer = new Program();
        Base inner = outer.inner("Hello");
    }
}

这种情况是直接返回一个匿名类的对象,这个类没有名字,继承于 Base,而且是立即定义之后做返回的,而且返回时被向上转型为其基类 Base。

如果这个匿名内部类继承时调用一个带参数的构造函数,直接在 new 后面的基类(或接口)按照其接口签名返回即可。

5.6. 嵌套类(静态内部类)

如果一个内部类加上 static 修饰,这就是一个静态内部类,又称嵌套类。

嵌套类的对象本身与外部类的对象本身不存在前面描述的关联性。

这种情况下,无法通过 Outer.this 的方法获取外部的成员变量。

5.7. 接口内部的类

在接口内部可以放置内部类(可以实现外部接口本身);

接口内部类是自动 public static 的,因此这个内部类属于一个嵌套类。

可以使用这种方法来为接口定义一个实现,并且加入 main 方法用于测试。

5.8. 内部类的继承

如果要继承内部类,需要特殊的语法以确认其与外部类对象之间的关联:

class WithInner {
    class Inner {}
}

public class InheriInner extends WithInner.Inner {
    // 注意其构造函数需要传入外部类的对象进行初始化
    IneritInner(WithInner wi) {
        wi.super();
    }
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

5.9. 内部类的覆盖

如果外部类被派生,其内部类不会发生改变。

TODO: 详细暂且略过

5.10. 局部内部类

TODO: 略


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/02/java-cheatsheet-5.html【Java cheatsheet (V)】

发表评论

电子邮件地址不会被公开。 必填项已用*标注