一、什么样的类属于内部类?
毫无疑问,居然是内部类,定义在类里面的类就是内部类。
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
从输出的情况可以看出,内部类并没有被覆盖。也就是说,两个内部类并没有啥关系,是相互独立的。
参考书籍:编程思想
来源与公众号:苦逼的码农 原文连接