ホームページ  >  記事  >  Java  >  Java改善編(7) ----- 内部クラスの詳細説明

Java改善編(7) ----- 内部クラスの詳細説明

黄舟
黄舟オリジナル
2017-02-09 13:44:461049ブラウズ

あるクラスの定義を別のクラスの定義内に配置できます。これは内部クラスです。非常に 内部クラスは非常に便利な特性ですが、使用上の特性を理解するのがさらに困難です (これまで内部クラスを使用して使用したことがなく、内部クラスについては 1 つまたは 2 つ知っているだけです)。

アウトアウトアウト。

public class OuterClass {  
    private String name ;  
    private int age;  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public int getAge() {  
        return age;  
    }  
  
    public void setAge(int age) {  
        this.age = age;  
    }  
      
    class InnerClass{  
        public InnerClass(){  
            name = "chenssy";  
            age = 23;  
        }  
    }  
}

ここでの InnerClass は内部クラスです。初心者にとっては、インナークラスはあまり使用したことがありませんが (スイング登録イベントでのみ使用されるようです)、プログラミングの機能向上に伴い、その魅力を認識し、それを使用してプログラム構造をよりエレガントに設計できます。内部クラスを使用する前に、なぜ内部クラスを使用する必要があるのか​​、また内部クラスによってどのようなメリットがもたらされるのかを理解する必要があります。

1. 内部クラスを使用する理由


内部クラスを使用する理由「Think in Java」には次の文があります。 内部クラスを使用する最も魅力的な理由は、各内部クラスが独立して (インターフェース) 実装を継承できるため、外部クラスが (インターフェース) 実装を継承しているかどうかに関係なく、実装が存在しないことです。内部クラスへの影響。

プログラミングではインターフェイスを使用して解決するのが難しい問題が発生することがあります。現時点では、内部クラスによって提供される機能を使用して、複数の具体クラスまたは抽象クラスを継承することで、これらのプログラミング問題を解決できます。インターフェイスは問題の一部を解決するだけであり、内部クラスは多重継承の解決策をより完全にするものであると言えます。

public interface Father {  
  
}  
  
public interface Mother {  
  
}  
  
public class Son implements Father, Mother {  
  
}  
  
public class Daughter implements Father{  
  
    class Mother_ implements Mother{  
          
    }  
}

実際、この例では内部クラスを使用する利点がわかりませんが、Father と Mother がインターフェイスではなく、抽象クラスまたは具象クラスだったらどうなるでしょうか?現時点では、多重継承を実現するには内部クラスのみを使用できます。

実際、内部クラスを使用する最大の利点は、多重継承の問題をうまく解決できることです。しかし、多重継承の問題を解決する必要がない場合は、当然他のコーディング方法を使用できます。内部クラスを使用すると、次のような機能が得られます (「Think in Java」から抜粋):

1. 内部クラスは複数のインスタンスを使用でき、各インスタンスは独自のステータス情報を持ち、他の周辺オブジェクトの情報から独立しています。 。

2. 単一の周辺クラスでは、複数の内部クラスが同じインターフェイスを異なる方法で実装したり、同じクラスを継承したりできます。

3. 内部クラスのオブジェクトが作成される時間は、外部クラスのオブジェクトの作成に依存しません。

4. 内部クラスには紛らわしい「is-a」関係はなく、独立したエンティティです。

5. 内部クラスはより適切なカプセル化を提供します。周辺クラスを除き、他のクラスはそれにアクセスできません。

2. 内部クラスの基本


このパートでは、主に内部クラスが外部クラスのプロパティやメソッドを使用する方法、および .this と .new の使用方法を紹介します。

内部クラスを作成すると、外部クラスとの目に見えない接続が確立され、この接続に基づいて外部クラスの要素に無制限にアクセスできます。

public class OuterClass {  
    private String name ;  
    private int age;  
  
    /**省略getter和setter方法**/  
      
    public class InnerClass{  
        public InnerClass(){  
            name = "chenssy";  
            age = 23;  
        }  
          
        public void display(){  
            System.out.println("name:" + getName() +"   ;age:" + getAge());  
        }  
    }  
      
    public static void main(String[] args) {  
        OuterClass outerClass = new OuterClass();  
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();  
        innerClass.display();  
    }  
}  
--------------  
Output:  
name:chenssy   ;age:23

このアプリケーションでは、内部の InnerClass は、プライベートに変更されているにもかかわらず、外部クラスの OutputClass のプロパティにシームレスにアクセスできることがわかります。これは、外部クラスの内部クラス オブジェクトを作成するとき、外部クラスのメンバーにアクセスする限り、内部クラス オブジェクトはその外部クラス オブジェクトへの参照を確実に取得するため、この参照を使用します。囲んでいるクラス。

実際、このアプリケーションでは、内部クラスを参照する方法も確認しました。内部クラスを参照するには、このオブジェクトのタイプ、OuterClasName.InnerClassName を指定する必要があります。同時に、内部クラス オブジェクトを作成する必要がある場合は、外部クラス オブジェクトを使用して、.new を通じて内部クラスを作成する必要があります:OuterClass.InnerClass innerClass = innerClass.new InnerClass();。

同時に、外部クラス オブジェクトへの参照を生成する必要がある場合は、OuterClassName.this を使用して、外部クラスへの参照を正しく生成できます。もちろん、これはコンパイル時に認識されるため、実行時のコストはかかりません。

public class OuterClass {  
    public void display(){  
        System.out.println("OuterClass...");  
    }  
      
    public class InnerClass{  
        public OuterClass getOuterClass(){  
            return OuterClass.this;  
        }  
    }  
      
    public static void main(String[] args) {  
        OuterClass outerClass = new OuterClass();  
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();  
        innerClass.getOuterClass().display();  
    }  
}  
-------------  
Output:  
OuterClass...

 到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

       在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。


       三、成员内部类

       成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

       在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

public class OuterClass {  
    private String str;  
      
    public void outerDisplay(){  
        System.out.println("outerClass...");  
    }  
      
    public class InnerClass{  
        public void innerDisplay(){  
            //使用外围内的属性  
            str = "chenssy...";  
            System.out.println(str);  
            //使用外围内的方法  
            outerDisplay();  
        }  
    }  
      
    /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */  
    public InnerClass getInnerClass(){  
        return new InnerClass();  
    }  
      
    public static void main(String[] args) {  
        OuterClass outer = new OuterClass();  
        OuterClass.InnerClass inner = outer.getInnerClass();  
        inner.innerDisplay();  
    }  
}  
--------------------  
chenssy...  
outerClass...

推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 。


       四、局部内部类

       有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

       对于局部内部类实在是想不出什么好例子,所以就引用《Think in java》中的经典例子了。

       定义在方法里:

public class Parcel5 {  
    public Destionation destionation(String str){  
        class PDestionation implements Destionation{  
            private String label;  
            private PDestionation(String whereTo){  
                label = whereTo;  
            }  
            public String readLabel(){  
                return label;  
            }  
        }  
        return new PDestionation(str);  
    }  
      
    public static void main(String[] args) {  
        Parcel5 parcel5 = new Parcel5();  
        Destionation d = parcel5.destionation("chenssy");  
    }  
}

       定义在作用域内:

public class Parcel6 {  
    private void internalTracking(boolean b){  
        if(b){  
            class TrackingSlip{  
                private String id;  
                TrackingSlip(String s) {  
                    id = s;  
                }  
                String getSlip(){  
                    return id;  
                }  
            }  
            TrackingSlip ts = new TrackingSlip("chenssy");  
            String string = ts.getSlip();  
        }  
    }  
      
    public void track(){  
        internalTracking(true);  
    }  
      
    public static void main(String[] args) {  
        Parcel6 parcel6 = new Parcel6();  
        parcel6.track();  
    }  
}

 五、匿名内部类

       在做Swing编程中,我们经常使用这种方式来绑定事件

button2.addActionListener(    
                new ActionListener(){    
                    public void actionPerformed(ActionEvent e) {    
                        System.out.println("你按了按钮二");    
                    }    
                });

        我们咋一看可能觉得非常奇怪,因为这个内部类是没有名字的,在看如下这个例子:

public class OuterClass {  
    public InnerClass getInnerClass(final int num,String str2){  
        return new InnerClass(){  
            int number = num + 3;  
            public int getNumber(){  
                return number;  
            }  
        };        /* 注意:分号不能省 */  
    }  
      
    public static void main(String[] args) {  
        OuterClass out = new OuterClass();  
        InnerClass inner = out.getInnerClass(2, "chenssy");  
        System.out.println(inner.getNumber());  
    }  
}  
  
interface InnerClass {  
    int getNumber();  
}  
  
----------------  
Output:  
5

这里我们就需要看清几个地方

      1、 匿名内部类是没有访问修饰符的。

      2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。

      3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。

      4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。

PS:由于篇幅有限,对匿名内部类就介绍到这里,有关更多关于匿名内部类的知识,我就会在下篇博客(java提高篇-----详解匿名内部类)做详细的介绍,包括为何形参要定义成final,怎么对匿名内部类进行初始化等等,敬请期待……


       六、静态内部类

       在java提高篇-----关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

      1、 它的创建是不需要依赖于外围类的。

      2、 它不能使用任何外围类的非static成员变量和方法。

public class OuterClass {  
    private String sex;  
    public static String name = "chenssy";  
      
    /** 
     *静态内部类 
     */  
    static class InnerClass1{  
        /* 在静态内部类中可以存在静态成员 */  
        public static String _name1 = "chenssy_static";  
          
        public void display(){  
            /*  
             * 静态内部类只能访问外围类的静态成员变量和方法 
             * 不能访问外围类的非静态成员变量和方法 
             */  
            System.out.println("OutClass name :" + name);  
        }  
    }  
      
    /** 
     * 非静态内部类 
     */  
    class InnerClass2{  
        /* 非静态内部类中不能存在静态成员 */  
        public String _name2 = "chenssy_inner";  
        /* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */  
        public void display(){  
            System.out.println("OuterClass name:" + name);  
        }  
    }  
      
    /** 
     * @desc 外围类方法 
     * @author chenssy 
     * @data 2013-10-25 
     * @return void 
     */  
    public void display(){  
        /* 外围类访问静态内部类:内部类. */  
        System.out.println(InnerClass1._name1);  
        /* 静态内部类 可以直接创建实例不需要依赖于外围类 */  
        new InnerClass1().display();  
          
        /* 非静态内部的创建需要依赖于外围类 */  
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();  
        /* 方位非静态内部类的成员需要使用非静态内部类的实例 */  
        System.out.println(inner2._name2);  
        inner2.display();  
    }  
      
    public static void main(String[] args) {  
        OuterClass outer = new OuterClass();  
        outer.display();  
    }  
}  
----------------  
Output:  
chenssy_static  
OutClass name :chenssy  
chenssy_inner  
OuterClass name:chenssy

上面这个例子充分展现了静态内部类和非静态内部类的区别。

内部クラスの紹介は基本的にここで終わりです。実際、私の内部クラスに関する知識は表面的なものにすぎず、知識も限られています。この数日を使って内部クラスを勉強します

上記は Java 改善の章 (7) -----内部クラスの内容の詳細な説明については、PHP 中国語 Web サイトをご覧ください。 (www.php.cn)!


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