3.7 内部类
3.7.1 内部类概念
将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。为什么要定义内部类呢?类是用于描述事物的,而事物中如果还有具体的事物,而且这个内部的事物访问着所属事物中的内容。这时这个内部的事物,也需要用到类来描述。这个类就是内部类。
3.7.2 内部类访问特点
(1)内部类可以直接访问外部类中的成员,包括私有成员。
为什么内部类可以直接访问外部类中的成员呢?因为内部类都持有一个外部类的引用:“外部类名.this”。
(2)外部类要访问内部类中的成员必须要建立内部类的对象。
public class Outer {
int num = 4;
//内部类,可看成Outer的一个成员
class Inner
{
int num = 5;//Inner的成员变量
void method()
{
int num = 6;//Inner的局部变量
//内部类可以直接访问外部类中的成员。
//调用的是局部变量:6
System.out.println("method run1 .."+num);
//使用this,调用的是Inner类的成员变量:5
System.out.println("method run2 .."+this.num);
//使用外部类名.this,调用的是Outer类的成员变量:4
System.out.println("method run3 .."+Outer.this.num);
}
}
//可以将Outer类中看成有3个成员,一是成员变量num,二是类Inner,三是成员方法show()。
//外部类要访问内部类Inner中的成员必须创建内部类的对象。
public void show()
{
Inner in = new Inner();
in.method();
}
}
public class InnerClassDemo {
public static void main(String[] args) {
// TODO 自动生成的方法存根
new Outer().show();
}
}
运行结果如下:
内部类在文件中的存在形式:
3.7.3 内部类修饰符
当内部类定义在外部类的成员位置上时,可以使用成员的修饰符来进行内部类的修饰,
(1)权限修饰符。
内部类权限修饰符是默认或者公有public:可以直接这样访问内部类。
外部类名.内部类名 变量名 = new 外部类对象.new 内部类对象;
例如:Outer.Inter in=new Outer().new Inter();
私有:是不可以直接在外部访问。
public class Outer {
int num=10;
class Inter{
void method(){
System.out.println("method run1 .."+num);
}
}
public void show(){
System.out.println("method run2 .."+num);
}
}
public class InnerClassDemo2 {
public static void main(String[] args) {
//使用匿名对象的方式调用方法
new Outer().show();//method run2 ..10
//直接创建名对象再调用方法
Outer outer =new Outer();
outer.show();//method run2 ..10
//直接在其他类中,访问一个类的内部类。
//可以这么理解:内部类是外部类的一个成员,外部类要调用自己的成员自然要
//创建对象,而内部类本身又是一个类,要调用自己的成员自然要创建自己的对象
Outer.Inter in=new Outer().new Inter();
in.method();//method run1 ..10
}
}
运行结果如下:
(2)static修饰符。
①内部类被静态修饰,出现访问局限性,只能访问外部类中的静态成员。
public class Outer {
//int num=10;被静态修饰的内部类访问不到该普通成员变量
static int num=10;
//内部类被静态修饰,只能访问外部类中的静态成员
//静态内部类
static class Inter{
void method(){
System.out.println("method run1 .."+num);
}
}
public void show(){
System.out.println("method run2 .."+num);
}
}
②内部类被静态后,会随着外部类的加载而加载。而内部类若是没有被静态修饰,没有使用到内部类时,内部类不会进入内存。
a.访问静态内部类中的非静态成员:直接创建内部类对象。
外部类名.内部类名 变量名 = new 外部类名.内部类名();
例如:
Outer.Inter in = new Outer.Inter();
in.method();
b.访问静态内部类中的静态成员:不需要对象。
外部类名.内部类名.内部类的静态成员
例如:Outer.Inter.fun();
③如果内部类中定义了静态成员,该内部类必须被静态修饰。
因为若内部类不是静态的,那么访问内部类中的成员时需要创建内部类对象才可以。而内部类中定义了静态成员,该静态成员是随着内部类的加载而加载的,优先于对象存在。这就矛盾了!
public class Outer {
//int num=10;
static int num=10; //静态成员变量
//静态内部类
static class Inter{
void method(){
System.out.println("method run1 .."+num);
}
//静态内部类中静态方法
static void fun(){
System.out.println("fun run3 .."+num);
}
}
public void show(){
System.out.println("method run2 .."+num);
}
}
public class InnerClassDemo2 {
public static void main(String[] args) {
//直接new 内部类,因为内部类被静态后,会随着外部类的加载而加载
//调用内部类中的非静态方法
new Outer.Inter().method();
//访问静态内部类中的静态成员。不需要对象。
//使用:外部类名.内部类名.内部类的静态成员
Outer.Inter.fun();
}
}
运行结果:
其实只需记住一句话:静态随着类的加载而加载,随着类的消失而消失。
可以这么理解:内部类是外部类的一个成员,外部类要调用自己的成员自然要创建对象,而内部类本身又是一个类,要调用自己的成员自然要创建自己的对象。所以,可使用“new 外部类名().内部类名();”创建内部类的对象。而内部类被静态修饰时,随着外部类的加载而加载,所以无需创建外部类的对象调用内部类中的成员。所以可使用“new 外部类名.内部类名();”创建内部类的对象。若静态内部类中有静态成员,静态成员会随着外部类和静态内部类的加载而加载,所以无需创建对象调用该静态成员,所以可使用“外部类名.内部类名.内部类的静态成员”直接访问。
记住:内部类只有定义在外部类的成员位置上,才具备这些修饰符。
内部类定义在局部位置上,不允许访问局部中变量。只能访问被final修饰的局部常量。