目次
JAVA 类总结
顶级类与嵌套类
嵌套类字节码文件命名
静态嵌套类
内部类
遮蔽(Shadowing)
局部内部类
匿名类

JAVAクラスの概要

Mar 26, 2017 pm 03:59 PM

JAVA 类总结

最近看了遍java内部类相关的一些内容,做一些总结。与个人博客 zhiheng.me 同步发布,标题: JAVA 类总结。

顶级类与嵌套类

定义在某个类(或接口,下同)内部的类,称为嵌套类(nested class),相应的,其所在的类称之为该类的外围类(enclosing class)或包裹类。

非嵌套类称为顶级类(top-level class),一个 .java 文件中可以有若干个顶级类(含抽象类和接口),但只能有一个被 public 修饰的类,且该类必须和 .java 文件同名。

顶级类的访问修饰符只能是 public 和包访问权限(默认权限,无修饰符)。

嵌套类可看作是外围类的一个成员,因此其修饰符可以是 public 、protected 、包访问权限和 private 。

嵌套类没有层次限制,可以在嵌套类里面在定义类,成为嵌套类中的嵌套类。

嵌套类分为两种,一种是静态的(用 static 关键字修饰)称为静态嵌套类(static nested class);一种是非静态的,称为内部类(inner class)。

注:在《Think in Java》一书中,作者将内部类定义为“将一个类定义在另一个类的定义内部,则这个类就是内部类”,因此,他将静态嵌套类视为内部类的一种。而本文使用了 java 官方文档中的定义。

内部类一般直接定义在外部类(outer class)中,就像该类的一个成员一样,我们把这样的内部类称为成员内部类(member inner class)。即不在构造器、方法、语句块中定义的内部类为成员内部类。

除成员内部类外还有另外两种较特殊的内部类:局部内部类(local class)和匿名内部类(anonymous class)。

嵌套类字节码文件命名

嵌套类经编译后会自动生成独立的字节码文件(.class),其命名格式:

外部类名称+\$+[该种类同名类中该类顺序]+[内部类名称]

以下代码(文件名:Outer.java)中含有静态类 Static 、成员内部类 Inner 、局部类 Local 、实现 Anonymous 接口的匿名类以及定义在该源文件中的接口 Anonymous 。

package thinkinjava;
 
public class Outer {
 
    public static class Static{}
 
    public class Inner {}
 
    {
        class Local{};
    }
 
    Anonymous anonymous = new Anonymous(){};
}
 
interface Anonymous {}
ログイン後にコピー

编译后形成了如下6个 .class 字节码文件。顶级类 Outer 和 Anonymous 都被编译成同名的 class 文件,静态嵌套类 Static 和成员内部类 Inner 被编译成了 Outer\$Static.class 和 Outer\$Inner.class ,因为成员类不能同名,所以也就没有同名类顺序。局部类 Local 编译后的文件名是 Outer\$1Local.class ,因为 Outer 类中只有一个名为 Local 的局部类,因此,其顺序是1。匿名类没有名称,所以编译后的文件名是 Outer\$1.class ,1表示该类是 Outer 类中第一个匿名类。

Anonymous.class
Outer$1.class
Outer$1Local.class
Outer$Inner.class
Outer$Static.class
Outer.class
ログイン後にコピー

静态嵌套类

public class OuterClass{
    public static class NestClass{}
}
ログイン後にコピー

静态嵌套类因为是静态的,因此从本质上来说它和外部类的关系更像是类与包(package)的关系。在其他类中引用使用的时候需要加上外部类限定: OuterClass.NestClass

  1. 与静态方法一样,静态嵌套类中不能访问外部类的非静态成员和非静态方法(不管是public还是private的);

  2. 静态嵌套类的实例化(instantiate)无需事先实例化外部类,因为静态嵌套类是与外部类直接相关联的,而非与外部类的实例(instance)相关联。

内部类

内部类是非静态的,因此内部类是与外部类的实例相关联的。在实例化内部类时,必须先行实例化外部类,再通过外部类的实例来创建内部类的实例:

OuterClass outObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
ログイン後にコピー
  1. 内部类中不能有 static 关键字修饰的静态成员(块、字段、方法、接口等),除非该成员是静态常量。所以,内部类中的静态成员必须是同时使用 final 关键字修饰的字段。

  2. 内部类可以访问外部类的任何成员(包括构造器),不管是公有的还是私有的,静态的还是非静态的。同样,外部类也可以访问到内部类的所有成员。

遮蔽(Shadowing)

定义在内部类或成员方法内的字段或参数,如果和外部作用域内的某个成员变量定义同名,那么外部的定义将被遮蔽,此时无法在内部作用域内仅通过名字访问到外部的成员。以下是摘自 Java Tutorial 中的一个例子:

public class ShadowTest {
 
    public int x = 0;
 
    class FirstLevel {
 
        public int x = 1;
 
        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }
 
    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}
// 输出如下
// x = 23
// this.x = 1
// ShadowTest.this.x = 0
ログイン後にコピー

局部内部类

局部类是定义在某个块(block)中的类。即定义在构造器、方法、循环体、分支结构(if 子句)中的类。

  1. 同局部变量,局部类不能用public,private,protected,static修饰,但可以被final或者abstract修饰。

  2. 局部类是内部类,因此可以访问其外部类的成员。但局部类的作用域在块内,所以外部类无法访问到局部内部类。

局部类属于块的作用域,因此可以访问局部变量(包括形参),但是只能访问用 final 修饰的局部变量。

在 Java SE 8 之后,局部类可以访问 effectively final 的局部变量和非 final 的形参了,effectively final 的变量没有 final 修饰但在初始化后从未改变过值。 “A variable or parameter whose value is never changed after it is initialized is effectively final”

匿名类

匿名类,顾名思义就是没有名称的类,没有名称也就无法在其他地方引用和实例化,当然也就没有构造器。匿名类在定义的同时会实例化本身(匿名类只实例化这一次)。

匿名类的定义从形式上看更像是一种表达式,也就是类的定义出现在一个表达式中。从语法形式上看,匿名类的定义像是调用了一个构造器。以下是几种匿名类的例子:

public class Test {
    InterfaceA a = new InterfaceA() {};//成员匿名类
    public static void main(String[] args){
        InterfaceA a = new InterfaceA() {};//局部匿名类
        //以上两种是通过实现接口实现匿名类,称为接口式匿名类,也可以通过继承类实现
        Test test = new Test(){};//继承式匿名类
        //还可以是位于参数上
        new Thread(new Runnable() {
            @Override
            public void run() {
            }
        }).start();//属于局部匿名类一种
    }
    private interface InterfaceA{}
}
ログイン後にコピー

匿名类不能使用任何关键字和访问控制符,匿名类和局部类访问规则一样,只不过内部类显式的定义了一个类,然后通过new的方式创建这个局部类实例,而匿名类直接new一个类实例。

以上がJAVAクラスの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットな記事タグ

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Javaの平方根

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Javaの完全数

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーター

Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

Javaのアームストロング数

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

ジャワのウェカ

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Javaのスミス番号

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

Java Springのインタビューの質問

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8 Stream Foreachから休憩または戻ってきますか?

See all articles