思维导图
概念
1、定义
简单来说就是在类的内部再定义一个类
2、形式
//外部类
class Outer{
//...
//内部类
class Inner{
//...
}
}
分类
1、成员内部类
1.1 特征
定义在类中,方法外
1.2 特性
1、编译成功后会生成两个class文件
MemberOuterClass.class
MemberOuterClass$MemberInnerClass.class
2、成员内部类中不能编写静态的属性和方法
原因:在类加载的时候,被static修饰的静态变量就会被初始化,静态方法就会被调用,如果在内部类中定义静态变量和静态方法,就会导致不需要外部类的对象就可以生成内部类的对象,这与成员内部类的定义相驳。
3、成员内部类的对象必须通过外部类的对象才能创建
4、成员内部类和外部类的相互访问
(1)成员内部类访问外部的属性和方法
- 内部类调用自身属性-----直接用
- 内部类调用自身方法-----this.方法名
- 内部类调用外部类非静态属性-----外部类类名.this.属性名
- 内部类调用外部类非静态方法-----外部类类名.this.方法名
- 内部类调用外部类静态属性-----外部类类名.方法名
- 内部类调用外部类静态方法-----外部类类名.方法名
public class MemberOuterClass {
//外部类属性
private String name;
private static int age;
//外部类的方法
public void run() {
}
public static void go(){
}
//成员内部类
public class MemberInnerClass{
private String name;
private int age;
public void run(String name) {
//访问当前run方法中的参数name
System.out.println(name);
//访问内部类自己的属性name
System.out.println(this.name);
//访问外部类的非静态属性
System.out.println(MemberOuterClass.this.name);
//访问外部类的静态属性
System.out.println(MemberOuterClass.age);
//访问外部类的非静态方法
MemberOuterClass.this.run();
//访问外部类的静态方法
MemberOuterClass.go();
}
}
//成员内部类声明结束
}
(2)外部类访问成员内部类的属性和方法
- 通过创建外部类的对象,可以直接调用成员内部类的属性和方法
public class MemberOuterClass {
//外部类方法
public void test() {
MemberInnerClass m = new MemberInnerClass();
//外部类访问成员内部类的属性
System.out.println(m.name);
System.out.println(m.age);
//外部类访问成员内部类的方法
m.run("tom");
}
//声明成员内部类
public class MemberInnerClass{
//定义内部类的属性和方法
private String name;
private int age;
public void run(String name) {
}
}
}
(3)在其他类中使用这个内部类
- 前提是这个成员内部类不是被private修饰的
- 这个内部类需要import导入,形式:import 外部类.内部类
- 创建对象时,需先创建外部类对象,再使用外部类对象再创建内部类对象:外部类对象.new 内部类对象();
2、静态内部类
2.1 特征
内部类被static修饰,也只有内部类能被static修饰,其他类不能被static修饰
2.2 特性
1、编译后生成两个class文件
staticOuterClass.class 外部类
staticOuterClass$staticInnerClass.class 静态内部类
2、静态内部类内可以编写属性和静态方法,并且四种内部类中只有静态内部类可以编写静态属性和静态方法
3、静态内部类与外部类的相互访问
(1)静态内部类访问外部类的属性和方法
- 静态内部类中访问不了外部类中的非静态属性和方法
- 内部类访问自身的属性和方法-----this.方法名/属性名
- 内部类访问自身的静态属性和方法-----直接使用
- 内部类访问外部类的静态属性和方法-----外部类类名.属性名/方法名
public class StaticOuterClass {
private String name; //外部类中的非静态属性
private static int age; //外部类中的静态属性
public void run() {} //外部类非静态方法
public static void go() {} //外部类静态方法
//声明静态内部类
public static class StaticInnerClass{
private String name;
private static int age;
public void run(String name) {
//访问当前run方法中的参数name
System.out.println(name);
//访问内部类自己的属性
System.out.println(this.name);
//访问内部类自己的静态属性
System.out.println(age);
//静态内部类中无法访问外部类的非静态属性和方法
//访问外部类的静态属性和方法
System.out.println(StaticOuterClass.age);
StaticOuterClass.go();
}
}
}
(2)在其他类中访问这个非private修饰的静态内部类
- 需要import导入,形式:import 外部类.内部类
- 创建对象时,直接:new 静态内部类对象();不再需要外部类对象
4、静态类与普通内部类的区别
普通内部类
1、内部类拥有普通类的所有特性,也拥有类成员变量的特性
2、内部类可以访问其外部类的成员变量,属性,方法,其它内部类
静态内部类
1、只有内部类才能声明为static,也可以说是静态内部类
2、只有静态内部类才能拥有静态成员,普通内部类只能定义普通成员
3、静态类跟静态方法一样,只能访问其外部类的静态成员
4、如果在外部类的静态方法中访问内部类,这时候只能访问静态内部类
3、局部内部类
3.1 特征
定义在外部类的方法中。
3.2 特性
1、局部内部类的作用范围只在当前方法中
2、最不常用。。。
3、局部内部类与外部类的相互访问
(1)局部内部类访问外部的属性和方法
public class LocalOuterClass {
private String name; //非静态变量
private static int age; //静态变量
//外部类方法
public void run() {} //非静态方法
public static void go() {} //静态方法
public void sayHello(String name) {
//开始声明局部内部类
class LocalInnerClass{
private String name;
public void test(String name) {
//访问当前test()方法中的参数name
System.out.println(name);
//访问内部类自身的属性
System.out.println(this.name);
//访问外部类的非静态属性
System.out.println(LocalOuterClass.this.name);
//访问外部类的非静态方法
LocalOuterClass.this.run();
//访问外部类的的静态属性和方法
System.out.println(LocalOuterClass.age);
LocalOuterClass.go();
}
}
}
}
(2)局部类内中访问当前方法中的变量(这个变量必须是final修饰的)
public void sayHello(final String name) {
final int num = 1;
class LocalInnerClass{
public void test() {
System.out.println(name);
System.out.println(num);
//final修饰的变量只能被赋值一次
//name = "tom";
//num = 2;
}
}
}
在JDK1.8中,一个局部变量在局部内部类中进行访问了,那这个变量自动变为final修饰
(3)外部类访问局部内部类的属性和方法
public void sayHello(String name) {
//开始声明局部内部类
class LocalInnerClass{
private int num;
public void test() {
}
}
//创建局部内部类对象
LocalInnerClass lic = new LocalInnerClass();
//对象访问属性
System.out.println(lic.num);
//对象调用方法
lic.test();
}
4、匿名内部类
4.1 特征
没有名字的类,使用匿名内部类可以简化实现接口和抽象方法重写的过程。
匿名内部类的一般格式:
父类或者接口类型 变量名 = new 父类或者接口(){
//方法重写
@Override
public void method(){
//执行语句
}
}; //注意别落下了这个分号
//调用实现(重写)后的方法
变量名.method();
4.2 特性
1、匿名内部类的两种形式
1、利用一个父类,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个父类的子类型
2、利用一个接口,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个接口的实现类
2、必须依托于一个父类型或者一个接口
(1)依托父类
//这是一个父类型
abstract class Animal{
public abstract void run(); //
}
public class Demo01 {
public static void main(String[] args) {
Animal animal = new Animal() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("匿名内部类中的默认实现");
}
};
//匿名内部类方法的通用
animal.run();
}
}
(2)依托接口
这个匿名内部类默认就是这个接口的实现类。
interface Action{
void run();
}
public class Demo {
public static void main(String[] args) {
Action a = new Action() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("匿名内部类的默认实现!");
}};
//匿名内部类的调用
a.run();
}
}
3、在声明的同时必须创建对象
4、匿名内部类中无法定义构造器