内部类详解

文章地址:http://blog.csdn.net/JavaEETeacher/archive/2011/03/26/6279460.aspx

内部类

内部类包括如下几种形式:

l         作为类成员的内部类;

l         成员方法中定义的内部类;

l         匿名内部类;

l         静态内部类。

http://blog.csdn.net/javaeeteacher 李绪成

1作为类成员的内部类

1.1内部类的编写

内部类和外部类的定义形式相同,但是需要在类中定义:

public class MyOuter {

       public class MyInner{

       }

}

该文件编译后能够生成两个类:MyOuter.classMyOuter$MyInner.class

注意:内部类的访问控制符有:publicprotectedprivate和缺省的,与类的成员变量和成员方法的访问控制符相同,而外部类的访问控制符只有public和缺省的。

内部类可以访问所在的外部类的成员变量,包括私有成员变量,就像类自身的方法能够访问类的所有类型的成员变量一样,例如下面的代码是正确的:

public class MyOuter {

       private String name="test";

       class MyInner{

              public void print(){

                     System.out.println(name);

              }

       }

}

内部类中不能定义static类型的方法,下面的代码是错误的:

public class MyOuter {

       private String name="test";

       class MyInner{

              public static void print(){

                     System.out.println(name);

              }

       }

}

内部类可以是抽象的,内部类可以继承某个类,也可以实现某个接口,

public class MyOuter {

       private String name="test";

       abstract class MyInner1{

              public abstract void print();

       }

       class MyInner2 extends MyInner1 implements Serializable{

              public void print(){

                     System.out.println(name);

              }

       }

}

内部类也可以是final类。

1.2从外部类的代码中使用内部类

可以把内部类的对象作为外部类的成员变量使用,可以在外部类的方法中使用内部类的对象。

下面的代码演示了如何把内部类的对象作为成员并且展示了两种实例化的代码:

public class MyOuter {

       private MyInner in=new MyInner(); //定义的时候实例化

       private MyInner in2; // 先定义

       public MyOuter(){

              in2 = new MyInner(); // 在构造方法中实例化,也可以在其他方法中实例化

       }

   

}

下面的代码展示了如何在外部类的方法中使用内部类的对象:

public class MyOuter {

       public void makeInner(){

              MyInner in3 = new MyInner(); //方法中定义变量并实例化

              in3.print();

       }

   

}

上面的实例化代码相当于MyOuter.MyInner in3 = this.new MyInner();,因为在类的内部使用所以在类型前面省略了MyOuter,实例化的时候省略的“this.”。

1.3 从外部类的代码外实例化内部类

在外部类的代码之外使用内部类,就像访问类的实例变量一样,需要先创建外部类的对象,然后通过外部类的对象访问内部类的方法,下面的代码展示了用法:

       public static void main(String[] args) {

              MyOuter.MyInner in = new MyOuter().new MyInner();

              in.print();

             

              MyOuter out = new MyOuter();

              MyOuter.MyInner in2 = out.new MyInner();

              in2.print();

       }

代码中展示了两种方式,两种方式的作用是相同的,下面的代码是错误的:

MyOuter.MyInner in3 = MyOuter.new MyInner();

MyOuter.MyInner in4 = new MyOuter.MyInner();

注意:在外部类的代码之外使用内部类,内部类必须是可见的,下面的代码是错误的:

public class MyOuter {

       private class MyInner{

              public void print(){

                     System.out.println(name);

              }

       }

   

}

public class Main {

       public static void main(String[] args) {

              MyOuter.MyInner in = new MyOuter().new MyInner();

       }

}

1.4 在内部类中引用外部类实例或者内部类实例

在类中引用当前实例可以使用this,但是内部类中要引用内部类的实例或者内部类所在的外部类的实例如何引用呢?在内部类中引用内部类自身的实例仍然是通过this,在内部类中引用外部类的实例需要使用外部类的名字加上this的方式,下面的代码展示了用法:

public class MyOuter {

       int x=20;

       public class MyInner2{

              int x=10;

              public void print(){

                     int x=5;

                     System.out.println("局部变量x的值:"+x);

                     System.out.println("内部类成员变量x的值:"+this.x);

                     System.out.println("外部类成员变量x的值:"+MyOuter.this);

              }

       }

       public static void main(String args[]){

              new MyOuter().new MyInner2().print();

       }

   

}

程序的运行结果:

局部变量x的值:5

内部类成员变量x的值:10

外部类成员变量x的值:20

http://blog.csdn.net/javaeeteacher 李绪成

2 成员方法中定义的内部类

2.1内部类的编写

成员方法中的内部类的编写与作为成员变量的内部类的编写方法基本相同,下面的代码展示了用法:

public class MyOuter2 {

       public void test() {

              class MyInner{

                     public void print(){

                            System.out.println(x);

                     }

              }       

       }

}

方法内部的类具有如下特点:

l         方法内部定义的类就像方法的局部变量,所以在类外或者类的其他方法中不能访问这个内部类。

l         没有访问控制符,因为该类只能在定义该类的方法中并且在类的定义之后使用;

l         不能访问方法的局部变量,除非局部变量是final类型的;

l         能够访问外部类的各种成员变量,如果内部类所在的方法是静态方法,则这个内部类只能访问外部类的静态成员;

l         可以使用finalabstract修饰。

2.2方法中内部类的访问

方法中的内部类只能在定义该内部类的方法中访问,并且是方法中内部类的定义之后访问。下面的代码展示了用法:

       public void main2(String[] args) {

              class MyInner{

                     public void print(){

                            System.out.println(x);

                     }

              }

              MyInner in = new MyInner();

              in.print();

       }

http://blog.csdn.net/javaeeteacher 李绪成

3 匿名内部类

顾名思义,匿名内部类没有类名,而我们创建对象是根据类名创建的,没有类名如何创建对象的?可以使用类的定义直接创建实例,例如下面的代码:

Parent p = new Parent() {

              public void print() {

                     System.out.println("匿名内部类中的输出方法");

              }

       };

new后面的信息表示创建了一个继承了Parent类的子类的实例。

匿名内部类有两种形式:

l         通过继承父类而形式的匿名内部类;

l         通过实现接口而形式的匿名内部类。

下面分别介绍。

3.1通过继承父类而形成的匿名内部类

看下面的代码:

class Parent {

       public void print() {

              System.out.println("父类的输出方法");

       }

}

public class MyOuter3 {

       Parent p = new Parent() {

              public void print() {

                     System.out.println("匿名内部类中的输出方法");

              }

       };

}

MyOut3中声明了类型为Parent的成员变量,通过new Parent来实例化对象,但是这里的实例化代码与以前见到过的实例化代码不同,以前的代码这样写:

Parent p = new Parent();

而这里是:

Parent p = new Parent(){

这里的大括号意味着新创建了一个类,这个类是Parent的子类,在子类中可以覆盖父类中的方法或者实现父类中定义的抽象方法,上面的代码重写了父类中的print方法。

    注意在倒数第二行的“};”,这个分号不能省略。

上面的代码中定义的成员变量p指向了匿名内部类的实例,也可以在成员方法中定义局部变量指向匿名内部类的实例。

对于匿名内部类的实例的方法的调用是通过执行该实例的父类引用,利用了Java语言的多态性。下面的代码展示了如何调用(在MyOuter3中增加的代码):

       public static void main(String[] args){

              new MyOuter3().p.print();

       }

输出结果是:

子类中的输出方法

注意:因为匿名内部类中的方法都是通过父类引用访问的,所以不能在匿名内部类中定义父类中没有声明的方法,这样的方法不能被访问到。如果是为了匿名内部类中的方法之间共享代码,可以编写供内部方法调用的在父类中没有定义的方法。

3.2通过实现接口而形成的匿名内部类

匿名内部类也可以通过实现接口来创建,与继承父类没有本质区别。下面的代码展示了使用接口创建匿名内部类:

interface Fly{

       public void takeof(); //起飞

       public void landing(); //降落

}

public class MyOuter3 {

       Fly bird = new Fly(){

              public void takeof(){

                     System.out.println("小鸟起飞了");

              }

              public void landing(){

                     System.out.println("小鸟降落了");

              }

       };

}

代码中new Fly(){…}意味着创建了一个实现了Fly接口的类的对象,这个类就是匿名内部类。这个匿名内部类必须实现接口中定义的所有方法,这与普通类实现接口的要求是相同的。在这个类中也不能定义其他的业务方法,这些方法是通过接口的引用访问的,因为接口中没有声明该方法,所以该方法将不能被访问。

注意:new Fly(){…}实例化的对象是实现了Fly接口的类的对象,而不是实例化Fly接口,接口是不能被实例化的。

这些匿名内部类被实例化以后通过父类引用或者接口引用访问,通常都会有一个引用指向这个新创建的匿名内部类的实例。有个特殊的应用不需要创建引用指向匿名内部类的实例,而是传递给形参,看下面的代码(在MyOuter3中添加如下代码):

       public static void main(String[] args){

        // 直接把匿名内部类的实例作为实参使用

              new MyOuter3().printFly(new Fly(){

                     public void takeof(){

                            System.out.println("飞机起飞");

                     }

                     public void landing(){

                            System.out.println("飞机降落");

                     }

              });

       }

       public void printFly(Fly fly){ // 参数需要是实现Fly接口的类的对象

              fly.takeof();

              fly.landing();

       }

注意:我们自己在开发程序的时候尽量不要使用内部类,内部类不利于代码重用,如果非常确定这个类只会使用一次,可以使用匿名内部类。

http://blog.csdn.net/javaeeteacher 李绪成

4 静态内部类

4.1静态内部类的定义

静态内部类与作为成员的内部类基本相同,只是这个内部类是静态的,使用static,类似于静态成员变量和静态成员方法。下面的代码展示了如何定义静态内部类:

public class MyOuter4 {

       static class MyInner{

      

       }

}

与静态方法一样,在静态内部类中只能访问外部类的静态方法,看下面的代码:

public class MyOuter4 {

       int x = 10;

       static int y = 20;

       static class MyInner{

              public void print(){

                     System.out.println(x);  // 错误

                     System.out.println(y);  // 正确

              }

       }

}

System.out.println(x);是错误的,因为它试图访问非静态成员变量xSystem.out.println(y)是正确的。

4.2静态内部类的使用

在实例化作为实例成员变量的内部类的时候,要先创建外部类的对象,然后通过对象的new操作符创建内部类的实例。而静态内部类就像静态方法一样,可以通过类名直接访问而不用创建实例。下面的代码展示了在外部类的内容和外部类的外部如何访问静态内部类(第一个方法是在MyOuter4中添加的代码,第二个方法是测试类中的代码):

       public void outprint(){

              MyInner inner = new MyInner();

              inner.print();

       }

       public static void main(String args[]){

              MyOuter4.MyInner inner = new MyOuter4.MyInner();

              inner.print();

       }

http://blog.csdn.net/javaeeteacher 李绪成

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值