浅谈java内部类

一、什么样的类属于内部类?

毫无疑问,居然是内部类,定义在类里面的类就是内部类。

public class Room {  
    class Student{//内部类   
    }  
}

内部类可以分为静态内部类(static修饰的类)和普通内部类。下面先讨论普通内部类:

(注意,以下所说的内部类都是指普通内部类)

1.内部类与外部类的关系: 对于普通内部类,实际上该类就类似于外部类的一个特殊成员,该内部类的创建必须依附于外部类,也就是说,必须先有外部类对象,才能创建内部类对象。这是因为内部类对象会隐式地连接到创建它的外部类对象上。并且内部类可以访问外部类的所有元素。创建时通过 .new来创建

public class Room {  
    private String book = "数据结构";  
    class Student{//内部类  
        public String getBook(){  
            return book;  
        }  
    }  
    public static void main(String[] args) {  
        Room r = new Room();  
        Student s = r.new Student();//不能有 Student s = new Student()来创建  
        System.out.println(s.getBook());  
    }  
} 

注:如果要在内部类通过this关键字来引用外部类对象,则需要在这样引用 Room.this 。如果只是用this的话,引用的是内部类对象。

2.在方法和作用域内的内部类

(1).定义在方法内的内部类,我们称之为局部内部类:

public void get(){//只贴方法内的代码,其他代码省略  
    class Book{ //定义在方法内的内部类  
        String name = book;//book变量是外部类的成员属性  
    }  
}

显然,Book内只是方法get()的一部分,而不是外部类的一部分,所以,get()方法之外都不能访问Book。

(2).下面展示任何在任意作用域内嵌入一个内部类

public void get2(boolean b){  
    if(b){//在if语句作用域内定义内部类  
        class Book2{  
            String name = book;  
        }  
    }  
} 

(3).内部类不能定义静态变量和静态方法

原因:类在初始化的过程中,是先初始化静态变量等的。也就是说,在编译是只要是定义为静态变量了,系统就会自动分配内存给它,但是内部类是依附与外部类的存在而存在的,也就是说只有外部类存在了,内部类才能存在,这就和编译时为静态变量分配内存产生了冲突。

3.匿名内部类

看下面一个程序

public class Animal {  
    public void run(){  
        System.out.println("我是一只不知名的动物");  
    }  
    public Animal getAnimal(){  
        return new Animal(){//返回匿名内部类  
            public void run(){  
                System.out.println("我是一只小猫");  
            }  
        };  
    }  
    public static void main(String[] args) {  
        Animal a = new Animal();  
        Animal a1 = a.getAnimal();  
        a1.run();  
    }  
}

打印结果:我是一只小猫

在getAnimal()方法里,将返回值的生成与表示这个返回值的类定义结合在一起。另外,这个类是匿名的,没有名字。对于这种用法,看起来似乎你正要创建一个Animal的对象,实际上,创建的却是一个继承了Animal类的匿名对象,run()方法 是对父类方法的重写。

对于这种匿名内部类,使用的是默认构造器来生成Animal的,如果你的基类(也就是父类)需要一个有参数的构造器,该怎么办: 只需要把参数传递给基类的构造器即可。

public Animal getAnimal2(String name){  
    return new Animal(name){//直接把参数给它就行  
        public void run(){  
            System.out.println("我是一只" + name);  
        }  
    };  
}

以下来讨论静态内部类:

对于静态内部类,它与普通内部类不同。普通的内部类对象会隐式地保存了一个引用,指向创建它的外部类对象。然而,对于静态类来说,就不是这样了:

(1).要创建静态内部类,它并不需要其外部类的对象

public class Book {   
    static class Math{  }  
    public static void main(String[] args) {  
        Math m = new Math();//静态内部类的创建  
    }  
}

(2).静态内部类不能访问非静态的外部类对象

public class Book {  
    int B_price = 10;  
    static String B_name = "好书";  
      
    static class Math{  
        //int M_price = B_price;//不能访问  
        String M_name = B_name;  
    }  
}

对于为何不能访问非静态变量我是这样理解的:非静态量是属于类对象成员,而不是类成员,它的存在是依附于对象而不是类。静态内部类访问这个外部类成员的时候,这个成员还不存在,因为外部对象还没有被创建。故不能访问非静态成员。(当然,也可以从类加载的顺序等分析)。

(3).静态内部类还可以作为接口的一部分。

正常情况下,是不能在接口内部放置任何代码的,但是静态内部类可以作为接口的一部分。你放到接口中的任何类都自动地是public和static的。因为类是static的,只是将静态内部类置于接口的命名空间内,这并不会违反接口的规则:

public interface AA {  
    void get();  
    class BB implements AA{  
        @Override  
        public void get() {  
            System.out.println("哈哈");     
        }     
    }  
} 

二、为啥需要内部类?

1.对于抽象类,我们都知道只能被单继承,如果一个类想要继承多个抽象类,那只能使用内部类才能实现多重继承(即定义几个内部类,每个内部类分担继承一个)。

2.内部类的使用,对一个类来说,提供了更好的封装。例如要生产一辆车,我们可以假设老板是外部类,负责组装车部件的团队是内部类。那么你想要修改车里面的部件时,不仅仅是通过老板就可以直接做出修改了,还得通过负责装车部件的团队。也就是说,外部类的有些属性成员,只要通过内部类才能修改,这样子设计,会更具合理性。

3.内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外部类对象的信息相互独立。

4.在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。

三、内部类可以被覆盖吗?

看下面一个例子

打印结果:
Eat
Eat.Apple

从输出的情况可以看出,内部类并没有被覆盖。也就是说,两个内部类并没有啥关系,是相互独立的。

参考书籍:编程思想

来源与公众号:苦逼的码农 原文连接

猜你喜欢

转载自juejin.im/post/5afac2d06fb9a07aab2a028f
今日推荐