1.前言
本篇来详细介绍Java语法中的内部类知识,内部类在数据结构中应用广泛,不废话了,开干👇。
2.内部类的概念
当一个事物的内部还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类,就比如链表的结点在类中的实现。
在 Java 中,可以将一个类定义在另一个类或者一个方法的内部。
public class A {
class B{
//........
}
}
其中A为外部类,B为内部类,只要是一个类中有另一个类,则这个类叫内部类。
3.内部类的分类
内部类有如下几种:
- 成员内部类:
- 实例内部类:未被static修饰的成员内部类
- 静态内部类:被static修饰的成员内部类
- 局部内部类
- 匿名内部类
3.1 实例内部类
未被static修饰的 成员内部类 叫实例内部类,其形式:
public class OutClass {
//......
//实例内部类
class InnerClass{
}
}
- 实例内部类 实例化 的方式:
public class Main {
public static void main(String[] args) {
//第一种方式:先将外部类对象先创建出来,然后再创建实例内部类对象
OutClass outClass = new OutClass();
OutClass.InnerClass innerClass = outClass.new InnerClass();
//第二种方式:直接创建,其实还是要先将外部类对象先创建出来
OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
}
}
- 实例内部类访问外部类的成员
1. 在实例内部类中可以直接访问外部类中的任意访问限定符修饰的成员。
public class OutClass {
//不同修饰符的变量
private int a = 10;
protected int b= 10;
public int c = 10;
int d = 10;
private void OutMethodA(){
System.out.println("我是OutMethodA!!!");
}
private static void OutMethodB(){
System.out.println("我是OutMethodB!!!");
}
//实例内部类
class InnerClass{
//在实例内部类中可以直接访问外部类中的任意访问限定符修饰的成员
public void InnerMethod(){
a = 20;
b = 20;
c = 20;
d = 20;
System.out.println("a = " + a + " b = " + b +" c = " + c + " d = " + d);
OutMethodA();
OutMethodB();
}
}
}
public class Main {
public static void main(String[] args) {
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
innerClass.InnerMethod();
}
}
结果:
a = 20 b = 20 c = 20 d = 20
我是OutMethodA!!!
我是OutMethodB!!!
2.如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的。
public class OutClass {
int d = 10;
private void A(){
System.out.println("我是OutClass的A!!!");
}
//实例内部类
class InnerClass{
int d = 200000;
private void A(){
System.out.println("我是InnerClass的A!!!");
}
public void InnerMethod(){
System.out.println("d = "+d);
A();
}
}
}
public class Main {
public static void main(String[] args) {
//第二种方式:直接创建
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
innerClass.InnerMethod();
}
}
结果:
d = 200000
我是InnerClass的A!!!
3.如果要访问外部类同名成员时候用:外部类名称.this.同名成员名字
public class OutClass {
int d = 10;
//实例内部类
class InnerClass{
int d = 200000;
public void A() {
System.out.println("d = " + OutClass.this.d);
}
}
}
------------------------------------------------------------------
public class Main {
public static void main(String[] args) {
//第二种方式:直接创建
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
innerClass.A();
}
}
结果:
d = 10
3.2 静态内部类
被static修饰的 内部成员类 称为静态内部类,形式如下👇。
public class OutClass {
//静态内部类
static class InnerClass{
//......
}
}
- 静态内部类的实例化方式:
//静态内部类的实例化方式
OutClass.InnerClass innerClass = new OutClass.InnerClass();
这里创建静态内部类对象时,不需要先创建外部类对象。
- 静态内部类访问外部类的成员:
1.只能访问外部类的静态成员
public class OutClass {
public int a = 1;
public static int b =2;
//静态内部类
static class InnerClass{
public void A(){
System.out.println(a);
System.out.println(b);
}
}
}
---------------------------------------------------------
public class Main {
public static void main(String[] args) {
//静态内部类的实例化方式
OutClass.InnerClass innerClass = new OutClass.InnerClass();
innerClass.A();
}
}
结果:
2.由于只能引用外部的静态成员,当外部与内部的静态成员同名时,访问外部类同名成员时候用:外部类名称.同名成员名字
public class OutClass {
public static int b =2;
//静态内部类
static class InnerClass{
public static int b =100;
public void A(){
//访问的是外部的a
System.out.println(OutClass.b);
//访问的是内部的a
System.out.println(b);
}
}
}
结果:
2
100
3.3 局部内部类
是定义在{}
中的类为局部内部类,这种用法几乎用不到,简单了解一下就行了。
public class OutClass {
//可以定义在构造方法中
OutClass(){
class InnerClass{
}
}
//可以定义在静态方法中
public static void A(){
class InnerClass{
}
}
//可以定义在普通方法中
public void B(){
class InnerClass{
}
}
//可以定义在代码块中
{
class InnerClass{
}
}
}
- 局部内部类不能被
public、private
等访问修饰符修饰:
- 只能在该
{}
中使用,其他位置都不能用:
public class OutClass {
//定义在静态方法中
public void A(){
class InnerClass{
public int a = 10000;
}
//只能在该方法体内部使用,其他位置都不能用
InnerClass innerClass = new InnerClass();
System.out.println(innerClass.a);
}
}
--------------------------------------------------------------------
public class Main {
public static void main(String[] args) {
OutClass outClass = new OutClass();
outClass.A();
}
}
结果:
10000
3.4 匿名内部类
匿名类是不能有名字的类,它们不能被引用,只能在创建时用 new 语句来声明它们。那么它是怎么用的呢?
假如有一个抽象类,里面有一个抽象方法,我们知道要用一个类来继承这个抽象类并重写方法才能使用。如下:
abstract class Test{
public abstract void method1();
}
class Tool extends Test{
//重写
public void method1() {
System.out.println("我是重写之后的method1()方法!!!");
}
}
public class OutClass {
public static void main(String[] args) {
Test test = new Tool();
test.method1();
}
}
结果:
那如果有的时候我想只用一次 method1()
方法,这时我还用一个“工具”类来继承的话就显得太麻烦了。那么匿名内部类就能解决这个问题:
abstract class Test{
public abstract void method1();
}
public class OutClass {
public static void main(String[] args) {
Test test = new Test() {
//必须重写所有的抽象方法。
public void method1() {
System.out.println("我是重写之后的method1()方法!!!");
}
};
//调用method1()
test.method1();
}
}
结果:
这里的匿名内部类主体是 new Test() {};
,它没有名字,并且要有分号。
匿名内部类的对象类型相当于是当前new
的那个的类型的子类型。做一个类比:你可以把这里的new Test()
看成是上一个例子中的Tool
的实例, new Test() {};
中的{}
放着的就是重写的方法。