ホームページ  >  記事  >  Java  >  Javaの内部クラスと匿名クラス

Javaの内部クラスと匿名クラス

高洛峰
高洛峰オリジナル
2016-12-15 12:41:301324ブラウズ

Java 内部クラス、同様の概念が C++、つまりネストされたクラスにもあります。一見すると、内部クラスは少し冗長に見えますが、初心者にとってはその有用性がそれほど明らかではないかもしれません。 Java の設計者が内部クラスに善意を持っていることがわかります。内部クラスの使用方法を学ぶことは、高度な Java プログラミングを習得する一環であり、これによりプログラム構造をよりエレガントに設計できるようになります。以下の側面から紹介していきます:

初対面

public interface Contents {
    int value();
}
public interface Destination {
    String readLabel();
}
public class Goods {
    private class Content implements Contents {
        private int i = 11;
        public int value() {
            return i;
        }
    }
    protected class GDestination implements Destination {
        private String label;
        private GDestination(String whereTo) {
            label = whereTo;
        }
        public String readLabel() {
            return label;
        }
    }
    public Destination dest(String s) {
        return new GDestination(s);
    }
    public Contents cont() {
        return new Content();
    }
}
class TestGoods {
    public static void main(String[] args) {
        Goods p = new Goods();
        Contents c = p.cont();
        Destination d = p.dest("Beijing");
    }
}

この例では、クラス Goods 内に Content クラスと GDestination クラスが定義されており、それぞれアクセス レベルを制御するための protected 修飾子と private 修飾子を持っています。 Content は商品の内容を表し、GDestination は商品の目的地を表します。これらは、Content と Destination という 2 つのインターフェイスをそれぞれ実装します。次の main メソッドでは、Contents c と Destination d を直接使用して操作します。これら 2 つの内部クラスの名前さえ表示されません。このようにして、内部クラスの最初の利点、つまり他の人に知られたくない操作を隠す、つまりカプセル化が反映されます。

同時に、外部クラスのスコープ外で内部クラスのオブジェクトを取得する最初の方法も発見しました。それは、外部クラスのメソッドを使用してオブジェクトを作成して返すことです。上記の例の cont() メソッドと dest() メソッドはこれを行います。それで、他の方法はありますか?もちろん、構文形式は次のとおりです:

outerObject=new outerClass(Constructor Parameters);
outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

非静的内部クラス オブジェクトを作成するときは、まず対応する外部クラス オブジェクトを作成する必要があることに注意してください。理由については、次のトピックにつながります。

非静的内部クラス オブジェクトは、外部クラス オブジェクトへの参照を持っています

今の例を少し変更しました:

public class Goods {
    private valueRate=2;
    private class Content implements Contents {
        private int i = 11*valueRate;
        public int value() {
            return i;
        }
    }
    protected class GDestination implements Destination {
        private String label;
        private GDestination(String whereTo) {
            label = whereTo;
        }
        public String readLabel() {
            return label;
        }
    }
    public Destination dest(String s) {
        return new GDestination(s);
    }
    public Contents cont() {
        return new Content();
    }
}

変更された部分は赤色で表示されます。ここでは、プライベート メンバー変数 valueRate を Goods クラスに追加します。これは、内部クラス Content の value() メソッドが値を計算するときに、商品の値係数が乗算されることを意味します。 value() は valueRate にアクセスできることがわかりました。これは内部クラスの 2 番目の利点でもあります。内部クラス オブジェクトは、それを作成した外部クラス オブジェクトの内容 (プライベート変数にも) にアクセスできます。これは、設計時により多くのアイデアやショートカットを提供してくれる非常に便利な機能です。この機能を実現するには、内部クラス オブジェクトに外部クラス オブジェクトへの参照が必要です。 Java コンパイラは、内部クラス オブジェクトを作成すると、その参照を暗黙的に外部クラス オブジェクトに渡し、保持します。これにより、内部クラス オブジェクトは常にその外部クラス オブジェクトにアクセスできるようになります。また、これが、外部クラスのスコープ外に内部クラス オブジェクトを作成する場合、最初にその外部クラス オブジェクトを作成する必要がある理由でもあります。

内部クラスのメンバー変数が外部クラスのメンバー変数と同じ名前を持つ場合、つまり、外部クラスの同じ名前のメンバー変数がブロックされている場合はどうすればよいのかと疑問に思う人もいるかもしれません。大丈夫、Java は次の形式を使用して外部クラスへの参照を表現します:

outerClass.this

これを使えば、この種のシールドを恐れることはありません。

静的内部クラス

通常のクラスと同様、内部クラスも静的にすることができます。ただし、非静的内部クラスと比較すると、静的内部クラスには外部参照がないという違いがあります。これは実際には C++ の入れ子クラスに非常に似ています。Java の内部クラスと C++ の入れ子クラスの最大の違いは、もちろん、設計の観点とその詳細の一部に違いがあります。

さらに、非静的内部クラスには、静的データ、静的メソッド、または別の静的内部クラスを含めることはできません (内部クラスのネストは複数のレベルにすることができます)。ただし、これらすべてを静的内部クラスで持つことができます。これが両者の 2 番目の違いと考えられます。

部分的な内部クラス

はい、Java 内部クラスはローカルにすることもでき、メソッド内またはコード ブロック内で定義することもできます。

public class Goods1 {
     public Destination dest(String s) {
          class GDestination implements Destination {
               private String label;
               private GDestination(String whereTo) {
                    label = whereTo;
               }
               public String readLabel() { return label; }
          }
          return new GDestination(s);
     }
     public static void main(String[] args) {
          Goods1 g= new Goods1();
          Destination d = g.dest("Beijing");
     }
}

上記はその一例です。 dest メソッドでは内部クラスを定義し、最後にこのメソッドはこの内部クラスのオブジェクトを返します。内部クラスのオブジェクトを作成し、それを外部に作成するだけであれば、これを行うことができます。もちろん、メソッド内に定義された内部クラスは設計を多様化することができ、用途はこれに限定されるものではありません。

ここにもっと奇妙な例が​​あります:

public class Goods2{
     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("slip");
               String s = ts.getSlip();
          }
     }
     public void track() { internalTracking(true); }
     public static void main(String[] args) {
          Goods2 g= new Goods2();
          g.track();
     }
}

これはスコープを超えているため、この内部クラスのオブジェクトを if の外に作成することはできません。ただし、内部クラス TrackingSlip は、コンパイル中に他のクラスと同時にコンパイルされます。ただし、独自のスコープがあり、このスコープを越えると無効になる点が異なります。それ以外は、他の内部クラスと変わりません。

匿名内部クラス

Java の匿名内部クラスの構文規則は少し奇妙に思えるかもしれませんが、匿名配列と同様に、クラスのオブジェクトを作成するだけでよく、その名前が必要ない場合、内部クラスを使用すると次のことができます。コードは簡潔かつ明確に見えます。その文法規則は次のとおりです:

new interfacename(){......}; 或 new superclassname(){......};

以下の例を続けてみましょう:

public class Goods3 {
     public Contents cont(){
          return new Contents(){
               private int i = 11;
               public int value() {
                    return i;
               }
          };
     }
}

这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。

在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:

frame.addWindowListener(new WindowAdapter(){
     public void windowClosing(WindowEvent e){
          System.exit(0);
     }
});

    有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:

如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。

将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。

在这个匿名内部类中使用初始化代码块。

为什么需要内部类?

java内部类有什么好处?为什么需要内部类?

    首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你 可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。

    不过你可能要质疑,更改一下方法的不就行了吗?

    的确,以此作为设计内部类的理由,实在没有说服力。

    真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题——没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。

  java内部类总结

(1)  在方法间定义的非静态内部类: 

       ● 外围类和内部类可互相访问自己的私有成员。

       ● 内部类中不能定义静态成员变量。

           在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象

 

(2) 在方法间定义的静态内部类:

       ● 只能访问外部类的静态成员。

         静态内部类没有了指向外部的引用

 

(3) 在方法中定义的局部内部类:

       ● 该内部类没有任何的访问控制权限

       ● 外围类看不见方法中的局部内部类的,但是局部内部类可以访问外围类的任何成员。

       ● 方法体中可以访问局部内部类,但是访问语句必须在定义局部内部类之后。

       ● 局部内部类只能访问方法体中的常量,即用final修饰的成员。

 

(4) 在方法中定义的匿名内部类:

       ● 没有构造器,取而代之的是将构造器参数传递给超类构造器

            当你只需要创建一个类的对象而且用不上它的名字时,使用匿名内部类可以使代码看上去简洁清楚。


更多Java中的内部类和匿名类 相关文章请关注PHP中文网!

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