[Java]内部クラス(Inner Class)

11363 ワード

内部クラスまたはネストクラス(nested class)は、他のクラスの内部に定義されたクラスです.2つの独立したクラス:
public class Test {
    //...
}
public class A {
    //...
}
ATestの内部クラスであり、クラスATest$A.classにコンパイルされる.
public class Test {
    // ...
    // Inner class
    public class A {
        // ...
    }
}

内部クラス:
// OuterClass.java: inner class demo
public class OuterClass {
	private int data;
	/** A method in the outer class */
	public void m() {
	    // Do something
	}
	// An inner class
	class InnerClass {
		/** A method in the inner class */
		public void mi() {
			// Directly reference data and method
			// defined in its outer class
			data++;
			m();
		}
	}
}
  • 内部クラスは、OuterClassName$InnerClassName.classのクラスとしてコンパイルされる.
  • 内部クラスは、その外部クラスに定義されたデータおよびメソッドを参照することができるので、外部クラスのオブジェクトの参照を内部クラスの構造関数に渡す必要はありません.このため、内部クラスはプログラムを簡単に、コンパクトにすることができます.
  • 内部クラスは、クラスのメンバーと同じ可視性ルールに合致する可視性修飾子を使用することができる.
  • 内部クラスは静的と定義でき、外部クラス名を使用して静的内部クラスにアクセスでき、静的内部クラスは外部クラスの非静的メンバーにアクセスできません.
  • 外部クラスの内部には、通常、内部クラスのオブジェクトが作成されます.ただし、他のクラスの内部に静的クラスオブジェクトを作成することもできます.内部クラスが静的でない場合は、まず外部クラスのインスタンスを作成し、次の構文を使用して内部クラスのオブジェクトを作成する必要があります.
  • OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    
  • 内部クラスが静的である場合、次の構文を使用して内部クラスオブジェクトを作成します.
  • OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
    

    内部クラスを使用する理由の1つは、コードの整理を容易にするために、複数の関連するクラスを1つのプライマリクラスの内部に配置することです.
    Stackoverflowの、翻訳したくない、直接copy paste:
    In common parlance, the terms “nested” and “inner” are used interchangeably by most programmers, but I’ll use the correct term “nested class” which covers both inner and static.
    Classes can be nested ad infinitum, e.g. class A can contain class B which contains class C which contains class D, etc. However, more than one level of class nesting is rare, as it is generally bad design.
    There are three reasons you might create a nested class:
    organization: sometimes it seems most sensible to sort a class into the namespace of another class, especially when it won't be used in any other context
    access: nested classes have special access to the variables/fields of their containing classes (precisely which variables/fields depends on the kind of nested class, whether inner or static).
    convenience: having to create a new file for every new type is bothersome, again, especially when the type will only be used in one context
    

    There are four kinds of nested class in Java. In brief, they are:
    static class: declared as a static member of another class
    inner class: declared as an instance member of another class
    local inner class: declared inside an instance method of another class
    anonymous inner class: like a local inner class, but written as an expression which returns a one-off object
    

    Let me elaborate in more details.
    Static Classes
    Static classes are the easiest kind to understand because they have nothing to do with instances of the containing class.
    A static class is a class declared as a static member of another class. Just like other static members, such a class is really just a hanger on that uses the containing class as its namespace, e.g. the class Goat declared as a static member of class Rhino in the package pizza is known by the name pizza.Rhino.Goat.
    package pizza; public class Rhino { … public static class Goat { … } }
    Frankly, static classes are a pretty worthless feature because classes are already divided into namespaces by packages. The only real conceivable reason to create a static class is that such a class has access to its containing class’s private static members, but I find this to be a pretty lame justification for the static class feature to exist.
    Inner Classes
    An inner class is a class declared as a non-static member of another class:
    package pizza; public class Rhino { public class Goat { … } private void jerry() { Goat g = new Goat(); } }
    Like with a static class, the inner class is known as qualified by its containing class name, pizza.Rhino.Goat, but inside the containing class, it can be known by its simple name. However, every instance of an inner class is tied to a particular instance of its containing class: above, the Goat created in jerry, is implicitly tied to the Rhino instance this in jerry. Otherwise, we make the associated Rhino instance explicit when we instantiate Goat:
    Rhino rhino = new Rhino(); Rhino.Goat goat = rhino.new Goat();
    (Notice you refer to the inner type as just Goat in the weird new syntax: Java infers the containing type from the rhino part. And, yes new rhino.Goat() would have made more sense to me too.)
    So what does this gain us? Well, the inner class instance has access to the instance members of the containing class instance. These enclosing instance members are referred to inside the inner class via just their simple names, not via this (this in the inner class refers to the inner class instance, not the associated containing class instance):
    public class Rhino { private String barry; public class Goat { public void colin() { System.out.println(barry); } } }
    In the inner class, you can refer to this of the containing class as Rhino.this, and you can use this to refer to its members, e.g. Rhino.this.barry.
    Local Inner Classes
    A local inner class is a class declared in the body of a method. Such a class is only known within its containing method, so it can only be instantiated and have its members accessed within its containing method. The gain is that a local inner class instance is tied to and can access the final local variables of its containing method. When the instance uses a final local of its containing method, the variable retains the value it held at the time of the instance’s creation, even if the variable has gone out of scope (this is effectively Java’s crude, limited version of closures).
    Because a local inner class is neither the member of a class or package, it is not declared with an access level. (Be clear, however, that its own members have access levels like in a normal class.)
    If a local inner class is declared in an instance method, an instantiation of the inner class is tied to the instance held by the containing method’s this at the time of the instance’s creation, and so the containing class’s instance members are accessible like in an instance inner class. A local inner class is instantiated simply via its name, e.g. local inner class Cat is instantiated as new Cat(), not new this.Cat() as you might expect.
    Anonymous Inner Classes
    An anonymous inner class is a syntactically convenient way of writing a local inner class. Most commonly, a local inner class is instantiated at most just once each time its containing method is run. It would be nice, then, if we could combine the local inner class definition and its single instantiation into one convenient syntax form, and it would also be nice if we didn’t have to think up a name for the class (the fewer unhelpful names your code contains, the better). An anonymous inner class allows both these things:
    new ParentClassName(constructorArgs) {members}
    This is an expression returning a new instance of an unnamed class which extends ParentClassName. You cannot supply your own constructor; rather, one is implicitly supplied which simply calls the super constructor, so the arguments supplied must fit the super constructor. (If the parent contains multiple constructors, the “simplest” one is called, “simplest” as determined by a rather complex set of rules not worth bothering to learn in detail–just pay attention to what NetBeans or Eclipse tell you.)
    Alternatively, you can specify an interface to implement:
    new InterfaceName() {members}
    Such a declaration creates a new instance of an unnamed class which extends Object and implements InterfaceName. Again, you cannot supply your own constructor; in this case, Java implicitly supplies a no-arg, do-nothing constructor (so there will never be constructor arguments in this case).
    Even though you can’t give an anonymous inner class a constructor, you can still do any setup you want using an initializer block (a {} block placed outside any method).
    Be clear that an anonymous inner class is simply a less flexible way of creating a local inner class with one instance. If you want a local inner class which implements multiple interfaces or which implements interfaces while extending some class other than Object or which specifies its own constructor, you’re stuck creating a regular named local inner class.
    [1] https://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class [2] Introduction to Java Programming 10th edition 15.4