(Thinking in Java)第10章 内部类

Thinking in Java捞干货,写笔记

一、成员内部类

1.最基本使用

public class Demo {
    class Contents{
        private int i=11;
        public int value(){
            return i;
        }
    }

    class Destination{
        private String label;
        Destination(String whereTo){
            label=whereTo;
        }
        String readLabel(){
            return label;
        }
    }
    
    public void ship(String dest){
        Contents c=new Contents();
        Destination d=new Destination(dest);
        System.out.println(d.readLabel());
    }

    public static void main(String[] args) {
        Demo d=new Demo();
        d.ship("Tasmania");
    }
}

2.内部类可以访问外部类的成员

内部类可以访问外部类的成员变量。如下:

public class Demo {
    private Object[] items;
    private int next = 0;

    public Demo(int size) {
        items = new Object[size];
    }

    public void add(Object x) {
        if (next < items.length) {
            items[next++] = x;
        }
    }

    private class SequenceSelector implements Selector {
        private int i = 0;

        public boolean end() {
            return i == items.length;
        }

        public Object current() {
            return items[i];
        }

        public void next() {
            if (i < items.length) {
                i++;
            }
        }
    }

    public Selector selector() {
        return new SequenceSelector();
    }

    public static void main(String[] args) {
        Demo d = new Demo(10);
        for (int i = 0; i < 10; i++) {
            d.add(Integer.toString(i));
        }
        Selector selector = d.selector();
        while (!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
    }
}

interface Selector {
    boolean end();

    Object current();

    void next();
}

因为在创建内部类对象的时候,内部类对象会捕获一个指向外部类对象的引用。访问外部类成员的时候,就是用这个引用来获取外部类成员的。内部类中也可以取得这个外部类对象引用。举例如下:

public class DotThis{
    void f(){
        System.out.println("DotThis.f()");
    }
    class Inner{
        public DotThis outer(){
            return DotThis.this;
            //A plain "this" would be Inner's 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语法。

public class DotNew{
    public class Inner{
    }
    public static void main(String[] args){
        Inner dni=new DotNew().new Inner();
    }
}

当创造内部类对象的时候,如果这个内部类不是嵌套类(静态内部类),那么就必须要通过外部类对象,才能创建这个内部类对象,为什么呢,之前说过,因为这个内部类对象要获取外部类的引用啊。
并且在存在多个内部类的时候,多个内部类之间可以互相创建对象。例子就不举了。

小结:现在所说的都是成员内部类,其实内部类没那么复杂,既然叫做成员内部类了,他就只是类的成员罢了。他也可以带修饰符,他的修饰符和其他普通的成员变量的修饰符的意义也没有什么不同。

3.内部类权限修饰符

当内部类被private修饰的时候,该类只能被外部类内的方法使用,其他类不能获取该内部类的引用,因为是private的,所以其他类根本不知道存在一个这样的类。当然也可以作为一个成员变量使用,但是如果作为成员变量,则其他类并不能直接创建内部类的引用,需要用其他手段获取该引用,如下:

class Outer{
    Inner in;
    private class Inner implements a_interface{
        void show(){
            System.out.println("123");
        }
    }
}
interface a_interface{
    void show();
}

class test{
    //Inner in=new Outer().in;这是错误的,因为test并不知道Outer类有一个Inner内部类,因为是私有的
    a_interface in=new Outer().in;//可以运用向上转型的方法获取private修饰的内部类。
}

小结:其实这也很好记,无论是public还是private,修饰到内部类上的时候,和他们修饰普通的成员变量(如string,int之类)的时候没什么不同,规则都一样,public就都能使用,private就类内可以用。所以规则就记住三条就好:1.先考虑外部类的权限,是否可以获取一个外部类对象。2.创建成员内部类对象的时候需要外部类对象。3.考虑内部类的权限,是否可以获取这样的一个内部类对象(或者说,在外部知不知道有这样一个内部类)。

二、方法和作用域内的内部类

当我们需要解决一个复杂的问题,想创建一个类来辅助解决问题,但是不希望这个类是公共可用的,甚至不希望在外部类之内的其他地方可以访问到这个辅助类。我们可以运用方法内的内部类

public class Outer {
    public InterfaceDemo get_InterfaceDemo(String s) {
         class InterfaceDemoTool implements InterfaceDemo {
            private String label;

            private InterfaceDemoTool(String label) {
                this.label = label;
            }

            public String readLabel() {
                return label;
            }
        }

        return new InterfaceDemoTool(s);
    }

    public static void main(String[] args) {
        Outer o = new Outer();
        InterfaceDemo i = o.get_InterfaceDemo("123");
    }
}

interface InterfaceDemo {
    String readLabel();
}

当然在方法中还可以定义多个内部类,并且这些内部类之间的关系和普通一个Java文件中多个类之间的关系好像没什么不同。也可以相互继承和创建对象。另外在方法中的内部类不能加private等权限修饰符,只能加abstract和final修饰符。
另外也可以在某个作用域内创建内部类对象

if(a==b){
     class inner{
     }
     new inner();
}

三、匿名内部类

下面这块代码中get_inner()的意思是,创建一个继承自InnerFather的匿名类对象,并且自动向上转型为InnerFather后返回。

public class Outer {
    public InnerFather get_inner() {
        return new InnerFather() {
            void print(){
                System.out.println("Inner_Override");
            }
        };
    }

    class InnerFather {
        InnerFather() {

        }
        void print(){
            System.out.println("InnerFather");
        }
    }

    public static void main(String[] args) {
        Outer o = new Outer();
        InnerFather i = o.get_inner();
        i.print();
    }
}

当然这只是有无参构造函数,当父类只有一个含参构造函数的时候,我们可以这样向匿名内部类传入一个构造函数参数。

public class Outer {
    public InnerFather get_inner(int i) {
        return new InnerFather(i) {
            void print(){
                System.out.println("Inner_Override");
            }
        };
    }

    class InnerFather {
        InnerFather(int i) {

        }
        void print(){
            System.out.println("InnerFather");
        }
    }

    public static void main(String[] args) {
        Outer o = new Outer();
        InnerFather i = o.get_inner(10);
        i.print();
    }
}

可以通过构造代码块来实现匿名内部类的自定义的构造函数

abstract class Base {
    public Base(int i) {
        System.out.println("Base constructor");
    }

    public abstract void f();
}

public class AnonymousConstructor {
    public static Base getBase(int i){
        return new Base(i){
            {System.out.println("AnonymousConstructor constructor");}
            public void f(){
            }
        };
    }

    public static void main(String[] args) {
        Base base = getBase(47);
    }
}

(书上说,如果传入了新的对象,就比如下面例子中的s_in,这个s_in就必须是final的,但是我实验了一下发现并不用啊,我也没太搞懂。)

abstract class Base {
    public Base(int i) {
        System.out.println("Base constructor");
    }

    public abstract void f();
}

public class AnonymousConstructor {
    public static Base getBase(int i,String s_in){
        return new Base(i){
            {System.out.println("AnonymousConstructor constructor");}//构造代码块4.嵌套类
            String s=s_in;
            public void f(){
            }
        };
    }

    public static void main(String[] args) {
        Base base = getBase(47,"hello");
    }
}

四、嵌套类

嵌套类指的是被static修饰的内部类。这意味着:1.创建嵌套类对象不需要外部类对象。2.不能再嵌套类对象之中访问非静态的外围类对象。普通内部类的成员和方法只能放在类的外部层次上(这句话我没搞懂= =),所以普通内部类不能有static的成员和方法。但是嵌套类可以有。

public class Outer {
    static class Inner{
        static int i=5;
    }
    public static void main(String[] args) {
        Inner i=new Outer.Inner();
    }
}

可以从上面的例子看到,在创建这个嵌套类对象的时候,并没有像最开始那样,用一个外部类对象来创建这个内部类对象。其实这和静态方法差不多。

可以在接口内部定义内部类,而且他们即使没有static修饰,也会自动变成public static的。

public interface ClassInInterface {
    void howdy();
    class Test implements ClassInInterface{
        public void howdy(){
            System.out.println("howdy!");
        }
        public static void main(String[] args) {
            new Test().howdy();
        }
    }
}

书上有句话说的很好,在开发的时候建议在每个类中都写一个main方法测试,但是这又必须带着那些已经编译过的额外代码,所以我们可以用嵌套类放置测试代码。

public class Outer {
    public void f(){
        System.out.println("I need to be tested");
    }

    public static class Tester{
        public static void main(String[] args) {
            Outer o=new Outer();
            o.f();
        }
    }
}

当然以上两段代码如果是在eclipse上运行的话,需要设置一下运行的main函数在哪,否则会报错
图片描述

五、多层内部类嵌套

纸老虎,爱有几层有几层,反正只要是外部类的东西,不管哪层外部类,都能访问到。

public class Outer {
    void f(){
        System.out.println("hello");
    }
    class Inner1{
        void g(){
            System.out.println("java");
        }
        class Inner2{
            void h(){
                f();
                g();
            }
        }
    }
    public static void main(String[] args) {
        Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
        in2.h();
    }
}

下面是个好玩的

public class Outer {
    void f(){
        System.out.println("hello");
    }
    class Inner1{
        void f(){
            System.out.println("java");
        }
        class Inner2{
            void h(){
                f();
            }
        }
    }
    public static void main(String[] args) {
        Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
        in2.h();
    }
}

最后打印结果是java。

大概就这么多吧,以后如果还有新东西再补。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值