zoukankan      html  css  js  c++  java
  • Java 内部类.md

    Java 内部类

    学习自

    《Java编程思想》

    Overview

    什么是内部类?
    Thinking In Java 中如此定义: 将一个类的定义放在里另一个类的定义的内部,这就是内部类。

    声明一个内部类

    package com.company;
    
    public class Parcel {
        class Contents {
            private int i = 11;
    
            public int value() {
                return i;
            }
        }
    
        class Destination {
            private String label;
    
            Destination(String whereTo) {
                this.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) {
        Parcel p = new Parcel();
        p.ship("Tasmania");
    }
    

    上面是一个简单的内部的声明,并没有什么特殊的情况,除了将类定义在一类的声明中,这种比较奇怪的写法外。

    创建内部类的对象

    如果想要确切地指向一个内部类的语法是: OuterClassName.InnerClassName
    根据这种个语法我们来创建内部类的对象来试试:

    图片.png | left | 702x104

    按照这种语法报了编译错误,显然这不是正确的方式,正确的方式如下(在外部类中暴露实例化内部类的方法):

    
    
    public class Parcel {
        class Contents {
            private int i = 11;
    
            public int value() {
                return i;
            }
        }
    
        class Destination {
            private String label;
    
            Destination(String whereTo) {
                this.label = whereTo;
            }
    
            String readLabel() {
                return label;
            }
        }
        //!!注意这里,我们暴露了方法来实例化内部类
        public Destination to(String dest) {
            return new Destination(dest);
        }
    
        public Contents contents() {
            return new Contents();
        }
    
        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) {
        Parcel p = new Parcel();
        Parcel.Destination destination = p.to("BeiJing");
    }
    

    我们知道了如果正确地实例化内部类,我们也应该知道为什么,直接通过 new 的方式不能实例化内部类:

    这是因为,在内部类中是可以引用外部类的成员的(这个稍后会提到),如果直接实例化内部列的话,内部类,是无法访问到外部类的实例成员的,因为外部类还没有实例化。
    不过,如果是想直接实例化内部类的话,也不是不可以,在后面我们会讲到那就是 静态内部类

    链接到外部类

    public class Sequence {
        private Object[] items;
        private int next = 0;
    
        public Sequence(int length) {
            items = new Object[length];
        }
    
        public void add(Object item) {
            if (next < items.length) {
                items[next++] = item;
            }
        }
    
        public SequenceSelector selector() {
            return new SequenceSelector();
        }
    
         class SequenceSelector {
            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 static void main(String[] args) {
        int length = 10;
    
        Sequence s = new Sequence(length);
        for (int i = 0; i < length; i++) {
            s.add(i);
        }
    
        Sequence.SequenceSelector selector = s.selector();
        while (!selector.end()) {
            System.out.print(selector.current() + ",");
            selector.next();
        }
    }
    //输出结构
    //0,1,2,3,4,5,6,7,8,9,
    

    上面我们,我们使用内部类完成了一个简单的迭代器模式的代码,值得注意的是,在 Selector 我们用到了items对象,值得注意的是,此对象并不是Selector本身的,而是Sequence的一个private成员。内部类可以访问器外部类的方法和字段,就像是自身拥有的似的. 通过这一特性,我们在一些特定的情况下,可以完成一些非常优雅的设计,比如说迭代器模式。

    为什么内部类可以访问外部类的对象

    原因是,当一个外部类的对象,创建了一个内部对象时,内部类会秘密地捕获一个执行外部类的对象的应用。我们不必去关心细节,因为编译器已经帮助我们处理好了,如此一来,为什么不能通过 new 关键字来实例化非__静态内部类__的疑惑也就迎刃而解。

    .this 和 .new

    .this 关键字

    如果在内部类中想要获取对外部类的引用,可以通过 OuterName.this 来获取。

    
    public class Outer {
        public void test() {
    
        }
    
        class Inner {
            public void foo() {
                //Outer.this 获取外部类的引用
                Outer.this.test();
            }
        }
    }
    

    .new 关键字

    如果想要实例化一个必须要用外部类的引用才行,所以我们一开始创建内部类的实例的时候是这样创建的

    public class Parcel {
        class Contents {
            private int i = 11;
    
            public int value() {
                return i;
            }
        }
    
        class Destination {
            private String label;
    
            Destination(String whereTo) {
                this.label = whereTo;
            }
    
            String readLabel() {
                return label;
            }
        }
        //!!注意这里,我们暴露了方法来实例化内部类
        public Destination to(String dest) {
            return new Destination(dest);
        }
    }
    

    上面的代码中,我们为了创建内部类的对象,我们不得不写了一个公开的方法,但是这无疑增加了我们的工作量,虽然并不多。现在有一个新的方式来创建内部类的实例---通过 .new 关键字。

    Parcel parcel = new Parcel();
    Parcel.Destination destination = parcel.new Destination("temp");
    

    方法和作用域中的内部类

    在我们想要创建一个类来辅助我们解决一个比较复杂得问题的时候,但是与此同时,又不希望这个类是公共的。

    public static void main(String[] args) {
        class Person {
            private String name;
            private String gender;
            private int age;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public String getGender() {
                return gender;
            }
    
            public void setGender(String gender) {
                this.gender = gender;
            }
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
        }
    
        Person person = new Person();
        person.setName("LD");
        person.setGender("Male");
        person.setAge(20);
    }
    

    就比如说Person类这个类仅仅能够在main方法中使用,在其他的地方是不能够被访问的。

    匿名内部类

    因为我主要在做一些Android的开发,在做一些小的Demo或者没有为了实现某些接口仅仅写较短的几句代码,就完全没有必要再新建一个类来解决了,我会使用匿名内部类来解决。

    Button openBtn = this.findViewById(R.id.openBtn);
    openBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            
        }
    });
    

    嵌套类

    上面说到,为了访问外部类的种类,内部类会捕获外部类的引用。当时已经确定内部类不会调用外部类的对象的时候,可以将其声明为 嵌套类 。其有以下特点:

    • 嵌套类并不需要其外围类的对象
    • 不能从嵌套类中访问费静态类型的成员
    • 因为没有对外部类的引用,可以直接通过 new 关键字实例化
    public class Parcel {
        public static class Destination {
            private String label;
    
            public Destination(String whereTo) {
                label = whereTo;
            }
    
            public void readLabel() {
                System.out.print(label);
            }
        }
    }
    //因为Destination是嵌套类所以能够直接被实例化
    public static void main(String[] args) {
        Parcel.Destination destination = new Parcel.Destination("Beijing");
        destination.readLabel();
    }
    
  • 相关阅读:
    rabbitMQ学习笔记(二) 简单的发送与接收消息 HelloWorld
    rabbitMQ学习笔记(一)Windows 与Linux下rabbitMQ的安装
    数据库必知必会操作手册—创建高级联结
    面试题 16.11. 跳水板(数学法)
    面试题 08.06. 汉诺塔问题(分治递归)
    剑指 Offer 32
    剑指 Offer 32
    剑指 Offer 53
    剑指 Offer 30. 包含min函数的栈(辅助栈)
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/slyfox/p/9265376.html
Copyright © 2011-2022 走看看