Java内部类详解

来源:互联网 发布:唯品会下单软件 编辑:程序博客网 时间:2024/06/16 09:25

简介:

  内部类(nested classes),面向对象程序设计中,可以在一个类的内部定义另一个类。嵌套类分为两种,即静态嵌套类和非静态嵌套类。静态嵌套类使用很少,最重要的是非静态嵌套类,也即是被称作为内部类(inner)。内部类是JAVA语言的主要附加部分。内部类几乎可以处于一个类内部任何位置,可以与实例变量处于同一级,或处于方法之内,甚至是一个表达式的一部分。

定义:

  内部类是JAVA语言的主要附加部分。嵌套类从JDK1.1开始引入。其中inner类又可分为三种:
- 其一、在一个类(外部类)中直接定义的内部类;
- 其二、在一个方法(外部类的方法)中定义的内部类;
- 其三、匿名内部类。

表现形式:

  1. 静态内部类
  2. 成员内部类
  3. 局部内部类
  4. 匿名内部类

优点:

  1. 内部类对象可以访问创建它的对象的实现,包括私有数据;
  2. 内部类不为同一包的其他类所见,具有很好的封装性;
  3. 使用内部类可以很方便的编写事件驱动程序;
  4. 匿名内部类可以方便的定义运行时回调;
  5. 内部类可以方便的定义

关于内部类的一些知识点:

1.静态修饰符。

  如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。
注意;如果内部类中定义了静态成员,那么该内部类必须是静态的。
内部类编译后的文件名为:“外部类名$内部类名.java”;

2.为什么内部类可以直接访问外部类中的成员呢?

  那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this
内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。

3.当内部类被定义在局部位置上,只能访问局部中被final修饰的局部变量。为什么?

  因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用

4.关于内部类对象的创建。

  如何在包含内部类的外部类中创建直接new就可以了,如果是在其他外部类中,创建看下面例子,当然内部类作为外部类的成员变量如果被private修饰,外部类是没有访问该内部类的权限的,也因此内部类具有很好的隐蔽性。

  非静态成员内部类创建,成员内部类就相当于是个普通的成员变量,要想使用这个成员变量,必要要依附在外部类对象的基础上,所以需要先把外部类new出来,才能接着new出内部类。

public class OuterClass {    public class Inter{    }}class Another{    public static void main(String args[]) {//        OuterClass.Inter inter = new OuterClass.Inter();  //错误        OuterClass.Inter inter2 = new OuterClass().new  Inter(); //正确    }}

  静态 内部类对象的创建,还是和 上面的是一个道理,因为是静态的所以直接外部对象+”.”就可以直接引用了,但是内部类还是需要new的,所以新建对象就像下面这样。

public class OuterClass {    public static class Inter{    }}class Another{    public  static void main(String args[]) {        OuterClass.Inter inter = new OuterClass.Inter();    }}

5.外部类的静态方法不能创建非静态内部类的对象

  因为静态方法随类的加载而加载,这时非静态内部类还没有加载。

public class OuterClass {    public static Inter getInter(){        return new Inter(); // 这一句会报错    };    class Inter{    }}

6.内部类向上转型为接口

  如果将一个权限修饰符为private的内部向上转型为其父类对象,或者直接向上转型为一个接口。在程序中舅舅可以完隐藏内部的具体实现过程。可以在外部提供一个接口,在接口中声明一个方法,如果在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一个方法,而在一般的类中是不能多次实现接口中的同一个方法。

interface OutInterface { // 定义一个接口    public void f();}public class InterfaceInner {    public static void main(String args[]) {        OuterClass2 out = new OuterClass2(); // 实例化一个OuterClass2对象        // 调用doit()方法,返回一个OutInterface接口        OutInterface outinter = out.doit();        outinter.f(); // 调用f()方法    }}class OuterClass2 {    // 定义一个内部类实现OutInterface接口    private class InnerClass implements OutInterface {        InnerClass(String s) { // 内部类构造方法            System.out.println(s);        }        public void f() { // 实现接口中的f()方法            System.out.println("访问内部类中的f()方法");        }    }    public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口        return new InnerClass("访问内部类构造方法");    }}
除了OuterClass2类可以访问这个内部类以外,其他类都不能访问该类,但是却可以访问他的doit方法,doit方法返回值类型又是外部接口类型,这样很好的对继承该类的子类隐藏了实现细节,仅为编写子类的人留下一个接口和一个外部类,同时也可以调用f()方法,但是f()方法的具体实现却得到了很好的隐藏,这就是内部类最基本的用途。非内部类不能被声明为private或者protected访问类型。

7.使用this关键字获取内部类与外部类的引用

public class TheSameName {    private int x;    private class Inner {        private int x = 9;        public void doit(int x) {            x++; // 调用的是形参x            this.x++; // 调用内部类的变量x            TheSameName.this.x++; // 调用外部类的变量x        }    }}

8.内部类的继承

class WithInner {      class Inner {}  }  public class InheritInner extends WithInner.Inner {      public InheritInner(WithInner wi) {          wi.super();      }      public static void main(String[] args) {          WithInner wi = new WithInner();          InheritInner ii = new InheritInner(wi);      }  }  
  要理解这个问题就得先理解内部类,Inner是WithInner的内部类,那么一般的用法WithInner.Inner inner = new WithInner(). new Inner() ;我们可以看出要想创建Inner的对象必须先创建WithInner的对象之后才能创建Inner对象,那么现在你要用一个类InheritInner继承Inner类,在继承过程中构造方法会被调用,即使你不写也会调用默认构造方法,但问题出现了,在调用父类Inner构造方法时找不到WithInner的对象,所以就必须给InheritInner类的构造方法传入WithInner对象再通过wi.super();方法调用Inner的默认构造方法,因为这是创建对象的基本流程,所以这句话wi.super();是必须的。

9.局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么?

       因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以 。

1 0
原创粉丝点击