内部类
内部类,顾名思义是定义在类中的类。此时,可以将它们区分为外部类和内部类
内部类分为:成员内部类,静态内部类,局部内部类,匿名内部类
成员内部类
定义
public class Test{
public class Exam{
public void test(){
sout("内部类");
}
}
}
创建
注意:内部类和成员方法、成员变量一样,是对象所有的,而不是类所有的,如果我们要使用成员内部类,那么就需要:
public static void main(String[] args){
Test test = new Test(); //首先创建一个对象
Test.Exam exam = test.new Exam();//在该对象基础上创建内部类的对象
或者写成一行:
main(){
Test.Exam exam = new Test().new Exam();
使用
- 成员内部类及其方法同样可以定义访问权限
- 成员内部类中可以使用外部类的成员变量,但是外部类无法使用成员内部类的成员变量(因为内部类是依附于外部类创建的,在外部类创建前,内部类的成员变量还没有创建)
- Java16后,成员内部类中可以定义静态变量
同名情况
如果外部类的成员变量与内部类的成员变量以及内部类的方法形参名相同,那么如何访问这三个变量呢?
public class Test {
private final String name; //final表示该1变量只能被赋值一次并且之后不能改变
public Test(String name){
this.name = name;
}
public class Inner {
String name;
public void test(String name){
System.out.println("方法参数的name = "+name); //依然是就近原则,最近的是参数,那就是参数了
System.out.println("成员内部类的name = "+this.name); //在内部类中使用this关键字,只能表示内部类对象
System.out.println("成员内部类的name = "+Test.this.name);
//如果需要指定为外部的对象,那么需要在前面添加外部类型名称
}
}
}
对方法的调用
- 调用内部类中方法:
.方法名() - 内部类的父类方法:
.super.方法名() - 外部类方法:
外部类名.this.方法名() - 外部类父类方法:
外部类名.super.方法名()
所以说成员内部类其实在某些情况下使用起来比较麻烦,对于这种成员内部类,我们一般只会在类的内部自己使用。
静态内部类
定义
即在定义内部类时在访问权限后加 static
public class Outer{
private final String name;
public static class Inner{
}
}
创建
不需要依附于类的对象,我们可以直接创建静态内部类的对象:
Outer.Inner inner = new Outer.Inner(); //Outer.Inner为类的全名,并不指外部类的属性
//注:如果在外部类的上下文中创建静态内部类的实例,
//可以省略外部类的类名部分
使用
- 静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类的对象
- 调用静态内部类中的非静态成员方法:先创建静态内部类对象,再通过对象调用
- 调用静态内部类中的静态成员方法:直接通过
外部类.内部类.方法名()调用
局部内部类
定义及创建
是定义在类的方法中的类
创建也是在方法中new一个并使用
public class Outer{
private final String name;
public void test(){
class Inner{ //定义Inner局部内部类
public void hello(){
sout("你好!");
}
}
Inner inner = new Inner();//创建实例对象
innner.helloo();
}
}
使用
局部内部类的作用范围仅在外部类的方法中
只不过这种局部内部类的形式,使用频率很低,基本上不会用到,所以说了解就行了。
匿名内部类
即没有名字的内部类,常用在抽象类的对象或接口的实例化创建中(其实不是真的没有名字,编译器会帮我们起),可以写在成员位置,也可以写在局部位置
(当然普通类的对象创建也能用,可以通过代码块或者一些方法给予一些初始属性)
定义与创建
new 类名 / 接口名(){
@Override
重写的方法;
}
对于类来说,匿名内部类与外部类是继承关系
对于接口来说,匿名内部类与接口是实现关系
假如说有一个抽象类Person:
public abstract class Person{
protected String name;
public abstract void test();
}
此时test为抽象方法
通常,我们要用一个子类继承Person类并对test方法重写
通过内部类,可直接在main方法中创建Person对象:
public static void main(String[] args){
Person person = new Person(){
@Override
public void test(){
sout("抽象方法的调用");
}
}; //!!!注意这是一句话最后要加分号
person.test();
}
此时在 new Person() 后加一个代码块表示匿名内部类的创建,在匿名内部类中依然可以定义成员变量和成员方法,同时匿名内部类中也可以访问抽象类的各种属性
创建一个匿名接口实现类:
Study study = new Study(){ //或者: new Study(){
@Override // @Override
public void study(){ // public void study(){
sout("匿名的接口实现类"); // sout("study方法调用");
} // }
} // }.study();
study.study();
注意
如果在匿名内部类中使用外部类的局部变量(方法内部定义的变量),这些局部变量必须是 final 或者是“隐式的 final”(即在定义后不再被修改)
给出一种反例:
public interface Study{
void study();
}
public static void main(String[] args){
int a = 10;
a = 20; //代表a不是final
Study study = new Study(){
@Override
public void study(){
sout(a); //错误!!
}
}
}