• 内部类的小总结(语法和用法方面)


    外部类的创建

    直接在  外部类里面   像定义其他类一样地去定义。

    在外部类的非static方法中,要用自己定义的内部类就和用普通类一样,直接拿来就new。

    除了外部类的feistatic方法,在其他地方像其他类中的方法或者是外部类的static方法中,要使用内部类则要用完整的   外部类.内部类名   这样的格式来标识一个内部类。

    引用外部类的变量

    内部类可以自动获得创建他的那个类中的类变量,这是因为内部类会暗中抓住  外部类对象  的引用,当你要用到外部类的  类变量的适合,这个引用会帮你选择正确的类变量。  因此   当你要创建一个   非static的内部类的对象的时候,一定只有在它和外部类的对象相关联的情况下,才能被创建。

    .this和.new

    上面说了,之所以内部类可以使用外部类的  类变量,是因为  偷偷抓住了  外部类对象的引用。   那么当你想要用到这个引用的时候,只需要OutClass.this就可以。  注意,直接在内部类中用this关键字,返回的引用是这个内部类对象的引用。

    怎么直接创建内部类的对象呢??用.new关键字,下面看个例子:

    DotNew.Inner dni = dn.new Inner();

    这是在一个static方法中,前面要描述内部类,肯定要外部类.内部类名  这样,然后后面  new对象就要用这个语法,我们前面说过一定要通过外部类的   对象     才能建立内部类的对象,所以要用    外部类对象  dn  然后再.new   +   内部类()。  注意这里  不用再  外部类.内部类()。

    内部类可以实现某个接口,然后向上转型

    一般的类的访问权限只能是public和default的package范围的嘛,但  内部类可以是private,protected的。再结合  接口实现和转型,可以生成更高效的代码。

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

    方法内的内部类例子:

    //: innerclasses/Parcel5.java
    // Nesting a class within a method.
    public class Parcel5 {
        public Destination destination(String s) {
            class PDestination implements Destination {
                private String label;
                private PDestination(String whereTo) {
                    label = whereTo;
                }
                public String readLabel() { return label; }
            }
        return new PDestination(s);
        }
    
        public static void main(String[] args) {
            Parcel5 p = new Parcel5();
            Destination d = p.destination("Tasmania");
        }
    } ///:

    还有贴一个笔记:

     

    还有在作用域中  使用内部类的例子:

    //: innerclasses/Parcel6.java
    // Nesting a class within a scope.
    public class Parcel6 {
        private void internalTracking(boolean b) {
            if(b) {
                class TrackingSlip {
                    private String id;
                    TrackingSlip(String s) {
                        id = s;
                    }
                    String getSlip() { return id; }
                }
                TrackingSlip ts = new TrackingSlip("slip");
                String s = ts.getSlip();
            }
    
            // Can’t use it here! Out of scope:
            //! TrackingSlip ts = new TrackingSlip("x");
        }
    
        public void track() { internalTracking(true); }
    
        public static void main(String[] args) {
            Parcel6 p = new Parcel6();
            p.track();
        }
    } ///:

    注意:  方法内部类和块中的内部类,可以任意访问外部类的类变量,但方法中的变量的话(比如方法内部类),就方法中的参数的话,一定要是final才能访问!!这个和下面讲的  匿名类 是一样的。 

    匿名内部类

    下面的例子是一个实现了Contents接口的匿名类,类的定义和return语句结合在了一起,注意后面还要有个分号:

    public Contents contents() {
        return new Contents() { // Insert a class definition
            private int i = 11;
            public int value() { return i; }
        }; // Semicolon required in this case
    }

    这是用默认的构造器来生成Contents,那么如果基类的构造器是需要参数的呢?

    public Wrapping wrapping(int x) {
        // Base constructor call:
        return new Wrapping(x) { // Pass constructor argument.
            public int value() {
                return super.value() * 47;
            }
        }; // Semicolon required
    }
    
    
    //: innerclasses/Wrapping.java
    /**
    *基类 Wrapping
    */
    public class Wrapping {
        private int i;
        public Wrapping(int x) { i = x; }
    
        public int value() { return i; }
    
    } ///:

    在 匿名类中  初始化一些类变量或者干点什么:

    // Argument must be final to use inside
    // anonymous inner class:
    public Destination destination(final String dest) {
        return new Destination() {
            private String label = dest;
            public String readLabel() { return label; }
        };
    }

    如果你在匿名类里面,要用到一个外面的定义的对象,那么编译器要求这个参数的引用是final的

    匿名类是没有构造器的,那么如果你想像  构造器一样,做一些复杂点的  初始化工作呢?可以用   实力初始化——instance initialization来实现:

    public Destination destination(final String dest, final float price) {
        return new Destination() {
            private int cost;
            // Instance initialization for each object:
            {
                cost = Math.round(price);
                if(cost > 100)System.out.println("Over budget!");
            }
            private String label = dest;
            public String readLabel() { return label; }
        };
    }

    匿名类一般就是这样的语法来用的,要么是继承一个基类,像上面的  return new 基类();   要么就实现一个接口   return new 接口();

    但只能是一个操作,即匿名类要么继承一个基类,要么实现一个接口。

    嵌套类(nested classes)

    如果不需要内部类对象和外部类对象有联系的话,可以把内部类声明为static——这通常被称为是嵌套类。  我们知道,普通的内部类会偷偷抓个  外部类对象的引用,而嵌套类nested classes就不是这样了,当一个内部类被声明为static时,意味着:

    1. 要创建内部类的对象,不需要外部类的对象。
    2. 不能从内部类的对象中访问非static的外部类对象。

    嵌套类和普通类还有个区别是,普通类的字段和方法只能放在外部层次上,所以普通内部类中不能有static字段和static数据,也不能包含嵌套类。  但是!!!嵌套类可以包含所有这些东西!!

    所以内部的static类也就是嵌套类  有点像是一个static的方法。

    interface里面的类

    interface里面的东西,会自动变成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();
            }
        }
    }

    书上说,就很方便喔,如果你有些公共的代码,想所有的实现这个接口的类都共用,那么就可以这样   在j接口中放个嵌套类喔~

    多层内部类中访问外部类成员

    一个内部类不管在里面多少层,都可以访问它外部类的成员,哪怕是private的东西。

    class MNA {
        private void f() {}
        class A {
            private void g() {}
            public class B {
                void h() {
                    g();
                    f();
                }
            }
        }
    }
    
    public class MultiNestingAccess {
        public static void main(String[] args) {
            MNA mna = new MNA();
            MNA.A mnaa = mna.new A();
            MNA.A.B mnaab = mnaa.new B();
            mnaab.h();
        }
    } ///:~

     内部类的继承

    我们知道,就一个内部类的对象,一定是要偷偷抓住外部类的对象的引用嘛,那么继承了  内部类的子类要怎么操作呢?  有个特别的语法:

    就如果一个类继承了一个内部类,那么原本的无参构造器不能用,你需要:
    1.构造器传一个 外部类的 对象
    2.在构造方法中第一句写 enclosingClassReference.super();

    看个例子:

    //: innerclasses/InheritInner.java
    // Inheriting an inner class.
    class WithInner {
        class Inner {}
    }
    
    public class InheritInner extends WithInner.Inner {
        //! InheritInner() {} // Won’t compile
        InheritInner(WithInner wi) {
            wi.super();
        }
        public static void main(String[] args) {
            WithInner wi = new WithInner();
            InheritInner ii = new InheritInner(wi);
        }
    } ///:~

    内部类可以被重写吗??

    想这么一个情况,如果有个内部类,它继承了它的外部类,然后重新定义它自己(内部类),会发生怎样的事情呢?但其实并没卵用。。看个例子

    //: innerclasses/BigEgg.java
    // An inner class cannot be overriden like a method.
    import static net.mindview.util.Print.*;
    class Egg {
        private Yolk y;
        protected class Yolk {
            public Yolk() { print("Egg.Yolk()"); }
        }
        public Egg() {
            print("New Egg()");
            y = new Yolk();
        }
    }
    
    public class BigEgg extends Egg {
        public class Yolk {
            public Yolk() { print("BigEgg.Yolk()"); }
        }    
    
        public static void main(String[] args) {
            new BigEgg();
        }
    } 
    /* Output:
    New Egg()
    Egg.Yolk()
    *///:~

    原本的父类Egg里面有个内部类Yolk。

    然后BigEgg继承Egg并又定义了一个Yolk类。似乎是重写了内部类。

    你可能认为,既然创建了BigEgg这样的对象,那么所使用的应该是覆盖后的Yolk版本,但输出并不是这样。

    这个例子说明,当继承了某个外围类的时候,内部类并没有什么神奇的变化。这两个内部类是完全独立的实体,各自在自己的命名空间中 。

    当然我们也可以明确地继承某个内部类,看例子:

    //: innerclasses/BigEgg2.java
    // Proper inheritance of an inner class.
    import static net.mindview.util.Print.*;
    class Egg2 {
        protected class Yolk {
            public Yolk() { print("Egg2.Yolk()"); }
            public void f() { print("Egg2.Yolk.f()");}
        }
    
        private Yolk y = new Yolk();
    
        public Egg2() { print("New Egg2()"); }
    
        public void insertYolk(Yolk yy) { y = yy; }
    
        public void g() { y.f(); }
    }
    
    public class BigEgg2 extends Egg2 {
        public class Yolk extends Egg2.Yolk {    //这里继承了内部类,但 构造方法没有显式地指出  Egg2对象的引用,我想是因为  这个类是BigEgg2的内部类,然后肯定有BigEgg2对象的引用吧,而这个
                               //BigEgg2又是Egg2的子类,意味着 BigEgg2对象里面相当于有这个Egg2基类对象,所以就相当于有这个引用了吧……
    public Yolk() { print("BigEgg2.Yolk()"); } public void f() { print("BigEgg2.Yolk.f()"); } } public BigEgg2() { insertYolk(new Yolk()); } public static void main(String[] args) { Egg2 e2 = new BigEgg2(); e2.g(); } } /* Output: Egg2.Yolk() New Egg2() Egg2.Yolk() BigEgg2.Yolk() BigEgg2.Yolk.f() *///:~

    这个输出有点绕,上一个我看了半天的分析笔记图片:

     关于标识符

    直接上图吧哈哈哈:

  • 相关阅读:
    linux安装mysql
    yum命令
    java启动jar包中的指定类
    linux系统配置参数修改
    iconfont阿里巴巴矢量图标库批量保存
    Python 使用Pandas读取Excel的学习笔记
    在Ubuntu18.04的Docker中安装Oracle镜像及简单使用
    Eclipse 安装PyDev开发Python及初步使用
    Python打包工具
    MacOS下打包Python应用
  • 原文地址:https://www.cnblogs.com/wangshen31/p/10292695.html
Copyright © 2020-2023  润新知