支持使用静态成员类而不是非静态类

Posted lillill

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了支持使用静态成员类而不是非静态类相关的知识,希望对你有一定的参考价值。

 

嵌套类(nested class)是在另一个类中定义的类。 嵌套类应该只存在于其宿主类(enclosing class)中。 如果一个嵌套类在其他一些情况下是有用的,那么它应该是一个顶级类。 有四种嵌套类: 静态成员类,非静态成员类,匿名类和局部类。 除了第一种以外,剩下的三种都被称为内部类(inner class)。 这个条目告诉你什么时候使用哪种类型的嵌套类以及为什么使用。

静态成员类是最简单的嵌套类。 最好把它看作是一个普通的类,恰好在另一个类中声明,并且可以 访问所有宿主类的成员,甚至是那些被声明为私有类的成员。 静态成员类是其宿主类的静态成员,并遵 循与其他静态成员相同的可访问性规则。 如果它被声明为 private ,则只能在宿主类中访问,等等。 静态成员类的一个常见用途是作为公共帮助类,仅在与其外部类一起使用时才有用。 例如,考虑一 个描述计算器支持的操作的枚举类型(详见第 34 条)。 Operation 枚举应该是 Calculator 类的 公共静态成员类。 Calculator 客户端可以使用 Calculator.Operation.PLUS 和 Calculator.Operation.MINUS 等名称来引用操作

非静态成员类实例和其宿主实例之间的关联是在创建成员类实例时建立的,并且之后不能被修改。 通常情况下,通过在宿主类的实例方法中调用非静态成员类构造方法来自动建立关联。 尽管很少有可能 使用表达式 enclosingInstance.new MemberClass(args) 手动建立关联。 正如你所预料的那样, 该关联在非静态成员类实例中占用了空间,并为其构建添加了时间开销

非静态成员类的一个常见用法是定义一个 Adapter [Gamma95],它允许将外部类的实例视为某个 不相关类的实例。 例如, Map 接口的实现通常使用非静态成员类来实现它们的集合视图,这些视图由 Map 的 keySet , entrySet 和 values 方法返回。 同样,集合接口(如 Set 和 List )的 实现通常使用非静态成员类来实现它们的迭代器:

 
 
 
?x
 
 
 
 
// Typical use of a nonstatic member class
public class MySet<E> extends AbstractSet<E> {
... // Bulk of the class omitted
@Override
public Iterator<E> iterator() {
return new MyIterator();
} p
rivate class MyIterator implements Iterator<E> {
...
}
}
 

如果你声明了一个不需要访问宿主实例的成员类,总是把 static 修饰符放在它的声明中,使它成为 一个静态成员类,而不是非静态的成员类。 如果你忽略了这个修饰符,每个实例都会有一个隐藏的外 部引用给它的宿主实例。 如前所述,存储这个引用需要占用时间和空间。 更严重的是,并且会导致即 使宿主类在满足垃圾回收的条件时却仍然驻留在内存中(详见第 7 条)。 由此产生的内存泄漏可能是灾 难性的。 由于引用是不可见的,所以通常难以检测到

私有静态成员类的常见用法是表示由它们的宿主类表示的对象的组件。 例如,考虑将键与值相关联 的 Map 实例。 许多 Map 实现对于映射中的每个键值对都有一个内部的 Entry 对象。 当每个 entry 都与 Map 关联时, entry 上的方法 ( getKey , getValue 和 setValue ) 不需要访问 Map 。 因此,使用非静态成员类来表示 entry 将是浪费的:私有静态成员类是最好的。 如果意外地 忽略了 entry 声明中的 static 修饰符, Map 仍然可以工作,但是每个 entry 都会包含对 Map 的引用,浪费空间和时间

正如你所期望的,一个匿名类没有名字。 它不是其宿主类的成员。 它不是与其他成员一起声明, 而是在使用时同时声明和实例化。 在表达式合法的代码中,匿名类是允许的。 当且仅当它们出现在非 静态上下文中时,匿名类才会封装实例。 但是,即使它们出现在静态上下文中,它们也不能有除常量型 变量之外的任何静态成员,这些常量型变量包括 final 的基本类型,或者初始化常量表达式的字符串 属性[JLS,4.12.4]。 匿名类的适用性有很多限制。 除了在声明的时候之外,不能实例化它们。 你不能执行 instanceof 方法测试或者做任何其他需要你命名的类。 不能声明一个匿名类来实现多个接口,或者 继承一个类并同时实现一个接口。 匿名类的客户端不能调用除父类型继承的成员以外的任何成员。 因 为匿名类在表达式中出现,所以它们必须保持简短 —— 约十行或更少 —— 否则可读性将受到影响。

局部类是四种嵌套类中使用最少的。 一个局部类可以在任何可以声明局部变量的地方声明,并遵守 相同的作用域规则。 局部类与其他类型的嵌套类具有共同的属性。 像成员类一样,他们有名字,可以 重复使用。 就像匿名类一样,只有在非静态上下文中定义它们时,它们才会包含实例,并且它们不能包 含静态成员。 像匿名类一样,应该保持简短,以免损害可读性

有四种不同的嵌套类,每个都有它的用途。 如果一个嵌套的类需要在一个方法之外可 见,或者太长而不能很好地适应一个方法,使用一个成员类。 如果一个成员类的每个实例都需要一个对 其宿主实例的引用,使其成为非静态的; 否则,使其静态。 假设这个类属于一个方法内部,如果你只需 要从一个地方创建实例,并且存在一个预置类型来说明这个类的特征,那么把它作为一个匿名类;否 则,把它变成局部类

以上是关于支持使用静态成员类而不是非静态类的主要内容,如果未能解决你的问题,请参考以下文章

Java中的静态和枚举

C#基础——静态成员,static关键字

单例模式

为啥片段类应该是公开的?

关于C++静态成员函数访问非静态成员变量的问题

finalsttic关键字,访问控制符