zoukankan      html  css  js  c++  java
  • Java——内部类(inner class)

    为什么要使用内部类?

    主要因为以下三点:

    1、内部类方法可以访问该类定义所在的作用域的数据,包括私有数据。
    2、内部类可以对同一个包中的其他类隐藏起来。
    3、想要定义一个回调函数却不想编写大量代码,使用匿名内部类比较便捷。
     

    一个类的定义放在另一个类的内部,这个类就叫做内部类。 (类名不需要和文件夹相同)

    public class Inner {
        //像这样的,Contents就叫做内部类     
        public class Contents {
            public void f() {
                System.out.println("hello");
            }
        }
    }

    内部类可以是静态static的,也可用public,default,protected和private修饰。而外部类(类名和文件名相同的类)只能使用public和default来修饰。

    内部类是一种编译器现象,与虚拟机无关。编译器将会把内部类编译成用$分隔外部类名与内部类名的常规类文件,而虚拟机对此一无所知。
    例如:对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。

    内部类分为以下四种:      

    静态内部类static inner class (also called nested class)

    成员内部类member inner class

    局部内部类local inner class

    匿名内部类anonymous inner class

    静态内部类Static Inner Class

    1、最简单的内部类形式。

    2、类定义时加上static关键字。

    3、不能和外部类有相同的名字。

    4、只可以访问外部类的静态成员和静态方法,包括了私有的静态成员和方法。

    5、生成静态内部类对象的方式为:

      OuterClass.InnerClass inner = new OuterClass.InnerClass();

     
    package cy.内部类.静态内部类;
    
    public class StaticOuter {
        private static String name = "Outer";
        private int age = 10;
    
        public static class StaticInner {
            @SuppressWarnings("unused")
            private static String name = "Inner";
    
            public void sayOuterName() {
                System.out.println("inner:" + StaticOuter.name);
            }
            
            /*
             * 错误,静态内部类不能访问外部类的非静态成员。
                public void sayOuterAge() {
                    System.out.println(age);
                }
             */
        }
    
        public void sayName() {
            System.out.println(name);
        }
    
        public void sayAge() {
            System.out.println(age);
        }
    
    }
    package cy.内部类.静态内部类;
    
    public class TestMain {
        public static void main(String[] args) {
            StaticOuter staticOuter = new StaticOuter();
            staticOuter.sayAge();
            staticOuter.sayName();
            
            StaticOuter.StaticInner staticInner = new StaticOuter.StaticInner();
            staticInner.sayOuterName();
        }
    }

    运行结果:

    10
    Outer
    inner:Outer

    由此可以看出,静态内部类的对象处了没有对外围类对象的应用特权外,与其他所有内部类完全一样。

    成员内部类member inner class

    package cy.内部类.成员内部类;
    
    public class Outer {
        private static String name = "Outer";
        private int age = 10;
    
        public class Inner {
            private final static String name = "Inner";
            private int age = 11;
            
            public void sayOuterName() {
                // 内部类中引用外部类对象的静态成员
                System.out.println("inner:" + Outer.name);
            }
            
            public void sayInnerName() {
                System.out.println("inner:" + Inner.name);
            }
            
            public void sayInnerAge() {
                System.out.println("inner:" + this.age);
            }
    
            public void sayOuterAge() {
                // 内部类中引用外部类对象的非静态成员
                System.out.println(Outer.this.age);
            }
            
            public Outer createOuter() {
                // 内部类中创建外部类。
                return new Outer();
            }
    
        }
    
        public void sayName() {
            System.out.println(name);
        }
    
        public void sayAge() {
            System.out.println(age);
        }
    
        public Inner createInner() {
            // 外部类中创建内部类对象。
            return this.new Inner();
        }
        
    }
    public class TestMain {
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.sayAge();
            outer.sayName();
    
            // 区别于静态内部类的创建方法
            Inner inner = outer.new Inner();
            inner.sayOuterName();
        }
    }

    运行结果:

    10
    Outer
    inner:Outer

    局部内部类local inner class

    局部类不能用public,protected或者private访问说明符进行声明。它的作用域是被限定在这个局部类的块中。

    局部类有一个优势,即对外世界可以完全隐藏起来,其他类中的代码不能访问它。

    package cy.内部类.局部内部类;
    
    public class Outer {
        private static String name = "Outer";
        private int age = 10;
    
        public void doSomeThing() {
    
            // 局部内部类,局部内部类,不允许带有 public,protected,private
            // public class Inner {
            // protected class Inner {
            // private class Inner {
            class Inner {
                // private static String name;
                // private final static String name;
    
                public void sayInnerName() {
                    System.out.println(name);
                }
    
                public void sayOuterName() {
                    System.out.println(Outer.name);
                }
            }
    
            Inner inner = new Inner();
            inner.sayInnerName();
            inner.sayOuterName();
        }
    
        public void doSomeThingA() {
            if (this.age > 0) {
    
                // 这个Inner与上一个Inner没有任何关系
                class Inner {
                    public void sayInnerName() {
                        System.out.println(name);
                    }
    
                    public void sayOuterName() {
                        System.out.println(Outer.name);
                    }
                }
    
                Inner inner = new Inner();
                inner.sayInnerName();
                inner.sayOuterName();
            }
    
        }
    
        public void sayName() {
            System.out.println(name);
        }
    
        public void sayAge() {
            System.out.println(age);
        }
    
    }

    匿名内部类anonymous inner class

    假设这创建某个类的一个对象,就不必命名了,这种类成为“匿名内部类”。

    package cy.内部类.匿名内部类;
    
    public class Outer {
        public static void main(String[] args) {
    
            // 内部类引用外部类对象,使用final。
            final String name = "name";
    
            // 接口直接创建对象。类名称并没有直接定义。Java编译器会自动给一个类名称。
            // 注意匿名内部类的重要使用场景。“线程”
            Say s = new Say() {
                @Override
                public void say() {
                    System.out.println("hello world " + name);
                }
            };
    
            s.say();
        }
    }
    
    interface Say {
        void say();
    }

    这种语法有点难理解,它的含义是:创建一个实现Say接口的类的新对象,需要实现的方法say定义在{}中。

    由于构造器的名字必须跟类名相同,而匿名类没有名称,所以匿名类不能有构造器。取而代之的是,构造器参数传递给超类(superclass)构造器。尤其是在内部类实现接口的时候,不能有任何构造参数。

  • 相关阅读:
    docker 安装 clickhouse单机版
    CockRoachDB简介
    Ubuntu18.04 LTS Cockroach集群搭建
    ClickHouse 的一些优化参数
    ClickHouse 概念整理
    OOM Killer机制
    win10系统下载地址
    Quartz.Net在C#中的使用
    JavaScript的undefined与null、NaN的区别
    Java Web基础回顾 —JSP
  • 原文地址:https://www.cnblogs.com/iCcccy/p/4692227.html
Copyright © 2011-2022 走看看