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)构造器。尤其是在内部类实现接口的时候,不能有任何构造参数。

posted @ 2015-07-31 15:10  iCcccy  阅读(265)  评论(0编辑  收藏  举报