Java内部类

作者: 卡路fly | 来源:发表于2017-04-08 15:28 被阅读64次
    内部类.png

    内部类

    • 内部类作为外部类的成员,可以使用人已访问控制符修饰。
    • 外部类的上一级程序单元是包,所以只有两个作用域:同一个包内、任意位置。因此需要两种权限:包访问权限、公开访问权限,对应省略访问修饰控制符和public访问控制符。因此如果一个外部类不使用任何访问控制符修饰,则只能被同一个包中其他类访问。
    • 内部类的上一程序单元是外部类,所以具有4个作用域:同一个类、同一个包、父子类、和任意位置,可以有4种访问权限控制。
    • 成员内部类的class文件格式为:OuterClass$InnerClass.class
    • 外部类成员变量、内部类成员变量与内部类里方法的局部变量同名,则可以通过使用this、外部类类名.this作为限定区分。

    非静态内部类

    定义:一个类放在另一个类的内部定义。
    大部分时候都被作为成员内部类定义,而不是局部内部类。
    可以直接访问外部类的private成员,反过来不成立

    • 因为在非静态内部类对象里,保存了一个它寄存的外部类对象的引用。

    • 非静态内部类的方法内访问某个变量时:
      1.系统优先在方法内查找是否存在该名字的局部变量,如果存在即使用;
      2.到该方法所在的内部类中查找是否存在改名字的成员变量,如果存在即使用;
      3.到内部类所在的外部类中查找,如不存在出现编译错误:提示找不到该变量。

    • 非静态内部类成员只有在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类成员,必须显示创建非静态内部类对象来进行访问。

    • 非静态内部类里不能有静态方法、静态Field、静态初始化块。


    静态内部类

    包括静态成员、非静态成员。

    • 静态成员不能访问非静态成员。
    • 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
    • 静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。(静态内部类是外部类的类相关,不是外部类的对象相关。静态内部类对象不是寄存在外部类对象里的,而是寄存在外部类的类本身中。当静态内部类对象存在时,并不存在一个被他寄存的外部类,静态内部类对象里只有对外部类的类引用,没有对外部类的对象应用。)
    • 外部类不能直接访问静态内部类成员,可以使用静态内部类的雷鸣作为调用者来访问静态内部类的类成员。
    public class A{
        static class B{
            private static int pro1 = 5;
            private int pro2 = 9;
        }
        public void accessInnerB(){
            System.out.println(B.pro1);
                System.out.println(new B().pro2);
      
        }
    }
    

    内部类的使用

    (1)外部类内部使用内部类

    不要再外部类的静态成员中使用非静态内部类,静态成员不能访问非静态成员。

    (2)外部类以外使用非静态内部类

    • 内部类不能使用private访问控制权限,private修饰的内部类只能在外部类的内部使用。
    • 省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类所访问。
    • 使用protected修饰的内部类,可悲与外部类处于同一个包中的其他类和外部类的子类所访问。
    • 使用public修饰的内部类,可以在任何地方被访问。

    (3)在外部类以外使用静态内部类

    语法:new OuterClass.InnerConstructor()


    局部内部类

    定义:把一个内部类放在方法中定义

    • 上一级程序单元都为方法,不是类,所以,所有的局部成员都不能使用static修饰。
    • 局部成员的作用域实在所在的方法,其他程序单元永远也不可能访问另一个方法中的局部成员,所以所有局部成员都不能使用访问控制符修饰。

    生成的class文件命名格式为:
    OuterClass$NInnerClass.class.

    public class LocalInnerClass
    {
        public static void main(String[] args)
        {
            // 定义局部内部类
            class InnerBase
            {
                int a;
            }
            // 定义局部内部类的子类
            class InnerSub extends InnerBase
            {
                int b;
            }
            // 创建局部内部类的对象
            InnerSub is = new InnerSub();
            is.a = 5;
            is.b = 8;
            System.out.println("InnerSub对象的a和b实例变量是:"
                + is.a + "," + is.b);
        }
    }
    

    匿名内部类

    定义:只需要使用一次的类,必须继承一个父类

    内部不能是抽象类

    系统在创建匿名内部类时,会创建匿名内部类的对象,因此,不允许将匿名内部类定义成抽象类。

    不能定义构造器

    • 匿名内部类没有类名,无法定义构造器,但匿名内部类可以定义实例初始化块,利用实例初始化块来完成构造器需要完成的事情。
    • 通过接口创建匿名内部类时,也不能显示创建构造函数,因此只有一个隐式的无参数构造器,所以new接口名后的括号不能传入参数值。
    • 通过继承父类创建匿名内部类时,将拥有和父类相似的构造器,既拥有相同形参列表。
    • 如果匿名内部类需要访问外部类的局部变量,必须用final修饰符来修饰外部类的局部变量。
    • 通过接口创建匿名内部类
    interface Product
    {
        public double getPrice();
        public String getName();
    }
    public class AnonymousTest
    {
        public void test(Product p)
        {
            System.out.println("购买了一个" + p.getName()
                + ",花掉了" + p.getPrice());
        }
        public static void main(String[] args)
        {
            AnonymousTest ta = new AnonymousTest();
            // 调用test()方法时,需要传入一个Product参数,
            // 此处传入其匿名实现类的实例
            ta.test(new Product()
            {
                public double getPrice()
                {
                    return 567.8;
                }
                public String getName()
                {
                    return "AGP显卡";
                }
            });
        }
    }
    
    • 继承父类创建匿名内部类
    abstract class Device
    {
        private String name;
        public abstract double getPrice();
        public Device(){}
        public Device(String name)
        {
            this.name = name;
        }
        // 此处省略了name的setter和getter方法
        public void setName(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return this.name;
        }
    }
    public class AnonymousInner
    {
        public void test(Device d)
        {
            System.out.println("购买了一个" + d.getName()
                + ",花掉了" + d.getPrice());
        }
        public static void main(String[] args)
        {
            AnonymousInner ai = new AnonymousInner();
            // 调用有参数的构造器创建Device匿名实现类的对象
            ai.test(new Device("电子示波器")
            {
                public double getPrice()
                {
                    return 67.8;
                }
            });
            // 调用无参数的构造器创建Device匿名实现类的对象
            Device d = new Device()
            {
                // 初始化块
                {
                    System.out.println("匿名内部类的初始化块...");
                }
                // 实现抽象方法
                public double getPrice()
                {
                    return 56.2;
                }
                // 重写父类的实例方法
                public String getName()
                {
                    return "键盘";
                }
            };
            ai.test(d);
        }
    }
    

    闭包&回掉

    闭包:能被调用的对象,保存了它的作用域信息。
    回掉:某个方法一旦获得了内部类对象的引用后,就可以再合适的时候反过来去调用外部类实例的方法。(允许客户类通过内部类引用来调用其外部类的方法)

    • 接口
    interface Teachable
    {
        void work();
    }
    
    • 程序员
    public class Programmer
    {
        private String name;
        //Programmer类的两个构造器
        public Programmer(){}
        public Programmer(String name)
        {
            this.name = name;
        }
        //此处省略了name的setter和getter方法
        public void setName(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return this.name;
        }
        public void work()
        {
            System.out.println(name + "在灯下认真敲键盘...");
        }
    }
    
    public class TeachableProgrammer extends Programmer
    {
        public TeachableProgrammer(){}
        public TeachableProgrammer(String name)
        {
            super(name);
        }
        //教学工作依然由TeachableProgrammer类定义
        private void teach()
        {
            System.out.println(getName() + "教师在讲台上讲解...");
        }
        private class Closure implements Teachable
        {
            /*
            非静态内部类回调外部类实现work方法,非静态内部类引用的作用仅仅是
            向客户类提供一个回调外部类的途径
            */
            public void work()
            {
                teach();
            }
        }
        //返回一个非静态内部类引用,允许外部类通过该非静态内部类引用来回调外部类的方法
        public Teachable getCallbackReference()
        {
            return new Closure();
        }
    }
    
    public class TeachableProgrammerTest
    {
        public static void main(String[] args)
        {
            TeachableProgrammer tp = new TeachableProgrammer("李刚");
            //直接调用TeachableProgrammer类从Programmer类继承到的work方法
            tp.work();
            //表面上调用的是Closure的work方法,
            //实际上是回调TeachableProgrammer的teach方法
            tp.getCallbackReference().work();
        }
    }
    
    

    <h6 align = "right"> ——整理自疯狂Java</h6>

    相关文章

      网友评论

        本文标题:Java内部类

        本文链接:https://www.haomeiwen.com/subject/nzblattx.html