乐趣区

关于python:抬抬小手学Python-内部类

 对于外部类的局部内容,正在深刻理解中。每天都在批改更新中。

一、成员外部类

/**
 *  须要晓得两个前提:
 *  1. 成员外部类是外围类的一个成员, 它两关系特地好, 开诚布公, 抵足而眠, 都是最好的亲兄弟
 *  所以拜访权限什么的, 基本不存在
 *
 *  2. 外部类对象依赖于外围类对象存在
 *  思考:
 *      a, 在成员外部类的成员办法中, 有没有外围类对象呢? 有
 *
 *      成员外部类的成员办法必然是成员外部类的对象去调用的【了解】*      既然都曾经有成员外部类的对象了,【为什么???】所以这里肯定有外围类对象
 *
 *      b, 在外围类的成员办法中, 有没有外部类对象? 没有
 *      外部类对象依赖于外围类对象存在, 外围类的对象尽管存在, 然而外部类的对象就不肯定了
 *==========================================================================================
 * -【1】成员外部类外部拜访外围类
 * 1, 能够间接拜访, 不管拜访权限
 * 2, 如果拜访外围类的动态成员, 倡议加上外围类类名(这样可读性更好)* 3, 外部类的成员办法中隐含了传参 EnclosedClazz.this, 示意以后外部类的外围类对象
 * 能够用这个来解决外围类和外部类的同名成员问题
 * 当然 也隐含了一个 this, 代表以后外部类对象
 *
 * 这个 this 能够用来解决局部变量和成员变量同名的问题
 *
 * -【2】外围类拜访成员外部类成员
 *(1)在外围类的一般成员办法中 要本人手动创立外部类对象    能够用这个对象任意拜访外部类成员, 不管拜访权限
 *(2)如果在外围类的静态方法中 拜访外部类成员。必须创立两个对象 外围类对象的根底上创立外部类对象
 *
 * -【3】外部类拜访成员外部类成员
 *  必须要先创立外围类对象 再创立外部类对象
 *          留神: 外部类拜访外部类 受拜访权限限度
 *          1, 如果外部类是公有的, 外部类无奈创建对象
 *          2, 即使是可能创建对象, 外部类中的公有成员也不能拜访
 *
 * -【4】成员外部类拜访外部类成员(理解)* > 在成员外部类中拜访外部类成员,和在一般类中拜访其它类成员别无二致
 *
 * - 动态成员间接类名点拜访
 * - 一般成员需创立外部类对象
 * - 都受拜访权限管制
 */
public class OutsideClazz { // 外部类
    public static void main(String[] args) {
        // 创立外部类对象
        // 这里有没有外围类对象
        //EnclosedClazz enclosedClazz = new EnclosedClazz();
        //
        //EnclosedClazz.InnerClazz innerClazz = enclosedClazz.new InnerClazz();
        //
        // 上面的格局 是创立成员外部类对象的万能格局
        // 二合一
        EnclosedClazz.InnerClazz innerClazz = new EnclosedClazz().new InnerClazz();
        //System.out.println(innerClazz.a);

    }
}
class EnclosedClazz{ // 外围类
    // 外围类中成员变量
    int a;
    private int b = 10;
    static int c = 20;
    static final int D = 30;
    //(1)外围类中的成员办法
    public void test(){
        // 拜访外部类成员必须要有外部类对象
        // 这里有没有? 显然是没有的 所以要本人创建对象

        // 这里曾经存在了一个外围类对象【为什么???】, 用 this 批示   所以间接创立外部类对象即可
        InnerClazz innerClazz = new InnerClazz();
        System.out.println(innerClazz.a);// 不受拜访权限限度
        // 拜访外部类的动态常量, 间接用外部类类名就能够了
        System.out.println(InnerClazz.D);
        //EnclosedClazz.InnerClazz innerClazz2 = new EnclosedClazz().new InnerClazz();

    }
    //(2)外围类的静态方法中
    public static void testStatic(){
        // 外围类的静态方法 这里有没有对象?     这里没有任何对象 包含外围类对象
        // 所以在这里拜访成员外部类成员 必须创立两个对象

        // 1 创立外围类对象
        EnclosedClazz enclosedClazz = new EnclosedClazz();
        // 2 创立外部类对象
        InnerClazz innerClazz = enclosedClazz.new InnerClazz();

        // 3 下面能够二合一      // 有对象后, 拜访就一样了 不受拜访权限管制
        InnerClazz innerClazz1 = new EnclosedClazz().new InnerClazz();
        //EnclosedClazz.InnerClazz innerClazz2 = new EnclosedClazz().new InnerClazz();

    }

    class InnerClazz{ // 成员外部类
        // 思考: 如果外部类中有和外围类同名的动态变量咋办? 错了 成员外部类没有动态变量
        //static int c = 200;
        // 思考: 如果外部类中有和外围类同名的动态常量咋办? 就用类名辨别

        // 思考: 如果外部类中有和外围类同名的一般变量咋办? 一般类的成员办法中隐含了 this 传参 代表以后对象
        // 而成员外部类的成员办法中也隐含了一个参数 代表以后外部类的外围类对象 用 EnclosedClazz.this 标记它
        static final int D = 300;
        private int a = 10;
        // 依赖办法拜访外围类成员   成员外部类的成员办法必然是成员外部类的对象去调用的【了解】public void testInner(){System.out.println(EnclosedClazz.this.a);// 拜访外围类的同名一般成员变量
            System.out.println(b);// 成员外部类是外围类的一个成员,不存在拜访权限
            System.out.println(EnclosedClazz.c);// 拜访外围类的动态成员, 倡议加上外围类类名(这样可读性更好)System.out.println(EnclosedClazz.D);// 同上        这里 D 为外围类中的 30
            System.out.println(this.D);// 也隐含了一个 this, 代表以后外部类对象       这里 D 为 300

        }
    }

}

二、动态外部类

/**
 * 前提:
 *  1, 只有是外部类, 外围类都是亲兄弟, 都没有拜访权限限度
 *  2, 外围类和外部类对象就不会相互影响了 各干各的
 *
 * 需要: 不心愿依赖外围类, 又不心愿外部类可能拜访, 只能用动态外部类
 * -【1】动态外部类外部拜访外围类
 *  必须要创立外围类对象      动态成员举荐类名拜访      不受拜访权限管制
 *
 * -【2】外围类拜访动态外部类成员
 * 无论是什么办法, 间接创立外部类对象完事      不受拜访权限限度        如果是动态成员举荐应用类名拜访
 *
 * -【3】外部类拜访动态外部类成员
 * 这里动态外部类是一个能够独立的类
 * 惟一的区别 就是须要类的申明拜访权限限度
 * 语法:
 * EnclosedClazz.InnerStaticClazz ecisc = new EnclosedClazz.InnerStaticClazz();
 *
 * -【4】动态外部类拜访外部类成员(理解)* > 在动态外部类中,拜访外部类成员,和在一般类中拜访其余类成员别无二致
 *
 * - 动态成员,类名点间接拜访
 * - 一般成员需创建对象拜访
 * - 受拜访权限管制
 *
 */
public class OutsideClazz { // 外部类
    public static void main(String[] args) {
        // 创立外部类对象
        // 能够间接创立 然而它和一般类不同
        // 须要通知编译器 你这个外部类在哪里
        //EnclosedClazz.InnerClazz ic = new EnclosedClazz.InnerClazz();
        //System.out.println(ic.privateVar);
    }
}

class EnclosedClazz { // 外围类
    int aEn;
    private int aEnPrivate = 10;
    static int b = 10;
    // 成员办法
    public void test(){
        // 这里没有动态外部类对象, 须要创立
        // 不受拜访权限限度
    }
    public static void testStatic(){
        // 须要创立外围类对象吗?
        InnerClazz innerClazz = new InnerClazz();}

  private    static class InnerClazz  { // 动态外部类
        // 尽管这个类加了 static 然而你不要往动态成员思考 这里 static 示意这个外部类是独立的
        // 定义成员变量
        int aEn;
        private int privateVar = 100;
        private static int b = 10;
        static int c = 20;
        static final int D = 30;
        // 定义成员办法
        public void test(){
            // 拜访外围类成员 须要外围类对象
            // 思考: 这里有没有外围类对象?
            // 这里没有外围类对象, 须要创立外围类对象
            EnclosedClazz ec = new EnclosedClazz();
            System.out.println(ec.aEn);             // 外围类的就用外围类对象办法
            System.out.println(ec.aEnPrivate);
            // 思考: 这里如果外部类和外围类同名变量
            // 外围类的就用外围类对象办法, 本人的就用 this 拜访
            System.out.println(this.aEn); // 用 this 减少区分度      本人的就用 this 拜访
            System.out.println(InnerClazz.b);// 动态成员举荐类名拜访

        }
        public static void testStatic(){}

    }
    class InnerStatic{}}

三、部分外部类

public class Demo { // 外部类
    public static void main(String[] args) {
        //int a  = 10;
        for (int i = 0; i < 1; i++) {class T{}
        }
        if (true){class T{}
        }
        //switch
    }
   static  {class S{}
    }

}

class EnclosedClazz { // 外围类

    public void test() { // 一般的成员办法
        // 定义部分外部类
         class InnerLocalClazz{
            int a;
            private int b = 10;
            //Inner classes cannot have static declarations
            //static int c =100;
             static final  int D = 100; // 动态常量是不须要类加载
             //Inner classes cannot have static declarations
             //static final  Demo DEMO = new Demo();// 动态的援用类型常量 只有 String 不触发类加载
             public void test(){}
             //public static void test2(){}
        }
    }
}

=====================================================================================
public class Demo {public static void main(String[] args) {}}

class EnclosedClazz { // 外围类
    int a;
    private int b = 20;
    static int c = 10;

    public static void main(String[] args) {EnclosedClazz enclosedClazz = new EnclosedClazz();
        enclosedClazz.test();}

    public void test() { // 一般成员办法
        // 能够间接拜访外围类成员, 因为一般成员办法隐含 this 指向以后对象 所以曾经有对象
        // 可能间接拜访
        class InnerLocalClazz { // 部分外部类
            // 部分外部类的成员办法
            public void test() {System.out.println(a);   //0
                System.out.println(b);   //20
                System.out.println(EnclosedClazz.c);   //10
            }
        }
        // 在办法中创建对象
        // 触发类加载 也只有这一种形式 只能在这里创建对象
        InnerLocalClazz innerLocalClazz = new InnerLocalClazz();
        // 调用部分外部类的办法
        innerLocalClazz.test();    // 这里输入 3 个值}

    public static void testStatic() { // 动态成员办法
        class InnerLocalClazz{
            // 思考: 这里可能间接拜访外围类成员吗?
            // 不能, 起因是动态的办法没有以后对象
            public void test(){//System.out.println(b);
            }
        }

    }
}

部分外部类对象和办法局部变量的生命周期比照

部分外部类对象要比局部变量活得更久    jvm 放的正本啥时候隐没:跟对象同生共死
在 Java8 之前,这个办法的局部变量中的 final 必须由程序员手动加上去的,然而 8 当前,Java 开发者把这个 final 暗藏到了代码底层

public class Demo { // 外部类
    public static void main(String[] args)  {EnclosedClazz enclosedClazz = new EnclosedClazz();
      Father f =   enclosedClazz.test(); // 这里返回的理论是一个 InnerSon 对象
        // 父类援用指向子类对象 多态调用

        f.testInner(); // 这里曾经没有 a 了
        // 然而依然可能打印 a 的值,阐明 jvm 偷偷的帮咱们做了一件事:// 把办法的局部变量 a 塞到了对象当中

    }
}

class EnclosedClazz { // 外围类
    public Father test() {
        // 定义部分外部类 让它继承 Father
        int a = 10; // 当 test 调用完结 a 就销毁了 无了
        class InnerSon extends Father{

            @Override
            public void testInner() {System.out.println("2");
                //a = 20;
                //System.out.println(a);
            }
        }
        // 再次用 a
        // 创立部分外部类对象
        InnerSon is = new InnerSon();
        // 我间接把这个对象作为返回值返回
        return is; // 子类能够看成父类 向上转型 主动
        //is.test(); //2}

}

class Father {public void testInner() {System.out.println("1");
    }
}
=====================================================================================
部分外部类的经典应用
/**
 * 写一个办法去返回接口或者抽象类的具体子类
 *
 * 用部分外部类返回一个接口实现类 适宜用于想偷懒 不想写接口实现类的适宜
 * 适宜于 只应用一次的实现类 或者就想调用一次接口的办法
 * 然而对于屡次调用,这种形式就不实用
 *
 */
public class Demo {public static void main(String[] args) {
        // 经典写法调用
        I i = getIInstance();
        i.test();

        // 外部类的高端写法 调用
        I i2 = getIInstance2();
        i2.test();}
    public static I getIInstance(){
        // 经典写法
        // 先用一个类实现这个接口
        // 而后创立这个类的对象
        return new IImpl(); // 匿名对象}

    // 高端的写法,应用部分外部类
    public static I getIInstance2(){
        // 定义部分外部类
        class IInner implements I{
            @Override
            public void test() {System.out.println("222222");
            }
        }
        // 创立部分外部类对象
        //IInner iInner =
        return new IInner();}
}

interface I{void test();
}
class IImpl implements I{
    @Override
    public void test() {System.out.println("1111111");
    }
}


四、匿名外部类

/**
 * 匿名外部类:是匿名的(部分)外部类,也就是说匿名外部类实质上是部分外部类
 * 匿名对象:没有名字的对象
 * 匿名外部类:没有名字的(部分)外部类
 *
 * 匿名外部类的应用优缺点:* ​    1,当咱们只应用一次某类或者某接口的子类对象时,应用匿名外部类,会略微不便一点
 * ​    2,如果须要屡次拜访子类对象的成员,匿名外部类很麻烦。* ​    3,如果拜访匿名子类中的独有办法,必须用匿名对象去拜访
 *
 */
public class Demo {public static void main(String[] args) {
        // 老花样:创立接口的实现类
        I i = new IA();
        i.test();

        // 新花样:部分外部类创立接口实现类
        class InnerLocalClazz implements I{
            @Override
            public void test() {System.out.println("高端的写法,总是这么朴实无华,干燥!");
            }
        }
        // 间接创立部分外部类对象
        InnerLocalClazz innerLocalClazz = new InnerLocalClazz();
        innerLocalClazz.test();

        // 新新花样:在部分外部类的根底上,我罗唆连你这个外部类我都不要了,间接创立部分外部类对象,也就是匿名部分类
        // 语法:间接创建对象:new 接口或者类 (){};
        // 形式一
        I i2 = new I() {
            @Override
            public void test() {System.out.println("我是匿名外部类对象中的 test 办法");
            }

            public void test2(){}
        };//new 加上前面一块就是对象,能够用父类去接管它。实际上想接管 也只能用父类去接管
        i2.test();
        //i2.test2();  因为编译看右边,所以调用不了子类独有办法
        //((I) i2).test2(); // 因为这个子类是匿名的,也没有方法强转它
        // 总结,这种形式 打死了 也拜访不了子类的独有办法

        // 形式二
        // 以上匿名外部类的对象也能够不接管
        new I(){
            @Override
            public void test() {System.out.println("不必父类接管");
            }public void test2() {System.out.println("子类独有");
            }
        }.test2();

        // 以上两种形式,各有什么优缺点
        // 形式一用接口去接管后,这个对象就有援用,能够重复应用,然而形式一是用父类援用去接管的,这样就用不了子类中独有的办法
        // 形式二没有去接管,这个对象没有援用,只能用一次,用完后就成为垃圾了。然而形式二 能够调用子类独有办法
        // 形式一 形式二如果都能用 优先应用形式二 因为形式二省事

        // 用匿名外部类创立类的子类
        // 语法:new 类 (){};
        new A(){
            @Override
            public void test() {System.out.println("我是一般类的匿名外部类子类对象");
            }
        }.test();

        System.out.println(new AbstractA() {
            @Override
            public int test() {return 10;}
        }.test());
// 这一块相当于就是 10 所以就能够对他进行 10 的操作 比方赋值 比方计算 比方打印

        A a = new A() {}; // 它如果可能做本人,那它到底是什么类型呢?如果它做儿子,还能用父类来接管 隐含的继承
    }
}
interface I{void test();
}
class IA implements I{
    @Override
    public void test() {System.out.println("我是 IA I 接口的实现类");
    }
}
class A{public void test(){}}
abstract class AbstractA{public abstract int test();
}
退出移动版