1、内部类定义
- 定义:内部类(inner class)其实听名字好理解:就是定义在一个类中的类
- 看功能:(具体看后面的举栗)
- 内部类可以对同一个包中的其他类隐藏
- 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据
2、来看看吧,热身运动
(1)来个例子
我相信大家都用过,但是你可能不知道它底层是这样通过内部类来实现的。先康康如下代码吧!
既然能通过ArrayList
的实例去调用一个Iterator的实例,说明它内部肯定有实现,点进去看一下。
- 点到了这里:这个AbstractList是LinkedList和ArrayList的父类
- 点这个return的返回语句:listIterator又跳到了这里【在ArrayList里面定义了一个类叫ListItr的类,它继承了Itr类,继续点这个Itr类】
- 熟悉了吧
这个listIterator和Iterator差不多的道理
(2)道理来了
java的内部类和C++的内部类很类似,具体的情况是,内部类的对象会有一个隐藏的引用指向实例化这个对象的外部类对象。通过这个指针,它可以访问外部对象的全部状态。上面的Iterator就是一个很好的例子。看代码吧,咱们编程人员看代码好理解。
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Voice v1 = new Voice();
Voice.Employee ve = v1.new Employee();
}
}
class Voice {
private Integer age;
public String Name;
public class Employee implements Cloneable {
private int a;
public String b;
}
}
这个ve队形其实有个指针隐藏的指向了v1,懂了吧!!
3、一点一点的来看吧
(1)实例化内部类
这个很简单了吧,相信各位
Voice v1 = new Voice();
Voice.Employee ve = v1.new Employee();
(2)用内部类来访问外部对象的数据
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Voice v1 = new Voice();
Voice.Employee ve = v1.new Employee();
ve.at();
}
}
class Voice {
private Integer age;
private boolean beep = true;
public class Employee implements Cloneable {
public void at() {
System.out.println(beep);
}
}
}
- 我的目的是用对象去访问at方法,这个方法是去调用了外部的类的属性的,而且是private定义的,并且在内部类中去访问beep变量也没有报错,看输出结果。
- 咱们来看原因【内部类的对象ve总会有一个隐藏的引用指向创建它的外部类的对象也就是v1】
(3)实现访问外部数据的机制
其实很好理解,原因就是在我们的内部类中每次都实例化一个外部类的对象,就相当于如下的代码
class Voice {
private Integer age;
private boolean beep = true;
public class Employee implements Cloneable {
private Voice outer;
public Employee(Voice voice) {
this.outer = voice;
}
public void at() {
System.out.println(beep);
}
}
}
只是这个构造方法每次都是有编译器自动的添加这个对象上去的,但是对我们是不可见的。
(4)定义内部类的要求
- 内部类声明的所有静态变量字段都必须是final,并初始化为一个编译器常量。
- 内部类定义不能有static方法。
4、内部类的分类
(1)局部内部类
- 首先得为什么要有局部内部类吧
其实就是假设一个类我们只用一次,但是没了这个类又不行的时候,就可以在一个方法中定义一个内部类的情况。
- 局部类的优势
- 它的优势是对外部世界隐藏了它的一切,只在这里使用了一次。
- 第二是它可以访问方法的参数,就是比如我们的hello方法有参数的话,那我可以直接使用它,就想方法内的其他字段一样。【我感觉这个听起来有点扯淡】
(2)匿名内部类
就是不用给类定义名字了,但是我想要它的对象来使用的时候。
当然这个也就是格式了,而且也可以是类,可以是接口(那么你的那个类就要实现这个接口),都可以这样。
- 它不能有构造器
- 具体的以后用到了再说。
(3)静态内部类
很多时候,我们仅仅是为了能了在内部声明一个内部类,但是不要有之前讲的那隐藏的引用哦,那我们就可以定义静态内部类了
就可直接把类声明为static类,不细讲了,具体规则有如下
- 只要内部类不需要访问外部类的对象时,就应该把内部类声明为一个静态内部类,但是有很多时候会误认为嵌套类和内部类的情况
- 与常规内部类不同,静态内部类可以有静态方法和字段
- 在接口中声明的内部类自动是static和public的