详解 内部类 —— 内部类 与 匿名内部类

在本人之前的篇博文《详解 抽象类》中,讲到的对抽象类的使用手段是:
1.继承抽象类,并且实现其抽象方法,产生新类(子类)
2.实例化这个子类,完成抽象方法的实现。
但是,对抽象类的使用手法并不是唯一的,还有一种更直接、更犀利的实现手段,但这种手段是建立在内部类的知识基础上的,所以,在讲这种手段前,本人有必要先讲解一下 内部类 这个知识点。
并且本人谈到:这篇博文中所要讲解的知识,将会在本篇博文中提现到作用。
那么,废话不多说,现在就开始本篇博文主题的讲解吧!


内部类:

定义: 把类定义在其他类的内部,这个类就被称为内部类。

内部类 和 外部类 之间的访问特点

访问特点

  • 内部类可以直接访问外部类的成员,包括私有。
  • 外部类要访问内部类的成员,必须创建对象。

而我们可以根据内部类的位置,对内部类分为如下两类:

按照内部类位置分类

  • 成员位置:
    成员位置定义的类,被称为成员内部类
  • 局部位置:
    局部位置定义的类,被称为局部内部类

而对于这两种内部类,他们的修饰符也略有差别:
首先是 成员内部类

成员内部类的修饰符:

  • private 为了保证数据的安全性
  • static 为了方便访问数据

注意事项:

  1. 静态内部类访问的外部类数据必须用静态修饰
  2. 成员方法可以是静态的也可以是非静态

接下来是局部内部类

final修饰

  • 因为局部变量随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量
    为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值

注意事项:
JDK1.8之后,final会默认加上,不需要手动去加

那么,我们如何在 外部类中 直接访问内部类的成员呢?

外部类访问内部类成员的手段:
格式:

  1. 一般格式:
    外部类名.内部类名 对象名 = 外部类对象.内部类对象;
  2. 成员内部类静态修饰后:
    外部类名.内部类名 对象名 = new 外部类名.内部类名();

那么,本人还是通过一段代码来讲解内部类的使用方法:
OuterClass类:

package com.mec.about_inner.core;

public class OuterClass {
	
	private int privateMember;
	protected int protectedMember;
	public int publicMember;
	
	public OuterClass() {
		//这里定义三种不同的权限修饰符的成员
		privateMember = 1;
		protectedMember = 2;
		publicMember = 3;
	}
	
	//这里定义三种不同的权限修饰符的方法
	private void privateFun() {
		System.out.println("privateMember:" + privateMember);
	}
	
	protected void protectedFun() {
		privateFun();
		System.out.println("protectedMember:" + protectedMember);
	}
	
	public void publicFun() {
		privateFun();
		System.out.println("publicMember:" + publicMember);
	}
	
	public class InnerClass {
		private int innerMember;
		
		public InnerClass() {
			innerMember = 4;
		}
		
		private void InnerFun() {
			privateMember++;
			protectedMember++;
			publicMember++;
			
			privateFun();
			protectedFun();
			publicFun();
			System.out.println("innerMember:" + innerMember);
		}
		
	}
	
	//外部类可以定义其内部类对象的成员
	private InnerClass innerObject;
	
	public void fun() {
		//外部类可以实例化该成员,并且可根据内部类的对象,引用内部类的成员和方法
		innerObject = new  InnerClass();
		innerObject.InnerFun();
		System.out.println(innerObject.innerMember++);
	}
	
}

上面代码的注意点,本人已经在注释中写清楚了,所以在这里不再进行详细解释。
在这里本人只提醒一点:
内部类中的任何成员和方法,都可以被直属外部类调用。
外部类中的任何成员和方法,都可以被其所包含的内部类调用。
但是,在这里,本人要展示下bin目录下所生成的*.class文件:

在这里插入图片描述可见,这里额外生成了一个名为“OuterClass$InnerClass”的类,而这个名称,就表明这个类是在OuterClass类中的内部类InnerClass类。

那么,为什么本人在讲解直接使用抽象类的手段前,要讲解内部类呢?
那是因为,这种直接使用抽象类的手段,被称为“匿名内部类

匿名内部类:

首先,本人来解释下,什么是匿名内部类:

定义:就是局部内部类简化写法

匿名内部类也存在着特定的格式

格式:
new 类名或者接口名(){
重写方法;
} ;

根据这个格式,我们大概能够看的出来:
所谓的匿名内部类 是一个继承了该类 或者 实现了该接口 的 子类匿名对象

本人在这里再提醒一点:
在匿名内部类中出现的this,代表的是该匿名内部类 这个对象

现在,本人来给一个抽象类:
Bird类:

package com.mec.about_inner.core;

public abstract class Bird {
	private String name;
	
	public Bird(String name) {
		this.name = name;
	}
	
	public abstract String cry();
	
	public void print( ) {
		System.out.println("(" + name + ")" + "的叫声:" + cry());
	}
	
}

接下来,本人通过Test类,来展示直接使用抽象类的手段:
Test类:

package com.mec.about_inner.core;

public class Test {

	public static void main(String[] args) {
		//第一种手段的展示
		Bird lark = new Bird("百灵鸟") {
			@Override
			public String cry() {
				return "百灵既洽,祚我王国";
			}
		};
		
		lark.print();
		
		//第二种手段的展示
		new Bird("乌鸦") {
			@Override
			public String cry() {
				return "月影笼缁衣, 寒鸦枝上啼";
			}
		}.print();
		
		//第三种手段的展示
		new Bird("黄鹂") {
			public Bird fun() {
				System.out.println("这里是第三种调用抽象类的方法");
				return this;
			}
			
			@Override
			public String cry() {
				return "烟红露绿晓风香,燕舞莺啼春日长";
			}
		}.fun().print();
	}

}

在这里插入图片描述
这里对上面的代码做一些解释:
这三种手段,其实是一种手段,都利用了如下模式:

new 抽象类构造方法() {
	抽象类的所有抽象方法的实现;
}

剩下的操作,都是建立于这中方式的基础上才产生的,但是本质是一样的。

下面,本人再来展示下现在的bin目录下的*.class文件:
在这里插入图片描述可以看到,多生成了三个内部类,但是这三个内部类却没有有意义的名称,所以,这三个类被称为“匿名内部类”。

本人在这里做一下说明:
一个 匿名内部类 最好对应 一种 抽象方法的实现,这样使得我们的工具的功能更加单一化,在修改时不容易导致其他工具出错。

但是本人在这里想要提醒一句话,到了这里,Java的“工具化”思想想必是非常突出的了,所以,同学们时刻要注意无论Java学习到哪种程度,“工具化”思想都要时刻铭记,只有这样,才能真正地掌握Java地精髓!

原文地址:https://www.cnblogs.com/codderYouzg/p/12418349.html