您的位置:首页 > 编程语言 > Java开发

深入理解java嵌套类和内部类、匿名类

2016-04-27 10:53 856 查看

一、什么是嵌套类及内部类

  可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,最重要的是非静态嵌套类,也即是被称作为内部类(inner)。嵌套类从JDK1.1开始引入。其中inner类又可分为三种:
  其一、在一个类(外部类)中直接定义的内部类;
  其二、在一个方法(外部类的方法)中定义的内部类;
  其三、匿名内部类。

  下面,我将说明这几种嵌套类的使用及注意事项。

二、静态嵌套类

  如下所示代码为定义一个静态嵌套类,

public class StaticTest {

private static String name = "javaJohn"; 

  private String id = "X001";

  static class Person{

    private String address = "swjtu,chenDu,China";

    public String mail = "josserchai@yahoo.com";//内部类公有成员

    public void display(){

      //System.out.println(id);//不能直接访问外部类的非静态成员

      System.out.println(name);//只能直接访问外部类的静态成员

      System.out.println("Inner "+address);//访问本内部类成员。

    }

  }

  public void printInfo(){

    Person person = new Person();

    person.display();

    //System.out.println(mail);//不可访问

    //System.out.println(address);//不可访问

    System.out.println(person.address);//可以访问内部类的私有成员

    System.out.println(person.mail);//可以访问内部类的公有成员

  }

  public static void main(String[] args) {

  StaticTest staticTest = new StaticTest();

  staticTest.printInfo();

}

}

  在静态嵌套类内部,不能访问外部类的非静态成员,这是由Java语法中"静态方法不能直接访问非静态成员"所限定。若想访问外部类的变量,必须通过其它方法解决,由于这个原因,静态嵌套类使用很少。注意,外部类访问内部类的的成员有些特别,不能直接访问,但可以通过内部类来访问,这是因为静态嵌套内的所有成员和方法默认为静态的了。同时注意,内部静态类Person只在类StaticTest 范围内可见,若在其它类中引用或初始化,均是错误的。

三、在外部类中定义内部类

  如下所示代码为在外部类中定义两个内部类及它们的调用关系:
  

public class Outer {

  int outer_x = 100;

    class Inner{

      public int y = 10;

      private int z = 9;

      int m = 5;

      public void display(){

        System.out.println("display outer_x:"+ outer_x);

      }

      private void display2(){

        System.out.println("display outer_x:"+ outer_x);

      }

    }

    void test(){

      Inner inner = new Inner();

      inner.display();

      inner.display2();

      //System.out.println("Inner y:" + y);//不能访问内部内变量

      System.out.println("Inner y:" + inner.y);//可以访问

      System.out.println("Inner z:" + inner.z);//可以访问

      System.out.println("Inner m:" + inner.m);//可以访问

      InnerTwo innerTwo = new InnerTwo();

      innerTwo.show();

    }

    class InnerTwo{

      Inner innerx = new Inner();

      public void show(){

        //System.out.println(y);//不可访问Innter的y成员

        //System.out.println(Inner.y);//不可直接访问Inner的任何成员和方法

        innerx.display();//可以访问

        innerx.display2();//可以访问

        System.out.println(innerx.y);//可以访问

        System.out.println(innerx.z);//可以访问

        System.out.println(innerx.m);//可以访问

      }

    }

    public static void main(String args[]){

      Outer outer = new Outer();

      outer.test();

    }

  }

  以上代码需要说明有,对于内部类,通常在定义类的class关键字前不加public 或 private等限制符,若加了没有任何影响,同时好像这些限定符对内部类的变量和方法也没有影响(?)。另外,就是要注意,内部类Inner及InnterTwo只在类Outer的作用域内是可知的,如果类Outer外的任何代码尝试初始化类Inner或使用它,编译就不会通过。同时,内部类的变量成员只在内部内内部可见,若外部类或同层次的内部类需要访问,需采用示例程序中的方法,不可直接访问内部类的变量。

四、在外部类中定义内部类

匿名类就是没有名字的内部类,是内部类的一种特殊情况。????????? 这句话对吗???前端时间在写.net项目中,一直错将.cs里的两个class当作内部类,原来是一个文件里的两个类而已,这让我想起了Java中的内部类,比较内部类,那么还有两个类,那就是匿名类和匿名内部类。今天我想就Java中的这三种类进行个比较。我们知道在Java语言规范中可以做很多事,例如一个类或一个接口中可以声明一个类或接口,在一个方法中可以声明一个类,类与接口声明可以嵌套任意深度等。 匿名类: 1、new <类或接口><类的主体>,匿名类的声明是在编译时进行的,实例化是在运行时进行的,所以在for循环中一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。 2、如果要执行的对象需要一个对象,但却不值得创建全新的对象(可能是因为该对象只在一个方法内部使用),在这个时候使用匿名类就会非常合适,所以说,匿名类一般会在swing程序中快速创建事件处理程序。Java代码


firstButton.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

getTxtValue().setText("第一个按钮触发的事件!");

}

});

3、从技术上说,匿名类可以被看作非静态的内部类,所以他们具有方法内部声明的非静态内部类相同的权限和限制。 内部类:内部类顾名思义就是在一个类的内部还有一个类Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo {

public static void main(String[] args) {

new Outer().fun();

}

}

class Outer {

private String name = "Hello 内部类";

class Inner {

public void print() {

System.out.println("name = " + name);

}

};

public void fun() {

new Inner().print();

}

}

内部类生成的.class文件名为:Outer$Inner.class,从上面的结构发现内部类的的缺点是“结构非常的混乱”。Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo02 {

public static void main(String[] args) {

new Outer02().fun();

}

}

class Outer02 {

private String name = "Hello 内部类";

public void fun() {

new Inner02(this).print();

}

public String getName() {

return this.name;

}

};

class Inner02 {

private Outer02 out;

public Inner02(Outer02 out) {

this.out = out;

}

public void print() {

System.out.println("name = " + this.out.getName());

}

};

从上可以看出内部类的优点是“可以方便的访问外部类中的私有成员”;如果要在外部直接使用内部类的实例化对象: 外部类.内部类 内部类对象 = 外部类实例.new 内部类实例();Java代码


3ff8
package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo03 {

public static void main(String[] args) {

Outer03 out = new Outer03();//外部类实例

Outer03.Inner inner = out.new Inner();//实例化内部类对象

inner.print();

}

}

class Outer03{

private String name = "Hello 内部类";

class Inner {

public void print() {

System.out.println("name = " + name);

}

}

}

一个内部类如果使用static关键字声明的话,则此内部类就将成为外部类,可以直接通过外部类.内部类的形式访问Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo04 {

public static void main(String[] args) {

Outer04.Inner inner = new Outer04.Inner();// 实例化内部类对象

inner.print();

}

}

class Outer04 {

private static String name = "Hello 内部类";

static class Inner {

public void print() {

System.out.println("name = " + name);

}

}

}

内部类可以在任意的地方使用,例如方法中声明Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo05 {

public static void main(String[] args) {

new Outer05().fun();

}

}

class Outer05 {

private static String name = "Hello 内部类";

public void fun() {

class Inner {

public void print() {

System.out.println("name = " + name);

}

}

new Inner().print();

}

}

在方法中定义的内部类,可以直接访问外部类中的各个成员,但是如果要访问方法中的参数,则需要在参数上加上final关键字声明;Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class InnerClassDemo06 {

public static void main(String[] args) {

new Outer06().fun(20);

}

}

class Outer06 {

private static String name = "Hello 内部类";

public void fun(final int temp) {

class Inner {

public void print() {

System.out.println("temp = " + temp);

System.out.println("name = " + name);

}

}

new Inner().print();

}

}

匿名类与内部的联系与区别:按所在位置可以分为两大类: 1、在类的方法中 特点: a、可以访问宿主类的所有元素 ; b、保存宿主类对象的引用,创建对象时必须有宿主类对象; c、 不能有静态数据;继续划分: A、本地内部类; B、匿名内部类 两者的区别在于本地内部类有构造方法,而匿名内部类只能实例初始化; 2、在类或接口作用域中; 继续划分: A、普通内部类 B、静态内部类 匿名内部类:匿名内部类是在抽象类和接口的基础之上发展起来的。Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class NoNameClass01 {

public static void main(String[] args) {

new X().fun2();

}

}

interface A {

public void fun();

}

class B implements A {

public void fun() {

System.out.println("Hello 准备匿名内部类");

}

}

class X {

public void fun1(A a) {

a.fun();

}

public void fun2() {

this.fun1(new B());

}

}

通过上面的Demo,如果现在假设B类只使用一次,那么还有必要将其定义成一个单独的类么? 呵呵,此时就可以使用匿名内部类:Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class NoNameClass02 {

public static void main(String[] args) {

new XX().fun2();

}

}

interface AA {

public void fun();

}

class XX {

public void fun1(AA a) {

a.fun();

}

public void fun2() {

this.fun1(new AA() {

public void fun() {

System.out.println("Hello 准备匿名内部类");

}

});

}

}

其实在真正的项目开发中匿名内部类使用的非常之少,一般在Java的图形界面和现在的Android中使用的比较多点。 最后给一个内部类实现的简单链表:Java代码


package com.iflytek.innerclass;

/**

* @author xudongwang 2012-1-11

*

* Email:xdwangiflytek@gmail.com

*/

public class LinkDemo {

public static void main(String args[]) {

Link link = new Link();

link.add("A");

link.add("B");

link.add("C");

link.add("D");

link.add("E");

link.print();

}

};

class Link {

class Node {

private String name;

private Node next; // 单向链表,每个节点指向下一个节点

public Node(String name) {

this.name = name; // 通过构造方法为name属性赋值

}

public void addNode(Node newNode) { // 增加节点

if (this.next == null) {

this.next = newNode; // 保存节点

} else {

this.next.addNode(newNode); // 继续向下查找

}

}

public void printNode() { // 输出节点

System.out.println(this.name);

if (this.next != null) { // 此节点之后还存在其他的节点

this.next.printNode();

}

}

};

private Node root; // 链表的头

public void add(String name) { // 增加节点

Node newNode = new Node(name); // 定义一个新的节点

/*

* 如果是第一个节点,则肯定是根节点, 如果是第二个节点,则肯定放在根节点next中 如果是第三个节点,则肯定放在第二个节点的next中

*/

if (this.root == null) {

this.root = newNode; // 将第一个节点设置成根节点

} else {

// 肯定要放在最后一个节点之后

// 通过节点.next来不断的判断

this.root.addNode(newNode);

}

}

public void print() {

if (this.root != null) { // 如果根节点为空了,则没有任何内容

this.root.printNode();

}

}

};

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: