目录
1.内部类的引出与定义
如图所示,如果把我们的身体看作一个整体的话,那么它除了自己的属性(身高、体重)外,还包含很多的器官。而这些器官又可以分别单独的看做一个整体并且拥有各自的属性,但是却不能离开身体独立存在。如果把身体看做是一个类的话,那么这些器官便是这个类的内部类。
由此,我们便可得出内部类的定义:内部类就是在一个类内部进行其他类结构的嵌套操作。
2.使用内部类的好处
(1)内部类可以很好的实现隐藏。 一般的非内部类,是不允许有 private 与protected权限的,但内部类可以。
(2)内部类拥有外部类的所有元素的访问权限。
(3)通过多个内部类继承不同的父类可以实现多继承。
(4)可以避免修改接口而实现同一个类中两种同名方法的调用。
3.内部类的使用
(1)成员内部类:定义在类中的内部类
①首先,我们按照上面的例子定义一个成员内部类。
//身体
public class Body {
double weight;//体重
double height;//身高
//心脏
class Heart{
int rate;//心率
}
//大脑
class Brain{
int iq;//智力
}
//胃
class Stomach{
double ph;//PH值
}
//间接通过方法实例化器官
public void createHeart(int rate){
Heart heart = new Heart();
heart.rate = rate;
System.out.println(heart.rate);
}
}
②下面我们按照身体的逻辑对这个类进行实例化。
public static void main(String[] args) {
//间接实例化一个心脏(通过body的方法实例化)
Body body = new Body();
body.createHeart(110);
//直接实例化一个心脏
//外部类.内部类(先有身体才能在其中创建心脏)
Body.Heart heart = new Body().new Heart();
heart.rate = 100;
System.out.println(heart.rate);
}
结果为:
110
100
③若此时把心脏类加上static关键字变成一个静态类,那么这个类就不再属于某个身体的对象而是属于整个身体类,可以理解为很多个身体共用一个心脏,因此它的实例化方式也就会变为静态的。
//心脏
static class Heart{
int rate;//心率
}
//静态内部类属于外部类,不属于对象,因此不用先创建外部类
Body.Heart heart1 = new Body.Heart();
需要注意的是:
静态类中只能使用外部类的静态属性和静态方法,不可以用外部类的非静态属性和方法;
静态内部类属于类而不属于对象,因此创建时无需实例化外部类。
(2)局部内部类:定义在方法体中的内部类
public static void main(String[] args) {
//一个局部内部类
//作用范围只在此方法之中
//此方法结束立即死亡
class Inner{
int id;
int name;
public void method(){
System.out.println("局部内部类的方法");
}
}
Inner inner = new Inner();
inner.method();
}
结果:
局部内部类的方法
需要注意的是:
①局部内部类的作用范围仅在方法内,方法结束立刻死亡;
②不能用任何的访问修饰符修饰局部内部类;
普通类只能用public、(default)修饰;
只有成员内部类才能用所有四个访问修饰符。
③局部内部类如果希望访问方法的局部变量,那么这个局部变量必须是有效final的(即一次赋值,不再改变)。
public static void main(String[] args) {
//局部变量存在于栈中,方法结束立即消失
final int num = 10;//final关键字可省略(Java7以后)
class Inner{
public void method(){
System.out.println(num);
}
}
//内部类实例化对象存在于堆中,直到垃圾回收时才消失
Inner inner = new Inner();
inner.method();
/*
因此inner存在时间长于num
当num消失时inner并不会立即消失,
因此存放在inner中的num并不是栈中的num,
而是在inner中复制了num的值,
即使在方法运行时改变了num的值,inner中仍是10,
因此此时的num只能为final(常量)
*/
}
(3)匿名内部类:匿名内部类属于局部内部类,但是并没有去引用
①使用场景:
对于接口的实现类(父类的子类),如果只需要使用唯一一次,那么专门去定义这个实现类(子类)就显得没有必要,杀鸡焉用牛刀,此时我们就可以在方法中省去定义步骤直接使用匿名内部类。
②使用方式:
首先我们定义一个接口。
public interface Interface {
public void method();
}
下面我们用匿名内部类的方式实现这个接口。
public static void main(String[] args) {
//相较于多态的写法,匿名内部类直接new了父类对象,并重写父类对象的方法
Interface anInterface = new Interface() {
@Override
public void method() {
System.out.println("接口匿名内部类的方法重写");
}
};//注意此处的分号,它是一次代码执行的结束
anInterface.method();
}
如果匿名内部类实例化的对象只是使用唯一一次并且只调用其中的一个方法,我们可以直接把此对象写成匿名对象。
new Interface() {
@Override
public void method() {
System.out.println("接口匿名内部类的方法重写");
}
}.method();
此处需要注意的是,【匿名内部类】与【匿名对象】不是一回事!!!要注意区分。