浅析Java中的内部类

120 阅读3分钟

内部类

现实任务中,如果一个事物内部包含另一个事物,那么在面向对象的程序设计处理过程中表示为一个类内部包含另一个类,此时被包含的那个类就被称为内部类


分类

1. 成员内部类

格式:

// 外部类
修饰符 class 类名称{
    // 内部类
    修饰符 class 类名称{
        ...
    }
   ...
}

内部类访问外部类随意;外部用内部,需要内部类对象。那么外部类如何使用内部类对象呢?

  • 间接方式:在外部类的方法中使用内部类,然后main方法中只调用外部类方法

  • 直接方式:使用代码格式为:

    外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
    

局部内部类如果希望访问所在方法的局部变量,那么这个变量必须是有效final的

class Body {
    private String name = "body";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void methodBody(){
        System.out.println("outer class...");
        // 间接调用内部类
        new Heart().beat();
    }

    //成员内部类
    public class Heart{
        String name = "HEART";

        public void beat(){
            System.out.println("beat...");

        }
    }
}

public class InterClassTest {
    public static void main(String[] args) {
        Body body = new Body();
        body.methodBody(); // outer class...  beat...
		
		// 直接调用内部类
        Body.Heart heart = new Body().new Heart();
        heart.beat(); // beat...
    }
}

2. 局部内部类(包含匿名内部类)

如果一个类是定义在一个方法内部,那么它就是一个局部内部类;只有当前所属方法才能使用它,出了这个方法的范围就不能再用。格式:

 修饰符 class 外部类名称{
     修饰符 返回值类型 外部类名称(参数列表){
         class 局部内部类名称{
             ...
         }
         ...
     }
     ...
 }

代码示例:

class Person{

    public void show(){
        class Teacher{
            public void show(){
                System.out.println("teacher...");
            }
        }
        Teacher t = new Teacher();
        t.show();
    }
}

public class LocalInterClass {
    public static void main(String[] args) {
        Person p = new Person();
        p.show();  // teacher...
    }
}

变量重名问题

通过关键字指定访问的是哪一个变量,如果是当前方法的变量则直接访问;如果是当前类成员变量,需使用this关键字指定访问;如果是外部类的成员变量,需使用外部类名称.this.成员变量名称访问。

class Body {
    private String name = "body";

    //成员内部类
    public class Heart{
        String name = "HEART";
        
        public void show(){
            String name = "heart";
            // 解决重名变量问题
            System.out.println(name);
            System.out.println(this.name);
            System.out.println(Body.this.name);
        }
    }
}

public class InterClassTest {
    public static void main(String[] args) {
        Body.Heart heart = new Body().new Heart();
        heart.show();
        /*
         * heart
         * HEART
         * body
         */
    }
}

访问控制修饰符问题

包含有外部类、内部类的访问控制修饰符的使用:

  • 外部类public、(default)
  • 成员内部类::public / protected / (default) / private
  • 局部内部类:什么都不能写

匿名内部类

如果接口的实现类(或父类的子类)只需要使用唯一的一次,则可以省略该类的定义,而改为使用匿名内部类。格式:

接口名称 对象名 = new 接口名称(){
	//覆盖称谢所有抽象方法
};

注意事项:对于上面创建匿名内部类的语句来说:

  • new代表创建对象的动作
  • 接口名称是匿名内部类需要实现那个接口
  • {...}是匿名内部类的内容

匿名内部类和匿名对象:

  • 匿名内部类在创建对象的时候,只能使用唯一的一次如果希望希望多次创建多次,而且类的内容完全一样,则只能使用接口的单独实现类
  • 匿名内部类是省略了实现类/子类名称,但匿名对象是省略了对象名称