匿名内部类

本文详细介绍了Java匿名内部类的使用注意事项,包括为什么形参必须为final,如何初始化,以及内部类的特点和应用场景。匿名内部类简化代码编写,必须继承父类或实现接口,不能有构造函数。此外,文章还总结了Java内部类的四种类型,强调了内部类的封装作用和回调函数的编写优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

匿名内部类的使用主意事项

  • 匿名内部类就是没有名字的内部类
  • 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
  • 但使用匿名内部类还有个前提条件:必须继承一个父类或者实现一个接口
  • 匿名内部类中是不能定义构造函数的

使用的形参为什么要final

  1. 我们给匿名内部类传递参数的时候,若该形参在内部类中有需要被使用,那么该形参必须要为final。也就是说,当所在的方法的形参需要被内部类里面使用时,该形参必须为final。
  2. 为什么必须为final呢?
  • 首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部文件并不是同一个class文件,仅仅只保留对外部类的引用。当外部类传入参数需要被内部类调用时,从Java程序的角度看是直接被调用
  • 但实际上却不是的,它们两者可以任意变化,也就是说在内部类中我对属性的改变并不会影响到外面的形参,所以为了保持参数的一致性,就规定使用final来避免形参的不确定性
  • 简单理解来说,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变
  • 故如果定义一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器就会要求该参数引用是final的。

匿名内部类初始化

我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果

常见的匿名内部类实例

public class Demo{
	public static void main(String[] args){
		Runnable r = new Runnable(){
			public void run(){
				for(int i = 1;i<= 5;i++){
					System.out.print(i+" ");
				}
			}
		};
		Thread t = new Thread(r);
		t.start;
	}
}

Java内部类小结

成员内部类

也是最常规的内部类。该内部类相当于外部类成员的位置。该内部类可以访问外部类的所有成员和方法,即使是private。

public class Outer{
	public class Inner{
		public void print(String str){
			System.out.println(str);
		}
	}
	public Inner getInner(){
		return new Inner();
	}
	public static void main(String[] args){
		Outer outer = new Outer();
		Outer.Inner inner = outer.new Inner();
		inner.print("outer.new");

		inner = outer.getInner();
		inner.print("outer.get");
	}
}

静态内部类

  1. 该方法被修饰为static。同时作为静态内部类,它不能访问外部类非静态的成员和方法。
  2. 一般书写静态时,不涉及成员变量
class Outer{
	public Outter(){
		System.out.println("Outter constructor.");
	}
	static class Inner{
		public Inner(){
			System.out.println("Inner constructor.");
		}
	}
}

pulic class Demo{
	public static void main(String[] args){
		Outter.Inner inner = new Outter.Inner();
	}
}

方法内部类

类被创建在外部方法中:

  1. 可以访问外部类中的成员
  2. 不能被static private修饰,因为它不再是成员位置,只有成员才能被修饰为static
  3. 因此内部类中不能有静态成员
  4. 内部类要访问外部方法中的局部变量时,该局部变量需要被修饰成final
class People{
	public People(){
	}
}
class Man{
	public Man(){
	}
	public People getWoman(){
		class Woman extends People{//局部内部类
			int age = 0;
		}
		return new Woman();
	}
}

匿名内部类

  1. 就是一个内部类的简化版
  2. 定义匿名内部类的前提是,该类必须继承一个外部类或者实现接口。

为什么要有内部类

  1. 内部类是为了更好的封装,把内部类封装在外部类里,不允许同包其他类访问
  2. 内部类中的属性和方法即使是外部类也不能直接访问
  3. 相反内部类可以直接访问外部类的属性和方法,即使private
  4. 利于回调函数的编写。PS:回调函数是函数的迭代
  5. 当描述事物,如身体里的大脑时,大脑在身体内部,可以通过内部类直观描述

内部类特点

  1. 内部类对象不仅指向该内部类,还指向该内部类的外部类对象的内存
  2. 内部类和普通类一样可以重写Object类的方法,如toString方法;并且有构造函数,执行顺序依旧是先初始化属性,再执行构造函数
  3. 在编译完之后,会出现(外部类.class)和(内部类.class)两个类文件名
  4. 内部类可以被修饰为private,只能被外部类所访问,事实上一般也如此书写
  5. 内部类可以被写在外部类的任意位置,如成员位置,方法内。

内部类对象的建立

  1. 在同包其他类以及main方法中(前提要内部类没有被修饰成private,所以一般不采用),先创建外部对象,再通过外部类对象创建内部类

     	Outer outer = new Outer();
     	Outer.In inner = outer.new In();//第一个outer是为了说明该内部类是属于哪个外部类 		
    
  2. 通过匿名外部类创建内部类

     	Outer.In inner = new Outer().new In(); 	
    
  3. 在外部类里,可以直接创建对象,如I

     In inner = new In();
    

    或者直接:

     new In();
    

内部类的访问

  1. 静态时,静态内部类只能访问外部类静态成员;非静态内部类都可以直接访问。(原因是:内部类有一个外部类名.this的指引)当访问外部类静态成员出现重名时,通过(外部类.静态成员变量名)访问。如:Out.show();
  2. 重名情况下,非静态时,内部类访问自己内部类通过this.变量名。访问外部类通过(外部类.this.变量名)访问,如: Out.this.show();
  3. 在没有重名的情况下,无论静态非静态,内部类直接通过变量名访问外部成员变量。

外部类的访问

  1. 内部类为非静态时,外部类访问内部类,必须建立内部类对象。建立对象方法,如前所述

  2. 内部类为静态时,外部类访问非静态成员,通过(外部类对象名.内部类名.方法名)

     如:new Out().In.function(); 
    
  3. 内部类为静态时,外部类访问静态成员时,直接通过(外部类.内部类名.方法名),如

     如: out.In.function();
    

PS:当内部类中定义了静态成员时,内部类必须是静态的; 当外部静态方法访问内部类时,内部类也必须是静态的才能访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值