一. 概述
1. 定义
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类、嵌套类)。
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
2. 访问规则(互访)
(1)内部类可以直接访问外部类中的成员(包括私有)
之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用。
该引用的写法是:外部类名.this
(2)外部类要访问内部类,必须建立内部类的对象
class Outer
{
private int x=3;
//内部类
class Inner
{
void function()
{
//内部类访问外部类
//无需创建对象就可访问Outer类中的成员变量与成员函数
System.out.println("Inner:"+x);
}
}
void method()
{
//外部类访问内部类
//必须先建立内部类的对象
Inner in=new Inner();
in.function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
Outer out=new Outer();
out.method();
}
}
输出结果是:
Inner:3
class Outer
{
private int x=3;
//内部类
class Inner
{
void function()
{
//内部类访问外部类
//无需创建对象就可访问Outer类中的成员变量与成员函数
System.out.println("Inner:"+x);
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
//访问内部类中的成员
Outer.Inner in=new Outer().new Inner();
in.function();
}
}
输出结果是:
Inner:3
3. 内部类可以直接引用外部类中成员的原理
(1)打印内部类中的局部变量
class Outer
{
private int x=3;
//内部类
class Inner
{
int x=4;
void function()
{
int x=6;
System.out.println("Inner:"+x);
}
}
void method()
{
Inner in=new Inner();
in.function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
Outer out=new Outer();
out.method();
}
}
输出结果是:
Inner:6
(2)打印内部类中的成员变量
class Outer
{
private int x=3;
//内部类
class Inner
{
int x=4;
void function()
{
int x=6;
System.out.println("Inner:"+this.x);
}
}
void method()
{
Inner in=new Inner();
in.function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
Outer out=new Outer();
out.method();
}
}
输出结果是:
Inner:4
(3)打印外部类中的成员函数
class Outer
{
private int x=3;
//内部类
class Inner
{
int x=4;
void function()
{
int x=6;
System.out.println("Inner:"+Outer.this.x);
}
}
void method()
{
Inner in=new Inner();
in.function();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
Outer out=new Outer();
out.method();
}
}
输出结果是:
Inner:3
4. 访问格式
(1)当内部类定义在外部类的成员位置上,而且非私有,在外部其他类中可以直接建立内部类对象
格式:
外部类名.内部类名 变量名=外部类对象.内部类对象
例:
Outer.Inner in=new Outer().new Inner();
(2)当内部类在成员位置上,就可以被成员修饰符所修饰
比如:
private:将内部类在外部类中进行封装
static:内部类就具备了静态特性。
二. 静态内部类
1. 静态内部类只能直接访问外部类中的静态成员
出现了访问局限
2. 在外部其他类中,如何直接访问静态内部类呢?
(1)访问静态内部类的非静态成员
new Outer.Inner().function();
class Outer
{
//用static修饰,才可以被静态内部类Inner访问
private static int x=3;
//静态内部类
static class Inner
{
void function()
{
System.out.println("Inner:"+x);
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
/*
1. 内部类Inner是静态的,可以直接被类名调用
2.function是非静态的,需要由对象来调用
外部类名.内部类对象.内部类中的非静态函数
*/
new Outer.Inner().function();
}
}
输出结果为:
Inner:3
(2)访问静态内部类的静态成员
outer.Inner.function();
class Outer
{
//用static修饰,才可以被静态内部类Inner访问
private static int x=3;
//静态内部类
static class Inner
{
static void function()
{
System.out.println("Inner:"+x);
}
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
/*
1. 内部类Inner是静态的,可以直接被类名调用
2.function是静态的,可以直接被类名调用
外部类名.内部类名.内部类中的静态函数
*/
Outer.Inner.function();
}
}
输出结果为:
Inner:3
3. 注意
(1)当内部类中定义了静态成员,该类必须是静态的
(2)当外部类中的静态方法访问内部类时,内部类也必须是静态的
三. 内部类的位置
1. 内部类定义在成员位置上
(1)可以被private、static成员修饰符修饰
(2)被static修饰的内部类只能访问外部类中的静态成员
(3)当内部类定义了静态成员,该类必须是静态的
2. 内部类定义在局部位置上
(1)可以直接访问外部类中的成员,因为还持有外部类中的引用
class Outer
{
int x=3;
void method()
{
class Inner
{
void function()//可直接访问外部类中的成员
{
System.out.println(x);
}
}
/*
当调用method方法时,function方法不直接运行
需要先创建对象,由对象来运行function方法
*/
new Inner().function();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
new Outer().method();
}
}
(2)不可以被成员修饰符private、static修饰
内部类中的成员变量和成员函数也不能被static修饰,因为一旦被static修饰,该内部类也必须是静态的
(3)可以访问它所在的局部中的局部变量,但必须是被final修饰的
为什么局部内部类和匿名内部类只能访问final的局部变量?
追究其根本原因就是作用域中变量的生命周期导致的:
- 内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁
- 当外部类的方法结束时,局部变量就会被销毁了,但是内部类对象可能还存在(内部类对象访问了一个不存在的变量)
- 为了以上问题,就将局部变量复制了一份作为内部类的成员变量
- 将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的;通过将局部变量设置为final来解决
四. 匿名内部类
1. 引入
匿名内部类就是内部类的简写格式
2. 定义匿名内部类的前提
内部类必须继承一个类或者实现接口(继承的是外部其他类)
3. 格式
new 父类或者接口(可传值)
{
定义子类的内容
}
(1)非匿名内部类形式
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x=3;
class Inner extends AbsDemo //内部类可以继承外部其他类
{
void show()
{
System.out.println("show:"+x);
}
}
public void function()
{
new Inner().show();
}
}
class InnerClassDemo4
{
public static void main(String[] args)
{
new Outer().function();
}
}
(2)匿名内部类形式
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x=3;
public void function()
{
new AbsDemo(){
void show()
{
System.out.println("show:"+x);
}
}.show();
}
}
class InnerClassDemo4
{
public static void main(String[] args)
{
new Outer().function();
}
}
4. 实质
匿名内部类就是一个匿名子类对象
而且这个对象有点胖,可以理解为带内容的对象
5. 匿名类中可以定义匿名子类特有的方法
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x=3;
public void function()
{
new AbsDemo(){
void show()
{
System.out.println("show:"+x);
}
void abc()
{
System.out.println("haha");
}
}.abc();
}
}
class InnerClassDemo4
{
public static void main(String[] args)
{
new Outer().function();
}
}
6. 给匿名内部类起名字(存在局限不实用)
(1)调用匿名内部类中不同方法,需要创建多个匿名子类对象;为了解决以上麻烦,可以给匿名内部类起名(实际上是多态)
(2)实际上只能调用父类/接口中的函数,不能调用匿名子类中特有的函数(具有局限性不实用)