>Java >java지도 시간 >Java 개선편(7) ----- 내부 클래스에 대한 자세한 설명

Java 개선편(7) ----- 내부 클래스에 대한 자세한 설명

黄舟
黄舟원래의
2017-02-09 13:44:461067검색

한 클래스의 정의를 다른 클래스의 정의 안에 배치할 수 있습니다. 이것이 내부 클래스입니다.

내부 클래스는 매우 유용한 기능이지만 이해하고 사용하기가 어렵습니다(저는 지금까지 내부 클래스를 사용해 본 적이 없고 내부 클래스에 대해서는 조금밖에 모릅니다).

첫 만남

내부 클래스는 외부에서 보면 매우 이해하기 쉽습니다. 클래스 내부에 클래스를 정의하는 것에 지나지 않습니다.


1. 내부 클래스를 사용하는 이유

내부 클래스를 사용하는 이유는 무엇입니까? "Think in Java"에는 다음 문장이 있습니다. 내부 클래스를 사용하는 가장 매력적인 이유는 각 내부 클래스가 독립적으로 (인터페이스) 구현을 상속할 수 있기 때문에 외부 클래스가 (인터페이스) 구현을 상속했는지 여부에 관계없이 내부 클래스에 영향을 미칩니다.

때때로 우리 프로그래밍에는 인터페이스를 사용하여 해결하기 어려운 문제가 있습니다. 이때 내부 클래스에서 제공하는 기능을 사용하여 여러 구체적 또는 추상 클래스를 상속하여 이러한 프로그램 디자인 문제를 해결할 수 있습니다. . 인터페이스는 문제의 일부만 해결하고 내부 클래스는 다중 상속 솔루션을 더욱 완벽하게 만든다고 말할 수 있습니다.

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;  
        }  
    }  
}

사실 이 예에서는 내부 클래스를 사용하는 이점을 실제로 볼 수 없지만, Father와 Mother가 인터페이스가 아니라 추상 클래스이거나 구체적인 클래스라면 어떨까요? 현재로서는 다중 상속을 달성하기 위해 내부 클래스만 사용할 수 있습니다.

사실 내부 클래스를 사용하면 다중상속 문제를 아주 잘 해결할 수 있다는 것이 가장 큰 장점이지만, 다중상속 문제를 굳이 해결할 필요가 없다면 자연스럽게 다른 코딩을 사용하면 된다. 하지만 내부 클래스를 사용하면 다음과 같은 기능도 얻을 수 있습니다("Think in java"에서 발췌).

1. 내부 클래스는 여러 인스턴스를 사용할 수 있습니다. 각 인스턴스는 자체 상태 정보를 가지며 관련되어 있습니다. 다른 주변 개체의 정보는 서로 독립적입니다.

2. 단일 주변 클래스에서 여러 내부 클래스가 동일한 인터페이스를 다른 방식으로 구현하거나 동일한 클래스를 상속할 수 있습니다.

3. 내부 클래스 객체가 생성되는 시간은 외부 클래스 객체 생성에 의존하지 않습니다.

4. 내부 클래스 간에 혼동되는 "is-a" 관계가 없습니다. 독립적인 개체입니다.

5. 내부 클래스는 더 나은 캡슐화를 제공합니다. 주변 클래스를 제외하고 다른 클래스는 액세스할 수 없습니다.


2. 내부 클래스의 기본

이번 섹션에서는 주로 내부 클래스가 외부 클래스의 속성과 메소드를 어떻게 활용하는지 소개하고, .this 및 .new 사용.

내부 클래스를 만들면 외부 클래스와 보이지 않는 연결이 있으며, 이 연결을 통해 외부 클래스의 요소에 무제한으로 액세스할 수 있습니다.

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

이 애플리케이션에서는 내부 InnerClass가 비공개적으로 수정되었음에도 불구하고 외부 클래스 OuterClass의 속성에 원활하게 액세스할 수 있음을 확인할 수 있습니다. 이는 외부 클래스의 내부 클래스 개체를 생성할 때 외부 클래스 개체에 대한 참조를 확실히 캡처하기 때문입니다. 외부 클래스의 멤버에 액세스하는 한 이 참조를 사용합니다. 둘러싸는 클래스.

사실 이 애플리케이션에서는 내부 클래스를 참조하는 방법도 살펴보았습니다. 내부 클래스를 참조하려면 OuterClasName.InnerClassName이라는 객체의 유형을 지정해야 합니다. 동시에 내부 클래스 객체를 생성해야 하는 경우 외부 클래스 객체를 사용하여 .new를 통해 내부 클래스를 생성해야 합니다. OuterClass.InnerClass innerClass = externalClass.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 중국어 웹사이트(www.php .cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.