详述有名内部类与匿名内部类

详述有名内部类与匿名内部类

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();
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值