Static Nested Class 和 Inner Class的不同

时间:2021-04-12 22:49:19

Java Nested Class

Java Nested Class 对不少人来说是个让人迷惑的东西, 也是面试中容易考倒人的概念, 笔者最近稍微深入研究了一下这个题目,现将一点心得体会跟大家分享, 希望能对其他人有所帮助, 讲错的地方也欢迎大家指正.


首先先澄清一个相对比较简单的让人模糊概念.

1. Static Nested Class 不是 Inner Class.
Jave Nested Class 分为两大类:1. Static Nested Class;2. Non-static Nested Class.

Non-Static Nested Class 才是真正的Inner Class. 正统的书上是这么区分的, 至于有没有道理, 是个仁者见仁, 智者见智的问题.

在笔者看来, 我觉得如此分没有什么意义, 甚至觉得将 Non-Static Nested Class 归入 Inner Class更合理一些, 因为, Inner Class 跟 其他 class member 和 class method 一样, 都是 outerclass 的一个成员.

但权威们要这么区分, 我等也只能跟风了.

2. Inner Class 的 Scope 问题.
A. 如果 outer class 的 scope 是 public, 那么四个不同的 scope 对 Inner Class 都有不同的意义.
public -- 任何一个其他class 都能看到和使用.

private -- Scope只限于包含这个Inner Class 的 Outer Class 中, 也就说只有 Outer Class 的成员能够看到和使用, 在这个Outer Class 外面看不到这个Inner Class.

package -- 这个是默认行为(default), 只有同一个package 的 才能看到和使用这个 Inner Class.

protected -- 比package稍微多一点, 不同package, 但继承了Outer Class 的 子 类 ( extended class of Outer Class), 也能使用这个 Inner Class.

B. 我们知道主类(CLASS) 的 scope 只能是 public 或者 package, private 和protected 对 主类(CLASS)没有意义. 主CLASS就是供其他CLASS 使用的, 要不给所有的CLASS 用, 要不给同一个 package 的CLASS 用. 其他两个scope没有任何意义, JAVA compiler 禁止主类(Main Class)使用 private和protected.

好,有意思的地方来了, 如果 主类的scope 是 package, 那么作为成员的Inner Class的 scope 该如何定义?
因为主类(Outer Class) 的 scope 是 package, 那么 , 只有同一个package的CLASS可以看到这个Outer Class.

既然如此, 对Inner Class 而言, 只有private 和 默认(defalut package) 有意义.

至于其他的protected, public和package, 对 Inner Class来说, 含义是一样的, 都是 只有 同一个package的其他CLASS 可以 看到和使用这个Inner Class.

在这种情况下, public 和 protected 纯属扯蛋, 除了把人脑子搞乱外,没有任何意义.

我不了解的是, 为什么compiler不象针对Main Class一样, 对scope为package(默认)的CLASS 的 Inner Class 使用相似的限制, 只允许有private和package(默认), 这样可以避免混乱.

private scope的意思没有变, 还是只有同一个OUT CLASS的其他成员才可以看到和使用这个 Inner Class, private only to this "Outer Class".

3. Static-Nested Class
多数情况下, 使用比较多的都是这类CLASS, 因为比较简单, 方便. 学过一些JAVA的人知道, 使用Nested Class
的主要目的有两个:1. 将逻辑上紧密相关的CLASS放在一起(在同一个主CLASS中); 2. 只被一个主CLASS使用的非常局限性辅佐功能, 换句话说, 相当于你要写个HELPER CLASS, 但又只被一个主CLASS使用.

这么做,可以让你的程序更加紧凑, 容易阅读, 也安全.

谈到安全问题, 一般情况下, 我都喜欢将 Static-Nested Class 的scope设计成private. 这样, 外面的CLASS根本看不到我的implementation, 这样我就Hide了我的Logic, 这个叫encapsulation ,是面象程序一个很重要的概念.

如果你是个熟手, 甚至可以更进一步, 将你的Nested Class up-casting成 interface(接口), 人家更不知道你里面是什么东西了.

4. Static-Nested Class 的成员, 既可以定义为静态的(static), 也可以定义为动态的(instance).
Nested Class的静态成员(Method)只能对Outer Class的静态成员(static memebr)进行操作(ACCESS), 而不能Access Outer Class的动态成员(instance member).

而 Nested Class的动态成员(instance method) 却可以 Access Outer Class的所有成员, 这个概念很重要, 许多人对这个概念模糊.

有一个普通的原则, 因为静态方法(static method) 总是跟 CLASS 相关联(bind CLASS), 而 动态方法( (instance method) 总是跟 instance object 相关联, 所以,

静态方法(static method)永远不可以Access跟 object 相关的动态成员(instance member),
反过来就可以, 一个CLASS的 instance object 可以 Access 这个 Class 的任何成员, 包括静态成员(static member).

5. 跟其他普通CLASS成员的区别.

虽然 nested class 跟其他CLASS成员在绝大多数情况下一样, 地位和功能上没有什么不同.

Nested Class 是个类(Class) ,是可以初始化和赋值的(create an instance object), 请注意, Static Nested Class 和 Inner Class( Non-Static Nested Class) 在 语法上是不同的.

举个简单的例子.
class A
{
private int i = 6;
private static String s = "Nested Class";

int getValue()
{
return i;
}

private static class B
{
void setIntValue(int i)
{
new A().i = i;
}
int getIntValue()
{
return new A().i;
}
static void setStrValue(String s)
{
A.s = s;
}
static String getStrValue()
{
return A.s;
}
}
// Be careful , all members of C must not static!!!!!
private class C
{
void setIntValue(int i)
{
new A().i = i;
}
int getIntValue()
{
return new A().i;
}
}

public static void main(String[] args)
{
System.out.println("String value:" + B.getStrValue()); // OK, class access static method
System.out.println("String value:" + new B().getStrValue()); // OK, object access it's static method
System.out.println("Int value:" + new B().getIntValue()); // OK, object access instance method
// System.out.println("Int value:" + B.getIntValue()); // Not OK. class can not access instance method.

// creat an instance object from outside.
A.B myClass = new A.B(); // ok. because B is static member of A.
// If nested class is not static, you have to do this to create an object.
A.C myClass2 = new A().new C(); // OK. create instance of C from an instance of A.
//A.C myClass3 = new A.C(); // ERROR. can not access a instance member from Class.
}
}

请注意CLASS B 和 CLASS C 的区别, 其中B就是常见的Static Nested Class, 而C就是最常见的Inner Class. 定义C 跟 定义 B 是不一样的. 关键要理解
静态的成员只跟CLASS挂钩, 而动态成员必须跟object挂钩.

其中 Inner Class又可分为两类或者三类.

1. 普通的 Inner Class, 在 Outer Class 中定义, 跟 其他成员一样.

2. Local Inner Class. 在 Outer Class 的方法中或者任何一个block{}中定义,
方法中定义的Inner Class, 其 input parameter 必须是 Final 修饰过的变量.

3. 匿名 Inner Class(Anonymous Inner Class). 简单的说就是没有名字.

2 和 3 区别不到, 只有 Syntax上的区别.
Local Inner Class, 顾名思义, 它的SCOPE, 只在 定义它的 那个 block 中, 也就是在
包围它的 {} 中.

其他的使用,跟 普通的 Inner Class 差不多, 就不多说了.

举个简单的例子.

public class AbstracDemo
{
private abstract class MyAbs
{
abstract void print();
int readline()
{
return i;
}
}/*
private class MyAbsDemo extends MyAbs
{
void print()
{
System.out.println("----------:"+readline());
}
int readline()
{
return i;
}
}
*/
public int i = 12;

public static void main(String[] args)
{
AbstracDemo d = new AbstracDemo();
System.out.println("******:"+d.i);
class MyAbsDemo extends MyAbs
{
MyAbsDemo()
{
new AbstracDemo().super();
}
void print()
{
System.out.println("----------:"+readline());
}
int readline()
{
return new AbstracDemo().i;
}
}
MyAbsDemo m = new MyAbsDemo();
System.out.println("******:"+m.readline());
m.print();

}
}

Main当中的MyAbsDemo, 就是个典型的Local Inner Class.