1. 内部类基本介绍
一个类的内部又完整地嵌套了另一个类结构,我们称这个被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。内部类作为类的第五大成员(五大成员为:属性、方法、构造器、代码块、内部类),内部类的最大特点是可以直接访问外部类的私有属性,并且可以体现类与类之间的包含关系。
2. 内部类的分类
如果定义类在局部位置(方法中/代码块):(1)局部内部类(2)匿名内部类
定义在成员位置:(1)成员内部类(2)静态内部类
下面我们根据内部类定义位置进行详细介绍。
2.1 定义类在局部位置(指方法或代码块)
2.1.1 局部内部类
局部内部类特点:
- 局部内部类是定义在外部类的局部位置,通常在方法(也可以是代码块)
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,但是可以使用 final 修饰(修饰后不能被继承)
- 作用域:仅仅在定义它的方法或代码块中
- 局部内部类可以直接访问外部类的成员
- 如果想访问外部类的成员,可以使用 (外部类名.this.成员) 去访问
局部内部类构建:
class Outer02 {//外部类
private int n1 = 100;
private void m2() {
System.out.println("Outer02 的 m2被调用");
}
public void m1() {//方法
final class Inner02 {//局部内部类
private int n1 = 800;
public void f1() {
System.out.println("外部类的n1 = " + Outer02.this.n1 + "\t内部类的n1 = " + n1);
System.out.println("Outer02.this 的hashcode=" + Outer02.this);
m2();
}
}
//外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
{//代码块,可以定义局部内部类
}
}
}
在外部其他类中如何调用局部内部类呢?请看下面的例子:
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
System.out.println("outer02的hashcode=" + outer02);//与f1输出的hashcode相同
}
}
2.1.2 匿名内部类(重点)
首先先明确使用匿名内部类的需求:想创建一个单次使用的,实现了接口或者基于抽象类的对象(简化代码)。
匿名内部类特点:
- 匿名内部类是定义在外部类的局部位置,通常在方法(也可以是代码块)
- 本质是类,该类没有名字
匿名内部类演示:
class Outer04{
private int n1 = 10;
public void method(){
//1.tiger 的编译类型? IA
//2.tiger 的运行类型? 就是匿名内部类 XXXX => Outer04$1
//3.jdk底层在创建匿名内部类 Outer04$1,立即就创建了 Outer04$1 实例,
//并且把地址返回给tiger
//4.匿名内部类使用一次,就不能再使用(无法new Outer04$1,但可以继续创建)
//可以直接new IA()
IA tiger = new IA(){
@Override
public void cry() {
System.out.println("老虎叫唤");
}
};
System.out.println("tiger的运行类型 = " + tiger.getClass());
//tiger的运行类型 = class Outer04$1
tiger.cry();
//演示基于类的匿名内部类
//1.father编译类型 Father
//2.father运行类型 Outer04$2
//3.底层会创建匿名内部类
/*
class Outer04$2 extends Father{
}
*/
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father对象的运行类型=" + father.getClass());
//father对象的运行类型=class Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头");
}
};
animal.eat();
}
}
interface IA{
public void cry();
}
class Father{
public Father(String name){}
public void test(){}
}
abstract class Animal{
abstract void eat();
}
匿名内部类案例2:
public class Calculate {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
cellphone.testWork(new ICalculate() {
@Override
public double work(double n1, double n2) {
return n1 + n2;
}
}, 10, 8);
cellphone.testWork(new ICalculate() {
@Override
public double work(double n1, double n2) {
return n1 * n2;
}
}, 10, 8);
}
}
interface ICalculate{
public double work(double n1, double n2);
}
class Cellphone {
//传入一个实现了接口的匿名内部类即可
public void testWork(ICalculate iCalculate, double n1, double n2){
double result = iCalculate.work(n1, n2);//动态绑定
System.out.println("计算后的结果=" + result);
}
}
2.2 定义在成员位置
2.2.1 成员内部类
成员内部类特点:
- 成员内部类,定义在外部类的成员位置上。
- 可以添加任意访问修饰符(public protected 默认 private),因为它本身就是一个成员。
- 可以直接访问外部类的所有成员,包含私有的
- 如果成员内部类的成员和外部类的成员重名,会遵守就近原则
- 可以通过 (外部类名.this.属性) 来访问外部类成员
成员内部类构建:
class Outer08{
private int n1 = 10;
public String name = "zhangsan";
public class Inner08{//成员内部类
private int n1 = 99;
public void say(){
//可以直接访问外部类的所有成员,包含私有的
//可以通过 外部类名.this.属性 来访问外部类成员
System.out.println("n1 = " + n1 + " 外部类的n1 = " + Outer08.this.n1);
}
}
//下面为实例化内部类提供方法
//返回一个对象
public Inner08 getInner08Instance(){
return new Inner08();
}
public void t1(){
Inner08 inner08 = new Inner08();
inner08.say();
}
}
在外部其他类中如何调用成员内部类呢?请看下面的例子:
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,使用成员内部类的2种方式
//第一种方式
//
Outer08.Inner08 inner08 = outer08.new Inner08();
//第二种方式(常用)
//在外部类中,编写一个方法,可以返回 Inner08对象
Outer08.Inner08 inner08Instance = new Outer08().getInner08Instance();
inner08Instance.say();
}
}
2.2.2 静态内部类
静态内部类特点:
- 放在外部类的成员位置
- 使用static修饰
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意访问修饰符
- 作用域:同其他成员,为整个类体
静态内部类构建:
class Outer10{
private int n1 = 10;//静态内部类无法直接访问非静态成员
public static String name = "张三";
private static void cry(){}
//静态内部类
static class Inner10{
public static String name = "咕咕咕";
public void say(){
System.out.println("外部类的name = " + Outer10.name + "name = " + name);
}
}
public void m1(){
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10(){
return new Inner10();
}
//静态方法,可以不new对象直接调用
public static Inner10 getInner10_(){
return new Inner10();
}
}
在外部其他类中如何调用静态内部类呢?请看下面的例子:
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类 使用静态内部类
//方式1
//因为静态内部类,是可以直接通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式2
//编写一个方法,可以返回静态内部类的对象实例
//new 对象方法
Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("=============");
inner101.say();
//静态方法
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println("=============");
inner10_.say();
}
}