什么是Java内部类?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是Java内部类?相关的知识,希望对你有一定的参考价值。

内部类

内部类,即类内部的类。类中类。形式如下:

public class Outter{  // 外部类
    class Inner{    // 内部类

    }
}

1. 理解内部类的作用

  1. 内部类可以很好的实现隐藏

    ? 一般的非内部类,是不允许有 private 与protected权限的,但内部类可以

  2. 内部类拥有外围类的所有元素的访问权限

  3. 可是实现多重继承

  4. 匿名内部类优化接口

1)隐藏细节

? 平时我们对类的访问权限,都是通过类前面的访问修饰符来限制的,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以,所以我们能通过内部类来隐藏我们的信息。这看起来没什么作用,但是当内部类实现某个接口的时候,在进行向上转型,对外部来说,就完全隐藏了接口的实现了。

2)可以无条件地访问外围类的所有元素

? 内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员。

3)可以实现多重继承

? 这个特点非常重要,它是内部类存在的最大理由之一。正是由于他的存在使得Java的继承机制更加完善。大家都知道Java只能继承一个类,它的多重继承在我们没有学习内部类之前是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。

4)通过匿名内部类来优化简单的接口实现

? 有了匿名内部类,可以不需要定义一个新的类,而直接通过匿名内部类创建对象。对那些只是用一次的类是非常方便的事情。

2.内部类的分类

? 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类

内部类的共性:

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

  • 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。

  • 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量

1)成员内部类

? 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

技术图片

? 虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:

a) 内部类的基本结构

内部类其实严重破坏了良好的代码结构,但为什么还要使用内部类呢?

因为内部类可以随意使用外部类的成员变量(包括private)而不用生成外部类的对象,这也是内部类的唯一优点

b) 内部类中的变量访问形式

? 内部类在没有同名成员变量和局部变量的情况下,内部类会直接访问外部类的成员变量;若有同名情况时,直接访问会导致内部类中的局部变量将外部类的成员变量覆盖,访问内部类本身的成员变量可用this.属性名,访问外部类的成员变量需要使用Out.this.属性名

c) 创建内部类实例

Out.Inner inner=new Out().new Inner();
//或
Out out=new Out()
Out.Inner inner=out.new Inner()

d) 私有内部类

? 如果一个内部类只希望被外部类中的方法操作,那么可以使用private声明内部类,此时我们必须在Out类里面生成In类的对象进行操作,而无法再使用Out.In in = new Out().new In() 生成内部类的对象

? 也就是说,此时的内部类只有外部类可控制

? 如同是,我的心脏只能由我的身体控制,其他人无法直接访问它

2) 静态内部类

? 如果用static 将内部类静态化,那么内部类就只能访问外部类的静态成员变量,不能直接访问外部类的实例变量、实例方法,只有通过对象引用才能访问。

? 其次,因为内部类被静态化,因此Out.In可以当做一个整体看,可以直接new 出内部类的对象(静态内部类不通过外部类实例进行创建对象)

3) 局部内部类

? 将内部类移到了外部类的方法中,然后在外部类的方法中再生成一个内部类对象去调用内部类方法。局部内部类和成员内部类的区别在于局部内部类的访问仅限于方法内

如果此时我们需要往外部类的方法中传入参数,那么外部类的方法形参必须使用final定义类

至于final在这里并没有特殊含义,只是一种表示形式而已

局部内部类:像局部变量一样,不能被public, protected, private和static修饰。jdk1.8 +可以不加 final

4) 匿名内部类

? 匿名内部类:定义类的最终目的是创建一个类的实例,但是如果某个类的实例只是用一次,则可以将类的定义与类的创建,放到与一起完成,或者说在定义类的同时就创建一个类 , 以这种方法定义的没有名字的类成为匿名内部类。

技术图片

声明和构造匿名内部类的一般格式如下:

 new ClassOrInterfaceName(){
/*类体*/
 }

? ①匿名内部类可以继承一个类或实现一个接口,这里的ClassOrInterfaceName是匿名内部类所继承的类名或实现的接口名。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果实现了一个接口,该类是Object类的直接子类,匿名类继承一个类或实现一个接口,不需要extends和implements关键字。

? ②由于匿名内部类没有名称,所以类体中不能定义构造方法,由于不知道类名也不能使用关键字来创建该类的实例。实际上匿名内部类的定义、构造、和第一次使用都发生在同样一个地方。此外,上式是一个表达式,返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量,如:

 TypeName obj=new Name(){
   /*此处为类体*/
  }

同样,也可以将构造的对象作为调用的参数。例:

someMethod(new Name(){
   /*此处为类体*/  
});

局部内部类:像局部变量一样,不能被public, protected, private和static修饰。Jdk1.7中只能访问方法中定义的final类型的局部变量。

枚举

java枚举类可以简单地理解为一种特殊的java类 。通过关键字 enum实现,自动继承自Enum类(枚举类)

public enum Color{
    RED,GREEN, YELLOW;
}
public class Test{
    public static void main(String[] args){
        System.out.println(Color.RED);
    }
}

其中每一个数据,都是枚举类的实例

作为类型安全的常量

可以实现接口拓展功能

将枚举数据与它的常量关联起来

将枚举数据和它的行为关联起来(特定于常量的方法实现)

以上是关于什么是Java内部类?的主要内容,如果未能解决你的问题,请参考以下文章

片段内部静态类和gradle问题

java开发的项目案例,大厂内部资料

java内部类

Java 静态内部类作用?

# Java 常用代码片段

# Java 常用代码片段