内部类总结

来源:互联网 发布:复制淘口令淘宝没反应 编辑:程序博客网 时间:2024/06/06 02:01

在Java中,可以将一个类定义在另一个 类里面或者一个方法里面,这样的类称 为内部类。广泛意义上的内部类一般来 说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类

内部类的共性:

1、内部类仍然是一个独立的类,在编 译之后内部类会被编译成独立的.class 文件,但是前面冠以外部类的类名和$ 符号;
2、内部类不能用普通的方式访问。内 部类是外部类的一个成员,因此内部类 可以自由地访问外部类的成员变量,无 论是否是private的;
3、内部类声明成静态的,就不能随便 的访问外部类的成员变量了,此时内部 类只能访问外部类的静态成员变量。

成员内部类

成员内部类的基本应用:

成员内部类是最普通的内部类,它的定义为位于另一个类的内部。 基本形式如下:

//外部类class Out {    private int age = 12;    //内部类    class In {        public void print() {            System. out.println(age );        }    }}public class Demo {    public static void main(String[] args) {        Out.In in = new Out().new In();        in.print();        //或者采用下种方式访问        /*        Out out = new Out();        Out.In in = out.new In();        in.print();        */    }}

运行结果:12

从上面的例子不难看出,内部类其实严重破坏了良好的代码结构,但为什么还要使用内部类呢?

因为内部类可以随意使用外部类的成员变量(包括私有)而不用生成外部类的对象,这也是内部类的唯一优点。

程序编译过后会产生两个.class文件,分别是Out.class和OutIn.class代表了上面程序中Out.In中的那个 。

Out.In in = new Out().new In()可以用来生成内部类的对象,这种方法存在两个小知识点需要注意:

  1.开头的Out是为了标明需要生成的内部类对象在哪个外部类当中

  2.必须先有外部类的对象才能生成内部类的对象,因为内部类的作用就是为了访问外部类中的成员变量

内部类如何访问外部类的变量

不过要注意,当成员内部类拥有和外部 类同名的成员变量和方法时,会发生隐 藏现象,即默认情况下访问的是成员内 部类的成员,看下面这个例子:

class Out {    private int age = 12;    class In {        private int age = 13;        public void print() {            int age = 14;            System. out.println("局部变量:" + age);            System. out.println("内部类变量:" + this. age);            System. out.println("外部类变量:" + Out.this. age);        }    }}public class Demo {    public static void main(String[] args) {        Out.In in = new Out().new In();        in.print();    }}

运行结果:

局部变量:14
内部类变量:13
外部类变量:12

从上面的例子可以总结出,访问内部类本身的成员变量可用this.属性名的方式。而如果要访问外 部类的同名成员,需要使用以下方式:

1、外部类.this.成员变量
2、外部类.this.成员方法

外部类如何访问内部类的变量

在成员内部类中可以无条件的访问外部 类的成员,而外部类想访问成员内部类 的成员就有限制了。在外部类中,如果 要访问成员内部类的成员,必须先创建 一个成员内部类的对象,再通过指向这 个对象的引用来访问。看下面这个例子 :

class Circle {    private double radius = 0;    public Circle( double radius) {        this.radius = radius;        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问    }    private Draw getDrawInstance() {        return new Draw();    }    class Draw {     //内部类        public void drawSahpe() {            System. out.println(radius );  //外部类的private成员        }    }}

成员内部类是依赖外部类存在的,如果要创建成员内部类的对象,则必须要有一个外部类的对象。 看下面这个例子,我们来总结一下成员内部类对象的创建方式:

class Out {//外部类    private In inner = null ;    public Out() {}    public In getInnerInstance() {        if(inner == null)            inner = new In();        return inner ;    }    class In { //内部类        public In() {}    }}public class Test {    public static void main(String[] args)  {              Out outter = new Out();        //第一种方式:        Out.In inner = outter. new In();  //必须通过 Outter对象来创建               //等价于下面这种写法 Out.In inner = new Out().new In();        //第二种方式:        Out.In inner1 = outter.getInnerInstance();    }}

内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。

我们来看下面这个私有内部类的示例:

class Out {    private int age = 12;    private class In {        public void print() {            System. out.println(age );        }    }    public void outPrint() {        new In().print();    }}public class Demo {    public static void main(String[] args) {        //此方法无效        /*        Out.In in = new Out().new In();        in.print();        */        Out out = new Out();        out.outPrint();    }}

运行结果:12

上面的代码中,我们必须在Out类里面生成In类的对象进行操作,而无法再使用Out.In in = new Out().new In() 生成内部类的对象 。如果一个内部类只希望被外部类中的方法操作,那么可以使用private声明内部类。也就是说,此时的内部类只有外部类可控制。

局布内部类

局部内部类是定义在一个方法或者一个 作用域里面的类,它和成员内部类的区 别在于局部内部类的访问权限仅限于方 法内或者该作用域内。简而言之,局部 内部类就像是方法里面的一个局部变量 ,是不能有public、protected、 private以及static修饰符修饰的。我们来看下面的例子:

class Out {    private int age = 12;    public void Print(final int x) {        class In {            public void inPrint() {                System. out.println(x);                System. out.println(age );            }        }        new In().inPrint();    }}public class Demo {    public static void main(String[] args) {        Out out = new Out();        out.Print(3);    }}

运行结果:

3
12

在上面的代码中,我们将内部类移到了外部类的方法中,然后在外部类的方法中再生成一个内部类对象去调用内部类方法。如果此时我们需要往外部类的方法中传入参数,那么外部类的方法形参必须使用final定义。至于final在这里并没有特殊含义,只是一种表示形式而已。

匿名内部类

顾名思义,匿名内部类就是没有名字的内部类。表 面上看起来它们似乎有名字,但实际上那不是它们 的名字。程序中使用匿名内部类时,在定义匿名 内部类的地方往往直接创建该类的一个对象。使用 匿名内部类有个前提条件:必须继承一个父类或实 现一个接口。匿名内部类的声明格式如下

//匿名内部类的声明格式new ParentName(){       //匿名内部类的定义}

为什么要使用匿名内部类?我们看下面一个例子, 当不使用匿名内部类时我们是这样实现抽象方法的 :

abstract class Person {    public abstract void eat();}class Child extends Person {    public void eat() {        System. out.println("eat something" );    }}public class Demo {    public static void main(String[] args) {        Person p = new Child();        p.eat();    }}

可以看到,我们用Child继承了Person类,然后实 现了Child的一个实例,将其向上转型为Person类 的引用。但是,如果此处的Child类只使用一次, 那么将其编写为独立的一个类岂不是很麻烦?这个 时候就引入了匿名内部类。我们来看使用匿名内部 类我们怎么实现:

abstract class Person {    public abstract void eat();}public class Demo {    public static void main(String[] args) {        Person p = new Person() {            public void eat() {                System. out.println("eat something" );            }        };        p.eat();    }}

可以看到,我们直接将抽象类Person中的方法在大 括号中实现了。这样便可以省略一个类的书写。

什么情况下需要使用匿名内部类?如果满足下面的 一些条件,使用匿名内部类是比较合适的:
1、只用到类的一个实例 。
2、类在定义后马上用到。
3、类非常小(SUN推荐是在4行代码以下)
4、给类命名并不会导致你的代码更容易被理解

在使用匿名内部类时,要记住以下几个原则:
1、匿名内部类不能有构造方法。
2、匿名内部类不能定义任何静态成员、静态方法。
3、匿名内部类不能是 public,protected,private,static。
4、只能创建匿名内部类的一个实例。
5、一个匿名内部类一定是在new的后面,用其隐含 实现一个接口或实现一个类。
6、因匿名内部类为局部内部类,所以局部内部类 的所有限制都对其生效

1、继承式的匿名内部类

abstract class Person {    public abstract void eat();}public class Demo {    public static void main(String[] args) {        Person p = new Person() {            public void eat() {                System. out.println("eat something" );            }        };        p.eat();    }}

2、接口式的匿名内部类

好像是在实例化一个接口。事实并非如此,接口式 的匿名内部类是实现了一个接口的匿名类。而且只 能实现一个接口。我们看下面这个例子:

interface Person {    public void eat();}public class Demo {    public static void main(String[] args) {        Person p = new Person() {            public void eat() {                System. out.println("eat something" );            }        };        p.eat();    }}

只要一个类是抽象的或是一个接口,那么其子类中 的方法都可以使用匿名内部类来实现。最常用的情 况就是在多线程的实现上,因为要实现多线程必须 继承Thread类或是继承Runnable接口。

Thread类的匿名内部类实现

public class Demo {    public static void main(String[] args) {        Thread t = new Thread() {            public void run() {                for (int i = 1; i <= 5; i++) {                    System. out.print(i + " " );                }            }        };        t.start();    }}运行结果:1 2 3 4 5

Runnable接口的匿名内部类实现

public class Demo {    public static void main(String[] args) {        Runnable r = new Runnable() {            public void run() {                for (int i = 1; i <= 5; i++) {                    System.out.print(i + " ");                }            }        };        Thread t = new Thread(r);        t.start();    }}运行结果:1 2 3 4 5

3、参数式的匿名内部类

class Test{       static void go(){            Bar b = new Bar();            b.doStuff( new Foo(){                   public void foo(){                        System. out.println("foofy" );                  }            });      }}class Bar{       void doStuff(Foo f){            f.foo();      }}interface Foo{       void foo();}

关于匿名内部类的一个典型的应用就是Hibernate的HibernateCallBack,有兴趣的同学可以参看本人的另外一篇博客。

静态内部类

静态内部类也是定义在另一个类里面的类,只不过 在类的前面多了一个关键字static。静态内部类是 不需要依赖外部类的,这点和类的静态成员属性有 点类似,并且它不能是由外部类的非static成员变 量或者方法,这点很好理解,因为在没有外部类的 对象的情况下,可以创建静态内部类的对象,如果 允许访问外部类的非static成员就会产生矛盾,因 为外部类的非static成员必须依附于具体的对象。 我们来看下面的例子:

这里写图片描述

2 0
原创粉丝点击