目录
在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致。
根据内部类的位置可以分为:
成员内部类
public class Demo {
private int i = 1;
class Inner{
public void show(){
System.out.println(i);
}
}
}
那该如何访问内部类方法呢?
在访问类中的方法 ,一般是new 一个对象,通过对象.方法();但这里发现会编译报错。因为内部类外面还有一个外部类,那我们来大胆假设一下,是否可以通过外部类对象.内部类对象来获取到内部对象的引用在调用方法
外部类.内部类 变量a= new 外部类(). new 内部类();
public class Test {
public static void main(String[] args) {
Demo.Inner inner = new Demo().new Inner();
inner.show();
}
}
静态内部类
既然有成员内部类,那在假设修饰符static就可以有静态内部类
public class Demo {
private int i = 1;
private static String str = "你好中国";
static class StaticInner{
public void hello(){
System.out.println(str);
}
}
}
那该如何调用静态内部类方法呢? 外部类名.静态内部类类名 = new 外部类.静态内部类()
在编写测试类
public class Test {
public static void main(String[] args) {
Demo.StaticInner inner = new Demo.StaticInner();
inner.hello();
}
}
注意:静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量
局部内部类
顾名思义就是在外部类的方法中
public class Demo {
private int i = 1;
public void method(){
class Inner{
public void show(){
System.out.println(i);
}
}
}
}
先编写测试类,看看是否能调用到局部内部类方法
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
demo.method();
}
}
编译不报错,但允许没有打印出成员变量i的值。那我们想一下,这里只是在调用了Demo对象的方法,并没有调用到内部类的方法,而且内部类的对象也并没有创建。
既然都申明了内部类,那我们大胆尝试一下通过直接new 内部类创建对象,最后得到如下代码
public void method(){
class Inner{
public void show(){
System.out.println(i);
}
}
Inner i = new Inner();
i.show();
}
发现编译通过,在修改测试类的调用方式,如下,最终调用成功
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
demo.method();
}
}
匿名内部类
它是属于局部内部类的一种特殊形式,它有一下特点
- 没有名字
- 必须继承一个抽象类或者实现一个接口
- 它连类名都没有,就不能通过类名.静态成员/静态方法
根据它的规则我们先创建一个接口
public interface Inter {
void show();
}
然后在编写一个外部类,根据之前写过的2中内部类形式,可以大胆猜测一下匿名内部类的写法
public class Demo {
private int i = 1;
public void test (){
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类");
}
};
}
}
通过测试类发现并没有打印输出
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
demo.test();
}
}
到底什么地方出问题了呢??? 我们一定要清醒的记住,内部类只是一个类,并没有通过对象调用方法。而匿名内部类这里已经使用new关键字,那我们大胆假设在定义的匿名内部类通过.show() 看是否可行。最后发现可以调用到匿名内部类的方法
public class Demo {
private int i = 1;
public void test (){
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类");
}
}.show(); //直接调用方法
}
}
在执行测试类,发现成功打印。
这里要说明一点,内部类不会因为外面的类或者方法销毁而销毁。 比如上面的调用了Demo对象的test() 方法,并不会因为test()结束,内部类Inter也一定会跟着销毁。
匿名内部类还有以下特点:
- 匿名内部类必须继承一个抽象类或者实现一个接口。
- 匿名内部类不能定义任何静态成员和静态方法。
- (局部内部类和匿名内部类)当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。为什么要加final呢?是因为生命周期不一致, 局部变量存储在jvm栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。