在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。
- 内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限
- 内部类可以分为4种形式:成员内部类,局部内部类,静态内部类,匿名内部类
内部类的特点:
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 修饰
- 内部类声明成静态的,只能直接访问外部类的静态成员变量。
在一个类中,除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。
在成员内部类中,可以访问外部类的所有成员,包括成员变量和成员方法,在外部类中,同样可以访问成员内部类的变量和方法
class Out{
int o = 0;//外部类的成员变量
void test1(){//外部类成员方法
System.out.println("外部类成员方法");
}
void test2(){//定义外部类方法,访问内部类的变量和成员
In in = new In();
System.out.println("内部类成员变量i:" + in.i);
in.print2();
}
class In{//成员内部类
int i = 1;
void print1(){//定义内部类方法,访问外部类成员的变量和方法
System.out.println("外部类成员变量o:" + o);
test1();
}
void print2(){
System.out.println("内部类成员方法");
}
}
}
public class demo001{
public static void main(String[] args) {
Out out = new Out(); //创建外部类对象
Out.In in = out.new In(); //创建内部类对象
in.print1(); //在成员内部类中访问外部类成员变量和方法
out.test2(); //在外部类中访问内部类成员和方法
}
}
- 外部类只有 2 种访问级别:public 和默认;
- 内部类则有 4 种访问级别:public、protected、 private和默认。
- 内部类与外部类不能重名。
在外部类中可以直接通过内部类的类名访问内部类。 In in = new In(); 在外部类以外的其他类中则需要通过内部类的完整类名访问内部类。 Out.In in = new Out().new In(); //创建内部类对象2. 局部内部类
局部内部类,也叫做方法内部类,就是定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其有效范围只限于方法内部
在局部内部类中,局部内部类可以访问外部类的所有成员变量和方法,而局部内部类中的变量和方法却只能在创建该局部内部类的方法中进行访问
public class Test {
public void method() {
class Inner {
// 局部内部类
}
}
}
局部内部类的特点:
- 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰
- 局部内部类只在当前方法中有效
- 局部内部类中不能定义 static 成员
- 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰
- 在局部内部类中可以访问外部类的所有成员
class Out{
int o = 0;
void test1(){
System.out.println("外部类成员方法");
}
void test2(){
class In{//局部内部类
int i = 1;
void show(){//局部内部类中访问外部类变量和方法
System.out.println("外部类变量o:" + o);
test1();
}
}
//在创建局部内部类的方法中,调用局部内部类变量和方法
In in = new In();
System.out.println("局部内部类变量i:" + in.i);
in.show();
}
}
public class demo001{
public static void main(String[] args) {
Out out = new Out();
out.test2();
}
}
- 在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 OuterClassName .this.MemberName 的形式访问外部类中的成员
静态内部类:使用 static 关键字修饰的成员内部类
public class Outer {
static class Inner {
// 静态内部类
}
}
静态内部类中只能访问外部类的静态成员,同时通过外部类访问静态内部类成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员
静态内部类的特点:
- 在创建静态内部类的实例时,不需要创建外部类的实例
class Out{
static class In{
}
}
public class demo001{
public static void main(String[] args) {
Out.In in = new Out.In();//不需要 new Out().new In()
}
- 静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例
- 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问
匿名类是指没有类名的内部类,在调用包含有接口类型参数的方法时,通常为了简化代码,不会创建一个接口的实现类作为方法参数传入,而是直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中直接完成方法的实现
使用匿名类可使代码更加简洁、紧凑,模块化程度更高。
new 父接口() {
// 匿名内部类实现部分
}
interface Animal{
void sleep();
}
public class demo001{
public static void animalSleep(Animal an){
an.sleep();
}
public static void main(String[] args) {
String name = "二哈";
animalSleep(new Animal() {
@Override
// JDK 8 开始,局部内部类、匿名内部类可以访问非 final 修饰的局部变量
public void sleep() {
System.out.println(name + " : 睡觉");
}
});
}
}
调用 animalSleep(Animal an) 方法时需要一个 Animal 接口类型的参数,所以使用了匿名内部类方式实现 Animal 接口并作为参数传入
- 在调用 animalSleep() 方法时,在方法的参数位置写上 new Animal(){} ,这相当于创建了一个实例对象,并将这个对象作为参数传给 animalSleep() 方法。在new Animal()后面有一对 {} ,表示创建的对象为 Animal 的子类实例,该子类时匿名的
animalSleep(new Animal() {} );
- 在{} 中编写匿名子类的实现代码
animalSleep(new Animal() {
@Override
public void sleep() {
System.out.println(name + " : 睡觉");
}
});
(特点有点难,后期再补代码 ::>_<::)
匿名内部类的特点:
- 匿名类和局部内部类一样,可以访问外部类的所有成员
- 匿名类中允许使用非静态代码块进行成员初始化操作
- 匿名类的非静态代码块会在父类的构造方法之后被执行



