详述有名内部类与匿名内部类
1、定义
①在一个外部类中定义的类称为内部类。例如:
public class Body {
public class Heart{
public void beat() {
System.out.println("正在跳动......");
}
{
Heart heart = this.new Heart();//this可以省略
heart.beat();
}
}
}
②按照是否有类名分为有名内部类和匿名内部类
如何调用内部类中的方法?
在main方法中需要先创建外部类对象,再创建内部类对象最后调用内部类方法。例如:
public class Body {
public class Heart{
public void beat() {
System.out.println("正在跳动......");
}
}
// {
// Heart heart = new Heart();
// heart.beat();
// }
public static void main(String[] args) {
Body body = new Body();
Heart heart = body.new Heart();
heart.beat();
}
}
在非静态代码块中无需创建外部类对象,但是需要在main方法中创建外部类对象才能执行非静态代码块。例如:
public class Body {
public class Heart{
public void beat() {
System.out.println("正在跳动......");
}
}
{
Heart heart = new Heart();
heart.beat();
}
public static void main(String[] args) {
Body body = new Body();
// Heart heart = body.new Heart();
// heart.beat();
}
}
说明:全局有名内部类的使用方式类似于全局变量,局部有名内部类的使用方式类似于局部变量,——它们都有固定的使用范围。
③匿名内部类由于没有类名而不能单独存在,定义匿名内部类的同时必须直接实例化该类,其语法格式如下:
new 父类构造器([参数列表])|接口(){
//匿名内部类类体
}
<1>普通类:匿名内部类实质是普通类的子类
public class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Test {
Mammal mammal = new Mammal() {
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
};
public static void main(String[] args) {
new Test().mammal.move();
}
}
new mammal{…};实质上是上转型对象,变量mammal的类型表面上是父类Mammal,实质上是Mammal类的子类,所以说匿名内部类是普通类的子类。
<2>抽象类:匿名内部类是抽象类的子类
public abstract class Mammal {
public mammal(String name){
}
public abstract void move()
public void breath(){
System.out.println("正在呼吸......");
}
}
public class Test {
Mammal mammal = new Mammal("鲸鱼") {
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
};
public static void main(String[] args) {
new Test().mammal.move();
}
}
程序中Mammal类是一个抽象类,因此匿名内部类是抽象类的子类。
<3>接口:匿名内部类是接口的实现类
public interface IMammal {
void move();
}
public class Test {
IMammal mammal = new IMammal() {
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
};
public static void main(String[] args) {
new Test().mammal.move();
}
}
IMammal是一个接口,匿名内部类实现了接口的一个抽象方法,因此匿名内部类是接口的实现类。
2、匿名内部类的特点
①匿名内部类一定是接口的实现类(该实现类只能实现一个接口)或类(抽象类或普通类)的子类,其中new关键字后面一定是该匿名内部类继承的父类或实现的接口。
②匿名内部类不能自定义构造方法,但是可以通过非静态代码块初始化成员变量。
public class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Test {
int age;
Mammal mammal = new Mammal() {
{
age = 10;
}
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
};
public static void main(String[] args) {
Test sea = new Test();
sea.mammal.move();
System.out.println(sea.age);
}
}
匿名内部类没有类名显然不能自定义构造方法,但却可以通过费静态代码块初始化成员变量,例如程序中的成员变量age。
③匿名内部类不能是抽象类,否则该匿名内部类里的抽象方法将永远不可能被实现。
④可以在匿名内部类中添加新的属性或方法,但这些属性或方法不能通过上转型对象调用,只能被非上转型方式创建的匿名内部类对象所调用。
public class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Test {
Mammal mammal = new Mammal() {
int age;
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
public void breath() {
System.out.println("鲸鱼靠鳃呼吸......");
}
};
public static void main(String[] args) {
Test sea = new Test();
sea.mammal.move();
// sea.mammal.age;//不能通过上转型对象调用新增的属性age
new Mammal() {
int age;
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
public void breath() {
System.out.println("鲸鱼靠鳃呼吸......");
}
}.breath();
}
}
不能通过上转型对象调用新增的属性age,但可以通过非上转型方式创建你内部类对象调用新增的属性或方法。
⑤内部类是一个独立的类:编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+
+
内
部
类
类
名
;
如
果
为
匿
名
内
部
类
,
则
匿
名
内
部
类
字
节
码
文
件
名
为
外
部
类
类
名
+
+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+
+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名++数字;
⑥普通外部类、抽象类和接口可以有内部类(匿名的或有名的)
⑦内部类可以直接定义在类中,也可以定义在方法或代码块中;其中直接定义在外部类中的内部类可以有public、protected、默认的和private四种访问权限修饰(普通外部类、接口和抽象类只能使用public和default修饰),也可以使用static修饰( static不能修饰普通外部类、接口和抽象类);但是定义在方法或代码块中的内部类不能有访问修饰符修饰,也不能有static修饰。
⑧内部类可以访问外部类的所有访问权限的成员变量,例如:
3、访问权限
①访问权限用于限制成员变量或方法能否在另一个类中使用,但因为局部变量已经限定,所以局部变量不能使用访问权限
②外部类或外部类接口只能用public或默认的,但是直接在类中定义的内部类,可以有public~private
③private修饰的成员变量可以在内部类中使用
④如果在内部类中使用局部变量的值,则JDK8.0及以上版本中可以不用final修饰,JDK8.0以前版本必须用final修饰。
public class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Test {
public Mammal mammal = new Mammal() {
int age;
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
public void breath() {
System.out.println("鲸鱼靠鳃呼吸......");
}
};//直接在类中定义的内部类可以用public修饰
public static void main(String[] args) {
Test sea = new Test();
sea.mammal.move();
// sea.mammal.age;
new Mammal() {
int age = 10;
@Override
public void move() {
System.out.println("鲸鱼靠鱼鳍游动......");
}
public void breath() {
System.out.println("鲸鱼靠鳃呼吸......"+age);//jdk8.0及以上版本,在内部类中使用局部变量不需要用final修饰
}
}.breath();
}
}