Java核心基础加强系列-内部类

2019是个学习之年,之前列出了一些需要加强的Java核心基础点,详情可参考文章 致敬2019,本篇文章是Java核心基础加强系列的第一篇文章。

内部类的定义

顾名思义,所谓内部类,是定义在一个类里面的类。

class OutterClass{
  private String outterName;
  class InnerClass{
    private String innerName;
  }
}

内部类的意义

每个内部类都能独立地继承一个接口的实现,无论外围类是否已经继承了某个接口的实现,对于内部类没有任何影响。

Java是不允许多继承的,可能你会说,Java的多继承是通过接口来实现的,可以实现多个接口啊,但是如果我们把接口换成抽象类呢,是不是接口的多实现就失效了呢。

其实,内部类的出现就是为了弥补Java在多继承上的限制与不足,使得Java在多继承上的解决方案变得完整。

初识内部类

下面我们就一个 成员内部类 实例来分析一下内部类的基础用法。

/**
 * User:        listeningrain
 * Date:        2019/1/10 10:35
 * Description: java内部类测试类
 */
public class OutterClass {

    private String name;
    private static Integer age;

    public OutterClass(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void outterPrint(){
        System.out.println("外部类的print方法");
    }

    //外围类作用范围内可以直接生成内部类的对象
    public void getInstance(){
        new InnerClass();
    }

    /**
     *内部类的定义
     */
    public class InnerClass{
        public void innerPrint(){
            //无限制地访问外围类的属性(无论是不是静态,私有)
            System.out.println("外部类name:"+name+"  外部类静态age: "+age);
        }

        public OutterClass getOutterClass(){
            return OutterClass.this;  //返回外部类的引用
        }
    }

    public static void main(String[] args){

        /**
         *在外围类的作用范围外,必须通过外部类的对象生成内部类的对象
         *通过外部类的对象的.new方法生成内部类对象
         */
        OutterClass outterClass = new OutterClass("听雨",23);
        OutterClass.InnerClass innerClass = outterClass.new InnerClass(); //
        innerClass.innerPrint();
        
        //通过内部类获得内部类对象的引用
        OutterClass outterClass1 = innerClass.getOutterClass();
        outterClass1.outterPrint();
    }
}

在上面的代码中,我们可以看到以下特点:

  1. 内部类可以无限制地访问外部类的属性和方法,无论其是不是私有的,是不是静态的。
  2. 在外围类的作用范围内,可以直接通过new()生成内部类的对象,但是在外围类的作用范围外,需要通过调用外部类对象的.new方法,才能生成内部类的对象。总而言之,要想调用内部类的属性和方法,只能通过内部类的对象,外围类是不能直接访问的。
  3. 在内部类中,可以通过外部类的.this方法返回外部类的引用。
咚咚咚~ 划重点了。
Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。

内部类的分类

内部类也有数种不同的分类,主要包括:成员内部类,局部内部类,匿名内部类,静态内部类,下面将逐一说明。

成员内部类

成员内部类是最普通的一类,内部类是外部类的一个成员变量,上面的例子就是一个成员内部类的实例,内部类可以无限制地访问外部类的属性和方法,无论其限定修饰符是不是私有的。但是外围类想访问内部类的属性和方法,必须通过内部类的对象来访问。

当然成员内部类也有一些限制:

  1. 成员内部类不能有static的属性和方法。
  2. 成员内部类依附于外部类,只有先创建了外部类的对象,才能创建内部类的对象。
/**
 * User:        listeningrain
 * Date:        2019/1/10 15:00
 * Description:
 */
public class OutterClass {
    private String str;

    public void outerPrint(){
        System.out.println("outerClass的print方法");
    }

    public class InnerClass{
        public void innerPrint(){
            //使用外围内的属性
            str = "Hello Outter, I am Inner";
            System.out.println(str);
            //使用外围内的方法
            outerPrint();
        }
    }

    /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
    public InnerClass getInnerClass(){
        return new InnerClass();
    }

    public static void main(String[] args) {
        OutterClass outer = new OutterClass();
        OutterClass.InnerClass inner = outer.getInnerClass();
        inner.innerPrint();
    }
}

局部内部类(用得比较少)

未完待续。。。

匿名内部类

关于匿名内部类,可能大家印象最深刻的就是在学习Java Swing编程的时候,定义一个事件监听器了,像下面这样:

button2.addActionListener(  
        new ActionListener(){  
            public void actionPerformed(ActionEvent e) {  
                  System.out.println("按钮被点击了");  
                }  
        });

关于匿名内部类的另一个例子

public class OuterClass {
   public InnerClass getInnerClass(final int num,String str2){
       return new InnerClass(){
           int number = num + 3;
           public int getNumber(){
               return number;
           }
       };        /* 注意:分号不能省 */
   }
   
   public static void main(String[] args) {
       OuterClass out = new OuterClass();
       InnerClass inner = out.getInnerClass(2, "chenssy");
       System.out.println(inner.getNumber());
   }
}

interface InnerClass {
   int getNumber();
}

匿名内部类的一些特点:

1、 匿名内部类是没有访问修饰符的。

2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。

3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。

4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。

静态内部类

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

1、 它的创建是不需要依赖于外围类的。

2、 它不能使用任何外围类的非static成员变量和方法。

下面来看一个例子:

/**
 * User:        listeningrain
 * Date:        2019/1/10 10:35
 * Description: java内部类测试类
 */
public class OutterClass {

    private String sex;
    public static String name = "outer name";

    /**
     *静态内部类的定义
     */
    static class InnerClass1{
        /* 在静态内部类中可以存在静态成员 */
        public static String _name1 = "static_inner1Name";

        public void display(){
            /*
             * 静态内部类只能访问外围类的静态成员变量和方法
             * 不能访问外围类的非静态成员变量和方法
             */
            System.out.println("OutClass name :" + name);

            /**
             *   System.out.println(sex); 报错
             */
        }
    }

    /**
     * 非静态内部类
     */
    class InnerClass2{
        /* 非静态内部类中不能存在静态成员 */
        private String _name2 ="non_static_inner2Name";
        /**
         *     static String age; 报错
         */

        /* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
        public void display(){
            System.out.println("OuterClass name:" + name);
        }
    }

    /**
     * 外围类方法
     */
    public void display(){
        /* 在外围类的作用范围内,可以直接创建实例不需要依赖于外围类 */
        new InnerClass1().display();
        new InnerClass2().display();
    }

    public static void main(String[] args) {
        OutterClass outer = new OutterClass();
        outer.display();
        
        /**
         * 在外围类的作用范围外,静态内部类对象的生成不依赖外部类对象
         */
        OutterClass.InnerClass1 innerClass1 = new OutterClass.InnerClass1();
        innerClass1.display();
    }

内部类实战

讲了这么多理论的东西,那么内部类到底该怎么用呢?

未完待续。。。

参考资料:https://www.cnblogs.com/dolphin0520/p/3811445.html

已有 1 条评论
  1. 静心听雨

    自己占个沙发

    静心听雨 回复
发表新评论