内部类的概念
- 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类
- 与之对应,包含内部类的类被称为外部类
- 内部类隐藏在外部类之内,更好的实现了信息隐藏
- 内部类分为:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
成员内部类
- 内部类中最常见的就是成员内部类,也称为普通内部类
- 内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
- 内部类的访问修饰符,可以任意,但是访问范围会受到影响
- 内部类可以直接访问外部类的成员;如果出现同名属性,优先访问内部类中定义的
- 可以使用外部类.this.成员的方式,访问外部类中同名的信息
- 外部类访问内部类信息,需要通过内部类实例,无法直接访问
- 内部类编译后.class文件命名:外部类$内部类.class
- 获取成员内部类对象实例的三种方式
- 方式一:new 外部类.new 内部类
Person.Heart myHeart=new Person().new Heart();
System.out.println(myHeart.beat());
- 方式二:外部类对象.new 内部类
myHeart=lili.new Heart();
System.out.println(myHeart.beat());
- 方式三:外部类对象.获取方法
myHeart=lili.getHeart();
System.out.println(myHeart.beat());
- 方式一:new 外部类.new 内部类
静态内部类
- 静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例
- 静态内部类对象实例时,可以不依赖于外部类对象
- 可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员
- 当内部类属性与外部类属性同名时,默认直接调用内部类中的成员
- 如果需要访问外部类中的静态属性,则可以通过 外部类.属性 的方式
- 如果需要访问外部类中的非静态属性,则可以通过 new 外部类().属性的方式
- 获取静态内部类对象实例
Person.Heart myHeart=new Person.Heart();
System.out.println(myHeart.beat());
方法内部类
- 定义在外部类方法中的内部类,也称局部内部类,作用范围也在方法内
- 和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
- 类中不能包含静态成员
- 类中可以包含final、abstract修饰的成员
匿名内部类
- 匿名内部类也就是没有名字的内部类
- 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
- 必须继承一个父类或实现一个接口
- 注意事项:
- 编译后的文件命名:外部类$数字.class
- 无法使用 public、private、protected、static 修饰,匿名内部类不能出现抽象方法
- 无法编写构造方法,但可以添加构造代码块
- 不能出现静态成员
- 匿名内部类可实现接口也可以继承类,但是不可兼得
- 匿名内部类不能是抽象的,它必须要实现继承的类或实现接口的所有抽象方法
- 例:
public abstract class Person {
private String name;
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void read();
}
public class PersonTest {
public void getRead(Person person) {
person.read();
}
public static void main(String[] args) {
PersonTest test = new PersonTest();
test.getRead(new Person() {
{
// 构造代码块
}
// public static int age=12;
@Override
public void read() {
System.out.println("男生喜欢看科幻类书籍");
}
});
test.getRead(new Person() {
@Override
public void read() {
System.out.println("女生喜欢读言情小说");
}
});
}
}
匿名内部类的几种表现形式
- 继承式的匿名内部类:
- 引用变量不是引用 Car 对象,而是 Car 匿名子类的对象
- 建立匿名内部类的关键点是重写父类的一个或多个方法
- 接口式的匿名内部类:
- 接口式的匿名内部类是实现了一个接口的匿名类,而且只能实现一个接口
- 参数式的匿名内部类
- 由上面的三个例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承 Thread 或是实现 Runnable 接口
- Thread 类的匿名内部类实现:
- Runnable 接口的匿名内部类实现
接口中的内部类
- 在实际开发过程中,如果想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么接口内部的嵌套类会显得很方便
- 在接口中可以含有内部类
- 首先创建接口,接口中定义了普通内部类 InnerClass 和抽象内部类 AbInnerClass
- 普通成员内部类的实例化
- 创建接口的实现类 ClassDemo
- 获取普通内部类对象,调用方法
- 运行结果:
- 抽象成员内部类的实例化
- 创建接口的实现类 AbClassDemo
- 获取抽象内部类对象,调用方法
- 运行结果:
案例总结
//接口Ball
public interface Ball {
//创建抽象方法play():void
void play();
}
public class BallTest implements Ball {
//无参构造
public BallTest() {
}
@Override
public void play() {
// TODO 自动生成的方法存根
};
public void playBall(Ball ball) {
ball.play();
};
//获取成员内部类对象
public Inner_m getInner_m() {
return new Inner_m();
}
// 创建成员内部类Inner_m
public class Inner_m implements Ball {
@Override
public void play() {
System.out.println("成员内部类:\n打篮球");
}
}
// 创建方法内部类
public void info() {
class Inner_f implements Ball {
@Override
public void play() {
System.out.println("***************\n方法内部类:\n打乒乓球");
}
}
Inner_f balltwo = new Inner_f();
balltwo.play();
}
}
public class Test {
public static void main(String[] args) {
BallTest ball = new BallTest();
// 方式1:外部类名.内部类名 标识符 = new 外部类().new 内部类()
BallTest.Inner_m ballone = new BallTest().new Inner_m();
// 方式2:外部类对象.new 内部类
ballone = ball.new Inner_m();
// 方式3:外部类对象.获取方法
ball.getInner_m();
ball.playBall(ballone);
// 获取方法内部类对象
ball.info();
// 匿名内部类
ball.playBall(new BallTest(){
@Override
public void play() {
System.out.println("***************\n匿名内部类:\n打排球");
}
});
}
}