一、基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。
内部类是类的第五大成员→【提示:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】。
内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。(注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。)
内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
二、成员内部类
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
1、特点
1.1 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员);
1.2 成员内部类中不能书写静态变量和方法,但是可以使用 static final关键字定义常量。
1.3 成员内部类可以使用四种权限修饰符进行修饰(四种权限修饰符:public(公有的) >protected(受保护的) > (default)(缺省/默认的) > private(私有的));
1.4 同名的属性名/方法名访问外部类时 → 外部类.this.成员名
1.5 成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。所以在外部类访问内部类的时候必须先实例化外部类对象。
1.6 成员内部类编译以后也会生成一个 .class文件,文件名是 外部类名$内部类名.class。
Outer outer= new outer();
Inner inner = outer.new Inner();
//或者如下一句代码:
Outer.Inner inner = new Outer().new Inner();
2.案例演示
public class Outer {
String name = "外部类的类名";
static String type = "外部类的type属性";
private int item = 1;
public static void show() {
System.out.println("掉用外部类中的show方法");
}
public void print() {
System.out.println("调用外部类中的打印方法");
}
//成员内部类 可以使用权限修饰符进行修饰
public class Inner{
//static double weight = 1.8; //成员内部类中不能使用static修饰变量和方法
String name = "内部类的类名";
public void innerShow(){
//成员内部类可以直接访问外部类的属性和方法
show();
print();
System.out.println(type);
System.out.println(item);
System.out.println("我是:" + name);
//进行特指访问时 使用类名.this.变量名进行访问
System.out.println("我是:" + Outer.this.name);
}
}
public static void main(String[] args) {
//成员内部类对象的创建步骤
//1.第一步需要实例化外部类对象
//2.第二步正常实例化内部类对象 但是new关键字要改成 外部类对象名.new
/*Outer outer = new Outer();
Inner inner = outer.new Inner();*/
//或者这样创建
Outer.Inner inner = new Outer().new Inner();
inner.innerShow();
}
}
三、静态内部类
说明:静态内部类是定义在外部类的成员位置,并且有static修饰
1、特点
1.1 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问外部类的非静态成员。
总结:静态只能访问静态的。不能访问非静态的。
1.2 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
1.3 静态内部类中即能声明静态成员也可以声明非静态成员。
1.4 静态内部类可以直接实例化 不需要依附于外部类。
1.5 外部类可以通过 静态内部类名.静态成员名 访问静态内部类的静态成员
2.案例演示
public class Static {
static String name = "外部类的类名";
//静态内部类中不能访问外部类非静态成员
String type = "外部类的type属性";
public static class Inner{
//四种权限修饰符可以修饰静态内部类
public String name = "静态内部类的类名";
static double weight = 1.8;
String type = "静态内部类的type属性";
public void show(){
System.out.println("我是:" + weight);
System.out.println("我是:" + type);
System.out.println("我是:" + name);
//System.out.println("我是:" + Static.type);//静态内部类中不能访问外部类非静态成员
System.out.println("我是:" + Static.name);
}
}
public static void main(String[] args) {
//静态内部类可以直接实例化 不需要依附于外部类
Inner inner = new Inner();
inner.show();
}
}
public class StaticOuter {
private int x = 10;
private static int m = 3;
public static final class StaticInner {
private int a = 5;
private static int b = 7;
private int x = 1;
private static int m = 6;
public void test() {
// System.out.println(x);
// foo();
int x = 2;
int m = 9;
System.out.println("StaticInner类test方法里 x = " + x); // 2
System.out.println("StaticInner类test方法里 x = " + this.x); // 1
System.out.println("StaticInner类test方法里 m = " + m); // 9
System.out.println("StaticInner类test方法里 StatiInner.m = " + StaticInner.m); // 6
System.out.println("StaticInner类test方法里 StaticOuter.m = " + StaticOuter.m); // 3
demo();
}
public static void bar() {
// System.out.println(x);
}
}
public static void demo() {
}
public void foo() {
}
}
三、局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
1、特点
1.1 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;
1.2 局部内部类不可使用权限修饰符 静态(static)修饰符进行修饰 同局部变量相同;
1.3 局部内部类访问外部类的静态成员
1.4 可以定义非静态成员变量、静态成员变量 但不能定义静态变量
1.5 如果这个局部内部类所在的方法是静态的,它无法访问外部类的非静态成员
1.6 局部内部类可以访问外部函数的局部变量,但 这个局部变量必须要非final修饰。JDK8以后,final可以省略
1.7 局部内部类只能在声明它的那个方法里使用
1.8 生成独立的.class文件,文件名是 外部类名.编号局部内部名
2.案例演示
public class Partial {
String name = "外部类的类名";
String type = "外部类的type属性";
private int item = 1;
public static void show() {
System.out.println("掉用外部类中的show方法");
}
public void print() {
System.out.println("调用外部类中的打印方法");
}
public void demo(){
String name = "外部类方法deme()内部的方法名";
String type = "外部类方法deme()内部的type属性";
/*编写在方法的内部的类称之为局部内部类
局部内部类不可使用权限修饰符 静态修饰符进行修饰 同局部变量相同
局部内部类与局部变量使用范围一样 在此方法内部
局部内部类可以直接访问方法中的属性 重名时使用参数传递完成访问*/
class Inner{
//局部内部类 可以访问方法外部类中属性和方法
String name = "局部类的类名";
public void showInner(String name){
show();
print();
System.out.println("我是:"+ type);
System.out.println("我是:"+ Partial.this.type);
System.out.println(item);
System.out.println("我是:" + this.name);
System.out.println("我是:" + name);
System.out.println("我是:" + Partial.this.name);
}
}
//局部内部类 创建对象 要在方法内部 局部内部类的外部声明
Inner inner = new Inner();
inner.showInner(name);
}
public static void main(String[] args) {
Partial partial = new Partial();
partial.demo();
}
}
四、匿名内部类
说明:用来创建一个接口或者抽象类对象(抽象类或者接口 本不可以直接创建对象,可使用匿名内部类方法直接创建)
1、特点
1.1 匿名内部类就是一种特殊的局部内部类,只不过没有名称而已,基本特点和局部内部类一致。定义在外部类的局部位置。
1.2 匿名内部类不能有构造器,匿名内部类没有类名,肯定无法声明构造器
1.3 匿名内部类的前提是,这个内部类必须要继承自一个父类或者父接口
1.4 匿名内部类是接口的一种常见简化写法,也是我们开发中最常使用的一种内部类。它的本质是一个实现类父类或者父类接口具体方法的一个匿名对象。
2.案例演示
abstract class Animal{
abstract void shout();
}
class Demo{
public void demo(){
Animal animal = new Animal() {
@Override
void shout() {
System.out.println("动物在叫");
}
};
}
}
// 实现关系下的匿名内部类:
interface Dao {
void show();
}
public class AnonymousDemo {
//编写回调方法 :callInner
public void callInner(){
// 接口关系下的匿名内部类
new Dao(){
//实现子类 但是没有名字 所以叫匿名内部类
@Override
public void show() {
System.out.println("接口方法...");
}
}.show();
}
}
// 测试:
public class Demo {
public static void main(String[] args) {
AnonymousDemo anonymousDemo = new AnonymousDemo();
anonymousDemo.callInner();
}
}
匿名内部类可用于给方法传递实参,演示如下:
interface Dao {
void show();
}
public class AnonymousDemo {
//编写回调方法:callInner 参数类型为接口Dao
private static void callInner(Dao d) {
d.show();
}
public static void main(String[] args) {
callInner(new Dao() {//接口回调
//实现子类 但是没有名字 所以叫匿名内部类
@Override
public void show() {
System.out.println("匿名内部类用于给方法传递实参");
}
});
}
}
说明:首先有一个接口,然后在使用的类中编写了一个方法(参数类型是接口对象),并使用接口中未实现的方法。
我们调用此方法直接构造一个接口对象传入,此时会自动生成一个此接口的子类(匿名内部类)实现接口中的方法。本质传入的类便是此时的匿名内部类。