> Java > java지도 시간 > 본문

Java의 내부 클래스 및 익명 클래스

高洛峰
풀어 주다: 2016-12-15 12:41:30
원래의
1325명이 탐색했습니다.

Java 내부 클래스(Inner Class)는 C++에도 비슷한 개념이 존재합니다. 즉, 중첩 클래스(Nested Class)는 언뜻 보기에 내부 클래스가 약간 중복되어 초보자에게는 그 유용성이 그다지 유용하지 않을 수 있습니다. . 물론이지만 더 깊이 이해하면 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");
    }
}
로그인 후 복사

이 예에서 Content 및 GDestination 클래스는 Goods 클래스 내부에 정의되어 있으며 protected 및 private 수식자가 있습니다. 액세스 수준을 제어합니다. Content는 상품의 내용을 나타내고, GDestination은 상품의 도착지를 나타냅니다. 그들은 각각 두 개의 인터페이스 Content와 Destination을 구현합니다. 다음 기본 메소드에서는 Contents c와 Destination d를 직접 사용하여 이 두 내부 클래스의 이름도 표시하지 않습니다. 이러한 방식으로 내부 클래스의 첫 번째 이점이 반영됩니다. 즉, 다른 사람이 알기를 원하지 않는 작업, 즉 캡슐화를 숨기는 것입니다.

동시에 우리는 외부 클래스의 범위 밖에서 내부 클래스 객체를 얻는 첫 번째 방법도 발견했습니다. 즉, 외부 클래스의 메서드를 사용하여 객체를 생성하고 반환하는 것입니다. 위 예제의 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();
    }
}
로그인 후 복사

수정된 부분은 빨간색으로 표시되어 있습니다. 여기에서는 내부 클래스 Content의 value() 메소드가 값을 계산할 때 상품의 가치 계수를 곱하는 전용 멤버 변수 valueRate를 Goods 클래스에 추가합니다. 우리는 value()가 valueRate에 접근할 수 있다는 것을 알았습니다. 이는 내부 클래스의 두 번째 이점이기도 합니다. 내부 클래스 객체는 자신을 생성한 외부 클래스 객체의 내용, 심지어 개인 변수에도 접근할 수 있습니다! 이는 디자인할 때 더 많은 아이디어와 지름길을 제공하는 매우 유용한 기능입니다. 이 기능을 수행하려면 내부 클래스 개체에 외부 클래스 개체에 대한 참조가 있어야 합니다. Java 컴파일러는 내부 클래스 객체를 생성할 때 외부 클래스 객체에 대한 참조를 암시적으로 전달하고 이를 유지합니다. 이를 통해 내부 클래스 개체는 항상 외부 클래스 개체에 액세스할 수 있으며, 이것이 외부 클래스 범위 외부에 내부 클래스 개체를 생성하려면 먼저 외부 클래스 개체를 생성해야 하는 이유이기도 합니다.

내부 클래스의 멤버 변수와 외부 클래스의 멤버 변수가 같은 이름을 가지고 있다면, 즉 외부 클래스의 같은 이름을 가진 멤버 변수가 막힌? 괜찮습니다. Java는 외부 클래스에 대한 참조를 표현하기 위해 다음 형식을 사용합니다.

outerClass.this
로그인 후 복사

이를 사용하면 이러한 종류의 차폐를 두려워하지 않습니다.

정적 내부 클래스

일반 클래스와 마찬가지로 내부 클래스도 정적일 수 있습니다. 그러나 비정적 내부 클래스와 비교하면 정적 내부 클래스에는 외부 참조가 없다는 차이점이 있습니다. 이는 실제로 C++의 중첩 클래스와 매우 유사합니다. Java 내부 클래스와 C++ 중첩 클래스의 가장 큰 차이점은 물론 외부에 대한 참조가 있는지 여부와 세부 사항에 차이가 있습니다.

또한, 비정적 내부 클래스에는 정적 데이터, 정적 메서드 또는 다른 정적 내부 클래스가 있을 수 없습니다(내부 클래스의 중첩은 두 수준 이상일 수 있음). 하지만 정적 내부 클래스에서는 이 모든 것을 가질 수 있습니다. 이것이 둘 사이의 두 번째 차이점이라고 볼 수 있습니다.

부분 내부 클래스

예, 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();
     }
}
로그인 후 복사

이 내부 클래스의 객체는 범위를 초과했기 때문에 외부에서 생성할 수 없습니다. 그러나 컴파일하는 동안 내부 클래스 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中文网!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!