java嵌套静态类和内部类_Java中的静态类和内部类

java嵌套静态类和内部类

嵌套类是声明为其他类或作用域成员的类。 嵌套类是更好地组织代码的一种方法。 例如,假设您有一个非嵌套类(也称为顶级类 ), 该类将对象存储在可调整大小的数组中,然后是返回每个对象的迭代器类。 您可以声明迭代器类为可调整大小的数组集合类的成员,而不是污染顶级类的名称空间。 之所以可行,是因为两者密切相关。

在Java中,嵌套类分为静态成员类内部类 。 内部类是非静态成员类,本地类或匿名类。 在本教程中,您将学习如何在Java代码中使用静态成员类和内部类型的三种类型。

避免嵌套类中的内存泄漏

另请参阅与本教程相关的Java技巧,您将在这里学习为什么嵌套类易受内存泄漏的影响

Java中的静态类

在我的Java 101教程Java中的 类和对象中 ,您学习了如何将静态字段和静态方法声明为类的成员。 在Java中的类和对象初始化中 ,您学习了如何将静态初始化器声明为类的成员。 现在,您将学习如何声明静态类 。 正式称为静态成员类 ,这些是嵌套类,您可以使用static关键字在与其他静态实体相同的级别上声明。 这是静态成员类声明的示例:


class C
{
   static int f;

   static void m() {}

   static
   {
      f = 2;
   }

   static class D
   {
      // members
   }
}

本示例介绍了具有静态字段f顶级类C ,静态方法m() ,静态初始化器和静态成员类D 请注意, DC的成员。 静态字段f ,静态方法m()和静态初始化器也是C成员。 由于所有这些元素都属于C类,因此被称为封闭类D类被称为封闭类

机箱和访问规则

尽管它是封闭的,但是静态成员类无法访问封闭类的实例字段并调用其实例方法。 但是,它可以访问封闭类的静态字段并调用其静态方法,甚至是那些声明为private成员。 为了演示,清单1宣称的EnclosingClass与嵌套SMClass

清单1.声明一个静态成员类(EnclosingClass.java,版本1)

class EnclosingClass
{
   private static String s;

   private static void m1()
   {
      System.out.println(s);
   }

   static void m2()
   {
      SMClass.accessEnclosingClass();
   }

   static class SMClass
   {
      static void accessEnclosingClass()
      {
         s = "Called from SMClass's accessEnclosingClass() method";
         m1();
      }

      void accessEnclosingClass2()
      {
         m2();
      }
   }
}

清单1声明了一个名为EnclosingClass的顶级类,其中包含类字段s ,类方法m1()m2()以及静态成员类SMClassSMClass声明类方法accessEnclosingClass()和实例方法accessEnclosingClass2() 。 请注意以下几点:

  • m2()SMClassaccessEnclosingClass()方法的调用需要SMClass. 前缀,因为accessEnclosingClass()被声明为static
  • accessEnclosingClass()能够访问EnclosingClasss场并调用它的m1()方法,即使双方已宣布private

清单2将源代码提供给SMCDemo应用程序类,该类演示了如何调用SMClassaccessEnclosingClass()方法。 它还演示了如何实例化SMClass并调用其accessEnclosingClass2()实例方法。

清单2.调用静态成员类的方法(SMCDemo.java)

public class SMCDemo
{
   public static void main(String[] args)
   {
      EnclosingClass.SMClass.accessEnclosingClass();
      EnclosingClass.SMClass smc = new EnclosingClass.SMClass();
      smc.accessEnclosingClass2();
   }
}

如清单2所示,如果要从封闭的类中调用顶级类的方法,则必须在封闭的类的名称之前加上封闭的类的名称。 同样,为了实例化一个封闭的类,您必须在该类的名称之前加上其封闭类的名称。 然后,您可以按常规方式调用实例方法。

编译清单1和清单2,如下所示:


javac *.java

当您编译包含静态成员类的封闭类时,编译器会为该静态成员类创建一个类文件,该类文件的名称由其封闭类的名称,美元符号字符和静态成员类的名称组成。 在这种情况下,在编译结果EnclosingClass$SMCClass.classEnclosingClass.class

运行应用程序,如下所示:


java SMCDemo

您应该观察以下输出:


Called from SMClass's accessEnclosingClass() method
Called from SMClass's accessEnclosingClass() method

示例:静态类和Java 2D

Java的标准类库是类文件的运行时库,该文件存储已编译的类和其他引用类型。 该库包含许多静态成员类的示例,其中一些可以在java.awt.geom包中的Java 2D几何形状类中找到。 (您将在下一个Java 101教程中了解软件包。)

java.awt.geom中找到的Ellipse2D类描述了一个椭圆,该椭圆由框架矩形根据(x,y)左上角以及宽度和高度范围定义。 以下代码片段显示了此类的体系结构基于FloatDouble静态成员类,它们都是Ellipse2D子类:


public abstract class Ellipse2D extends RectangularShape
{
   public static class Float extends Ellipse2D implements Serializable
   {
      public float x, y, width, height;

      public Float()
      {
      }

      public Float(float x, float y, float w, float h)
      {
         setFrame(x, y, w, h);
      }

      public double getX()
      {
         return (double) x;
      }

      // additional instance methods
   }

   public static class Double extends Ellipse2D implements Serializable
   {
      public double x, y, width, height;

      public Double()
      {
      }

      public Double(double x, double y, double w, double h)
      {
         setFrame(x, y, w, h);
      }

      public double getX()
      {
         return x;
      }

      // additional instance methods
   }

   public boolean contains(double x, double y)
   {
      // ...
   }

   // additional instance methods shared by Float, Double, and other
   // Ellipse2D subclasses
}

FloatDouble类扩展了Ellipse2D ,提供了浮点和双精度浮点Ellipse2D实现。 开发人员使用Float减少内存消耗,特别是因为您可能需要成千上万个这样的对象来构建单个2D场景。 当需要更高的精度时,我们使用Double

您不能实例化抽象的Ellipse2D类,但可以实例化FloatDouble 。 您还可以扩展Ellipse2D来描述基于椭圆的自定义形状。

例如,假设您要引入一个Circle2D类,该类在java.awt.geom包中不存在。 以下代码片段显示了如何使用浮点实现创建Ellipse2D对象:


Ellipse2D e2d = new Ellipse2D.Float(10.0f, 10.0f, 20.0f, 30.0f);

下一个代码片段显示了如何创建具有双精度浮点实现的Ellipse2D对象:


Ellipse2D e2d = new Ellipse2D.Double(10.0, 10.0, 20.0, 30.0);

现在,您可以通过在返回的Ellipse2D引用(例如e2d.getX() )上调用方法来调用FloatDouble声明的任何方法。 以相同的方式,您可以调用FloatDouble通用的任何方法,这些方法在Ellipse2D中声明。 一个例子是:


e2d.contains(2.0, 3.0)

这样就完成了对静态成员类的介绍。 接下来,我们将研究内部类,它们是非静态成员类,本地类或匿名类。 您将学习如何使用所有三种内部类类型。

下载
下载本教程中示例的源代码。 由Jeff Friesen为JavaWorld创建。

内部类,类型1:非静态成员类

您以前在Java 101系列中已经学习了如何将非静态(实例)字段,方法和构造函数声明为class的成员 。 您还可以声明非静态成员类 ,它们是与实例字段,方法和构造函数在同一级别声明的嵌套非静态类。 考虑以下示例:


class C
{
   int f;

   void m() {}

   C()
   {
      f = 2;
   }

   class D
   {
      // members
   }
}

在这里,我们介绍具有实例字段f ,实例方法m() ,构造函数和非静态成员类D顶级类C 所有这些实体都是类C成员,该类将它们包围起来。 但是,与前面的示例不同,这些实例实体与C 实例关联,而不与C类本身关联。

非静态成员类的每个实例都与其封闭类的实例隐式关联。 非静态成员类的实例方法可以调用封闭类的实例方法并访问其实例字段。 为了证明这一点接入,清单3中声明的EnclosingClass与嵌套NSMClass

清单3.用嵌套的非静态成员类声明一个包含类(EnclosingClass.java,版本2)

class EnclosingClass
{
   private String s;

   private void m()
   {
      System.out.println(s);
   }

   class NSMClass
   {
      void accessEnclosingClass()
      {
         s = "Called from NSMClass's accessEnclosingClass() method";
         m();
      }
   }
}

清单3声明了一个名为一个顶层类EnclosingClass与实例字段s ,实例方法m()和非静态成员类NSMClass 。 此外, NSMClass声明实例方法accessEnclosingClass()

由于accessEnclosingClass()是非静态的, NSMClass必须先实例化NSMClass然后才能调用此方法。 该实例化必须通过EnclosingClass一个实例进行,如清单4所示。

清单4. NSMCDemo.java

public class NSMCDemo
{
   public static void main(String[] args)
   {
      EnclosingClass ec = new EnclosingClass();
      ec.new NSMClass().accessEnclosingClass();
   }
}

清单4的main()方法首先实例化EnclosingClass并将其引用保存在局部变量ec 。 在main()方法然后使用EnclosingClass参考作为前缀到new运营商,以实例化NSMClass 。 然后,使用NSMClass引用来调用accessEnclosingClass()

我应该使用“ new”来引用封闭类吗?

很少使用new前缀来引用封闭类。 取而代之的是,您通常会从封闭类的构造函数或其封闭类的实例方法中调用封闭类的构造函数。

清单3和清单4如下编译:


javac *.java

当您编译包含非静态成员类的封闭类时,编译器会为非静态成员类创建一个类文件,该类文件的名称由其封闭类的名称,美元符号字符和非静态成员类的名称组成名称。 在这种情况下,在编译结果EnclosingClass$NSMCClass.classEnclosingClass.class

运行应用程序,如下所示:


java NSMCDemo

您应该观察以下输出:


Called from NSMClass's accessEnclosingClass() method

何时(以及如何)限定“ this”

封闭类的代码可以通过使用封闭类的名称和成员访问运算符( . )限定保留字this来获取对其封闭类实例的引用。 例如,如果内码accessEnclosingClass()需要获得到其基准EnclosingClass例如,它将指定EnclosingClass.this 。 因为编译器会生成代码来完成此任务,所以很少指定此前缀。

示例:HashMap中的非静态成员类

标准类库包括非静态成员类和静态成员类。 在此示例中,我们将查看HashMap类,该类是java.util包中Java Collections Framework的一部分。 HashMap描述了基于哈希表的地图实现,其中包括几个非静态成员类。

例如, KeySet非静态成员类描述了映射中包含的键的基于集合的视图 。 以下代码片段将封闭的KeySet类与其HashMap封闭类相关联:


public class HashMap<K,V> extends AbstractMap<K,V>
                          implements Map<K,V>, Cloneable, Serializable
{
   // various members

   final class KeySet extends AbstractSet<K>
   {
      // various members
   }

   // various members
}

<K,V><K>语法是泛型的示例, 泛型是帮助编译器强制执行类型安全的一组相关语言功能。 我将在即将到来的Java 101教程中介绍泛型。 现在,您只需要知道这些语法可帮助编译器强制执行可存储在映射和键集中的键对象的类型以及可存储在映射中的值对象的类型。

HashMap提供了一个keySet()方法,该方法在必要时实例化KeySet并返回此实例或缓存的实例。 这是完整的方法:

翻译自: https://www.infoworld.com/article/2074000/core-java-classes-within-classes.html

java嵌套静态类和内部类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值