java 內部類 嵌套類
概述
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 Selectorpublic 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 內部類 嵌套類