Java内部类

一、为何使用内部类

1、内部类提供了更好的封装,只有外部类能访问内部类;

2、内部类可以独立继承一个接口,不受外部类是否继承接口影响;

3、内部类中的属性和方法即使是外部类也无法直接访问,相反外部类可以直接访问内部类的属性和方法,即使使用private修饰;

4、利用回调函数的编写;

下面是一个内部类的例子:

public class OuterClass {
    private String outerName;
    private int outerAge;
    public class InnerClass{
        private String innerName;
        private int innerAge;
    }
}

二、内部类与外部类的联系

1、内部类是一个相对独立的实体,与外部类不是is-a的关系;

内部类是一个编译时概念,编译后外部类及其内部类会生成两个独立的class文件:OuterClass.classOuterClass$InnerClass.class,我用Java编译器对象面的OuterClass进行编译,编译后的结果如下:


2、内部类可以直接访问外部类的元素,但是外部类不可以直接访问内部类的元素;
public class OuterClass {

    private String outerName;
    private int outerAge;

    public class InnerClass{
        private int innerName;
        InnerClass(){
            //内部类可以访问外部类的元素
            outerName="I am outer class";
            outerAge=23;
        }
        public void display(){
            System.out.println(outerName+" and my age is "+outerAge);
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.display();
    }
}

在上面的例子中可以看到,内部类可以直接访问外部类的属性,尽管外部类使用的private修饰。这是因为在创建外部类时,内部类会自动捕获一个外部类的引用,所以内部类可以访问外部类元素,实际上是通过他所持有外部类引用的访问。在Java中,我们可以用过OuterClass.this来获得外部类的引用,例子如下:

public class OuterClass {
    public void display(){
        System.out.println("this is OuterClass...");
    }
    public class InnerClass{
        //获取外部类的引用
        public OuterClass getOuterClass(){
            return OuterClass.this;
        }
        public void innerDisplay(){
            //内部类也可以通过外部类的引用访问外部元素
            getOuterClass().display();
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.innerDisplay();
    }
}
3、外部类可以通过内部类引用间接访问内部类元素;
public class OuterClass {
    public void display(){
        //外部类访问内部类元素,需要通过内部类引用访问
        InnerClass innerClass=new InnerClass();
        innerClass.innerDisplay();
    }
    public class InnerClass{
        public void innerDisplay(){
            System.out.println("I am inner class");
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass=new OuterClass();
        outerClass.display();
    }
}

三、创建内部类

1、在外部类外面(即另外一个方法里面)创建内部类对象

OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();

其实也可以一步到位:

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

内部类对象创建方法实例:

public static void main(String[] args) {
    //先创建外部类对象,再创建内部类对象
    OuterClass outerClass = new OuterClass();
    OuterClass.InnerClass innerClass1 = outerClass.new InnerClass();
    innerClass1.innerDisplay();
    //一步到位创建
    OuterClass.InnerClass innerClass2=new OuterClass().new InnerClass();
    innerClass2.innerDisplay();
}

2、在外部类里面创建内部类对象

InnerClass innerClass=new InnerClass()

四、内部类的种类

在Java中内部类主要分为成员内部类、方法内部类、匿名内部类、静态内部类。

1、成员内部类;

成员内部类也是最普通的内部类,它是外部类的一个成员,所以它可以无限制的访问外部类的所有成员属性和方法,即使是private修饰的。但是外部类要访问内部类的属性和方法则要通过内部类实例来访问。

在成员内部类中要注意的两点:

①成员内部类中不存在任何static的变量和方法;

②成员内部类是依附于外部类的,所以只有先创建了内部类才可以创建外部类;

2、方法内部类(局部内部类);

方法内部类定义在外部类的方法中,方法内部类和成员内部类基本一致,只是他们的作用域不同,方法内部类只能在该方法中被使用,出了该方法就会失败。对于这个类的使用主要是应用与解决比较复杂的问题。例如:想创建一个类来辅助我们解决问题,但是又不希望这个类是公用的,这个时候就可以使用方法内部类。

3、匿名内部类;

匿名内部类其实就是一个没有名字的方法内部类,所以它符合方法内部类的所有约束,除此之外还有一些地方要注意:

①匿名内部类是没有修饰符的;

②匿名内部类必须继承一个抽象类或者实现一个接口;

③匿名内部类中不存在任何静态成员和方法;

④匿名内部类是没有构造方法的,因为它没有类名;

一般使用匿名内部类的场景是要继承或者实现的接口只有一个抽象方法,比如添加一个监听器:

public class Button {
    public void click(){
        //匿名内部类,实现的是ActionListener接口
        new ActionListener(){
            public void onAction(){
                System.out.println("click action...");
            }
        }.onAction();
    }
    //匿名内部类必须继承或实现一个已有的接口
    public interface ActionListener{
        public void onAction();
    }

    public static void main(String[] args) {
        Button button=new Button();
        button.click();
    }
}
4、静态内部类;

关键字static可以修饰成员变量、方法、代码块,其实它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,但是静态内部类却没有。没有这个引用就意味着:

①静态内部类的创建是不需要依赖于外部类,可以直接创建

②静态内部类不可以使用任何外部类的非static成员变量和方法,而内部类则都可以

public class OuterClass {
    private static String outerName;
    public  int age;

    static class InnerClass1{
        /* 在静态内部类中可以存在静态成员 */
        public static String _innerName = "static variable";
        public void display(){
            /*
             * 静态内部类只能访问外部类的静态成员变量和方法
             * 不能访问外部类的非静态成员变量和方法
             */
            System.out.println("OutClass name :" + outerName);
        }
    }
    class InnerClass2{
        /* 非静态内部类中不能存在静态成员 */
        public String _innerName = "no static variable";
        /* 非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的 */
        public void display(){
            System.out.println("OuterClass name:" + outerName);
            System.out.println("OuterClass age:" + age);
        }
    }
    public void display(){
        /* 外部类能直接访问静态内部类静态元素 */
        System.out.println(InnerClass1._innerName);
        /* 静态内部类可以直接创建实例不需要依赖于外部类 */
        new InnerClass1().display();
        /* 非静态内部的创建需要依赖于外部类 */
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
        /* 非静态内部类的成员需要使用非静态内部类的实例访问 */
        System.out.println(inner2._innerName);
        inner2.display();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.display();
    }
}




你可能感兴趣的:(工作学习笔记,java,内部类)