1. 程式人生 > >java 內部類 嵌套類

java 內部類 嵌套類

seq hub 存在 邏輯 val blog ems 不能 pri

概述

java允許我們把一個類a定義在另一個類b裏面,那麽這個類a就叫做內部類。例如如下面:

  • 如果內部類似Non-static的那麽被稱作內部類
    class OuterClass { ... class NestedClass { ... } }

  • 如果內部類是static 的那麽被稱作嵌套類或者內部靜態類
    ```
    class OuterClass {
    ...
    static class StaticNestedClass {
    ...
    }

}
```

使用方法

普通的內部類

Outer o = new Outer(); Outer.Inner i = o.new Inner();

  • 內部類的對象只能在與其外部類相關聯的情況下才能被創建。
  • 內部類訪問外部類實例時可以使用Outer.this,創建內部類實例時使用外部類的實例對象 .new Inner()
  • 內部類對象隱含地保存了一個指向外部類對象的引用,每一個非靜態內部類的實例都鏈接到一個外部類的實例上

    靜態嵌套類

  Outer.Inner i = new Outer.Inner();
  • 如果不需要內部類與其外部類對象之間有聯系,可以將內部類聲明為static.
  • 不能訪問非靜態的外圍成員

    註意

  • 如果一個類要被聲明為static的,只有一種情況,就是靜態內部類。
  • 靜態內部類跟靜態方法一樣,只能訪問靜態的成員變量和方法,不能訪問非靜態的方法和屬性,但是普通內部類可以訪問任意外部類的成員變量和方法
  • 靜態內部類可以聲明普通成員變量和方法以及static成員變量和方法,而普通內部類不能聲明static成員變量和方法。

    為什麽需要內部類

    內部類的使用場景

    我們來看一個例子:

    先定義一個抽象類
    ```
    /**
  • Selector叠代器
    */
    public abstract class Selector

```
/**

  • 用類包裝一個Integer的數組,並實現添加 通過繼承Selector叠代遍歷
    */
    public class Sequence extends Selector

    public Sequence(int size){
    items=new Object[size];
    }
    public void add(int x){
    if(next <items.length){
    items[next]=x;
    next++;
    }
    }

    /************************************實現抽象類*/

    private int index=0;
    @Override
    boolean hasNext() {
    return !(index==items.length);
    }

    @Override
    Integer next() {
    Integer value=null;
    if( hasNext()){
    value=Integer.parseInt(items[index].toString()) ;
    index++;
    }
    return value;

    }
    }

我們定義一個Sequence類來包裝了一個Object的數組,裏面封裝了添加初始化操作,通過繼承了Selector<T> 來實現了叠代遍歷功能。 這時如果我們需要Sequence再繼承其他類怎麽辦?比如現在有一個類SequenceBiz
/**

  • Sequence需要繼承的業務
    */
    public class SequenceBiz {
    public void log()
    {
    //dosomestring 一些需要Sequence繼承的業務
    System.out.println(this.getClass().getName()+"我記錄了日誌");
    }
    }
    這個時候可以使用內部類來解決 ##### 使用內部類
    /**
  • 用類包裝一個Object的數組,並使用內部類通過繼承Selector叠代遍歷
  • 繼承SequenceBiz 來處理其他業務
    */
    public class Sequence1 extends SequenceBiz{
    private Object [] items;
    private int next =0;

    public Sequence1(int size){
    items=new Object[size];
    }
    public void add(int x){
    if(next <items.length){
    items[next]=x;
    next++;
    }
    }
    private class SequenceSelector extends Selector

    @Override
    public Integer next() {
        Integer value=null;
        if( hasNext()){
            value=Integer.parseInt(items[index].toString()) ;
            index++;
        }
        return value;
    
    }
    }
    /**
    • 返回叠代器
    • @return
      */
      public Selector getSelector()
      {
      return new SequenceSelector();
      }

}

我們來測試一下
public class TestInnerClass {
public static void main(String[] args)
{
// Sequence sequence=new Sequence(5);
// for (int i=0;i<5;i++){
// sequence.add(i);
// }
// while (sequence.hasNext()){
// System.out.println(sequence.next());
// }
Sequence1 sequence1=new Sequence1(5);
for (int i=0;i<5;i++){
sequence1.add(i);
}
Selector selector=sequence1.getSelector();
while (selector.hasNext()){
System.out.println(selector.next());
}
sequence1.log();
}
}

##### 我們來看內部類的好處:
- 使用內部類解決了java中不能繼承多個類的問題
- Sequence1創建的private內部類來實現Selector 隱藏了Selector的具體實現。(jdk源碼中ArrayList的叠代器就是這種方法)
- 嵌套小類會使代碼更靠近使用位置,使代碼更加利於維護、
#### 靜態內部類的場景

##### 普通類中創建一個靜態類

 ```
    public class Outer {  
    private String name;  
    private int age;  
  
    public static class Builder {  
        private String name;  
        private int age;  
  
        public Builder(int age) {  
            this.age = age;  
        }  
  
        public Builder withName(String name) {  
            this.name = name;  
            return this;  
        }  
  
        public Builder withAge(int age) {  
            this.age = age;  
            return this;  
        }  
  
        public Outer build() {  
            return new Outer(this);  
        }  
    }  
  
    private Outer(Builder b) {  
        this.age = b.age;  
        this.name = b.name;  
    }  
}  

靜態內部類調用外部類的構造函數,來構造外部類,由於靜態內部類可以被單獨初始化說有在外部就有以下實現。即Builder design pattern(生成器設計模式)
我們可以在main中使用
調用 Outer outer = new Outer.Builder(2).withName("Yang Liu").build();

接口中的內部類

在接口中我們定義的內部類只能是靜態內部類。關於使用場景可以參考shiro框架中Subject接口。

/**
*生成器設計模式實現用於以簡化的方式創建實例
Builder design pattern implementation for creating {@link Subject} instances in a simplified way without requiring knowledge of Shiro‘s construction techniques.
*
/
public interface Subject {
     public static class Builder {
         
     }
}

關於這個設計模式可以參考
- https://www.cnblogs.com/zhuyuliang/p/5212746.html
- Builder Design Pattern

說明
- 如果類的構造器或者靜態工廠中有多個參數,設計這樣類時,最好使用builder模式,特別是大多數參數都是可選的時候。
- 如果現在不能確定參數的個數,使用構造器即builder模式。
- 靜態內部類提高了封裝性,和代碼的可讀性。 

總結

  • 使用內部類解決了多繼承的問題
  • 方便將存在一定邏輯關系的類組織在一起,又可以對外界隱藏。
  • 使代碼更靠近使用位置,使代碼更加利於維護

    參考

  • https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
  • https://www.cnblogs.com/chenssy/p/3388487.html
  • https://www.cnblogs.com/dolphin0520/p/3811445.html
  • http://blog.csdn.net/hivon/article/details/606312

    博客中的源碼地址

    github地址:https://github.com/yalunwang/java-clump

java 內部類 嵌套類