Java☞内部类

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

成员内部类

package cn.ihep.inerClass;

public class Family {

    private int number;
    static double money = 20000.0;

    public Family(int num) {
        this.number = num;
    }

    // 成员内部类
    class Mother {
        public void showMe() {
            System.out.println("我是妈妈!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }

    // 成员内部类
    class Father {
        public void showMe() {
            System.out.println("我是爸爸!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }
}

成员内部类Mother和Father在外部类Family内部,就像是Family的成员变量一样,成员内部类可以访问外部类的所有成员变量或者方法。(包括private成员)
虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:

package cn.ihep.inerClass;

public class Family {

    private int number;
    static double money = 20000.0;

    public Family(int num) {
        this.number = num;
    }
    
    public void checkMother(){
        //先创建成员内部类的对象才能访问其内部方法
        Mother m = new Mother();
        m.showMe();
        Father f = new Father();
        f.showMe();
    }

    // 成员内部类
    class Mother {
        public void showMe() {
            System.out.println("我是妈妈!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }

    // 成员内部类
    class Father {
        public void showMe() {
            System.out.println("我是爸爸!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }
}

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:

package cn.ihep.inerClass;

public class Family {

    private int number;
    static double money = 20000.0;

    public Family(int num) {
        this.number = num;
    }
    
    public void checkMother(){
        //先创建成员内部类的对象才能访问其内部方法
        Mother m = new Mother();
        m.showMe();
        Father f = new Father();
        f.showMe();
    }

    // 成员内部类
    class Mother {
        public void showMe() {
            System.out.println("我是妈妈!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }

    // 成员内部类
    class Father {
        public void showMe() {
            System.out.println("我是爸爸!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }
    
    public static void main(String[] args) {
        //想创建成员内部类的对象,要通过外部类来实现,如下:
        Family fam = new Family(4);
        Family.Mother m = fam.new Mother();
        m.showMe();
        
        Family.Father f = fam.new Father();
        f.showMe();
    }
}

局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或该作用域内。

package cn.ihep.inerClass;

public class PartFamily {

    private int number;
    static double money = 20000.0;

    public PartFamily(int num) {
        this.number = num;
    }

    public Mother tellMother(){
        class Daughter extends Mother{
            public void whoami(){
                System.out.println("我是女儿。");
            }
        }
        return new Daughter();
    }
    
    class Mother {
        public void showMe() {
            System.out.println("我是妈妈!");
            System.out.println("家庭成员有:" + number + "位。");
            System.out.println("家庭资产有:" + money);
        }
    }   
}

注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

匿名内部类

匿名内部类应该是平时我们编写代码时用得最多的,

package cn.ihep.inerClass;

public abstract class Bird {

    private String name;

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

    public String getName() {
        return this.name;
    }

    public abstract int fly();
}
---------------------------
package cn.ihep.inerClass;

public class TestBird {

    public void test(Bird b) {
        System.out.println(b.getName() + "能飞老远了!!!" + b.fly() + "km");
    }

    public static void main(String[] args) {
        TestBird t = new TestBird();
        t.test(new Bird() {
            public int fly() {
                return 100;
            }

            public String getName() {
                return "乌鸦 ";
            }
        });
    }
}
----------------------------
输出:
乌鸦 能飞老远了!!!100km

在TestBird类中,test()方法接受一个Bird类型的参数,同时我们知道一个抽象类是没有办法直接new的,我们必须要先有实现类才能new出来它的实现类实例。所以在main方法中直接使用匿名内部类来创建一个Bird实例。
我突然觉得,匿名内部类的使用好像是:你想实现一个接口或者继承某个类,而这个实现类呢又不常用,或者说可能就用这么一次,你完全没有必要去新建这个类,只需在用的地方用匿名内部类的方式把它给new出来即可,记得把该重写或者实现的方法给实现。另外这种方式维护起来也方便!
使用匿名内部类注意一下几点:

  1. 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
  2. 匿名内部类中是不能定义构造函数的。
  3. 匿名内部类中不能存在任何的静态成员变量和静态方法。
  4. 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
  5. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
  6. 我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为final。也就是说:当所在的方法的形参需要被内部类里面使用时,该形参必须为final。(JDK1.8之后就不需要我们手动添加final了,如果是JDK1.8之前,不加final编译都通不过。)

静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法。

package cn.ihep.inerClass;

public class StaticFamily {

    private int number;
    static double money = 2000.0;

    public StaticFamily(int num) {
        this.number = num;
    }

    static class Mother {
        public void showMe() {
            System.out.println("我是妈妈。");
            System.out.println("家庭收入:" + money);
        }
    }
    
    public static void main(String[] args) {
        StaticFamily.Mother m = new StaticFamily.Mother();
        m.showMe();
    }
}

这里要注意如何创建静态内部类对象的,外部类.内部类 xxx = new 外部类.内部类();

给出一道内部类的面试题

public class Test{
    public static void main(String[] args){
           // 初始化Bean1
           (1)
           bean1.I++;
           // 初始化Bean2
           (2)
           bean2.J++;
           //初始化Bean3
           (3)
           bean3.k++;
    }
    class Bean1{
           public int I = 0;
    }
 
    static class Bean2{
           public int J = 0;
    }
}
 
class Bean{
    class Bean3{
           public int k = 0;
    }
}

(1)(2)(3)处应该怎么填?

(1)
Test t = new Test();
t.Bean1 bean1  = t.new Bean1();

(2)
Test.Bean2 bean2 = new Test.Bean2();

(3)
Bean b = new Bean();
Bean.Bean3 bean3 = b.new Bean3();

你可能感兴趣的:(Java☞内部类)