java 内部类 嵌套类

概述

java允许我们把一个类a定义在另一个类b里面,那么这个类a就叫做内部类。例如如下面:

  1. 如果内部类似Non-static的那么被称作内部类
class OuterClass {
   ...
   class NestedClass {
       ...
   }
}
  1. 如果内部类是static 的那么被称作嵌套类或者内部静态类
class OuterClass {
  ...
  static class StaticNestedClass {
      ...
  }
 
}

使用方法

  1. 普通的内部类
Outer o = new Outer();
Outer.Inner i = o.new Inner();
  • 内部类的对象只能在与其外部类相关联的情况下才能被创建。
  • 内部类访问外部类实例时可以使用Outer.this,创建内部类实例时使用外部类的实例对象 .new Inner()
  • 内部类对象隐含地保存了一个指向外部类对象的引用,每一个非静态内部类的实例都链接到一个外部类的实例上
  1. 静态嵌套类
Outer.Inner i = new Outer.Inner();
  • 如果不需要内部类与其外部类对象之间有联系,可以将内部类声明为static.
  • 不能访问非静态的外围成员

注意

  • 如果一个类要被声明为static的,只有一种情况,就是静态内部类。
  • 静态内部类跟静态方法一样,只能访问静态的成员变量和方法,不能访问非静态的方法和属性,但是普通内部类可以访问任意外部类的成员变量和方法
  • 静态内部类可以声明普通成员变量和方法以及static成员变量和方法,而普通内部类不能声明static成员变量和方法。

为什么需要内部类

内部类的使用场景

  1. 先定义一个抽象类
/**
* Selector迭代器
*/
public abstract class Selector<T> {
  public  void ff(){
      System.out.println(this.getClass().getName());
  }
  abstract boolean hasNext();
  abstract T next();
}

再定义一个Sequence类

/**
* 用类包装一个Integer的数组,并实现添加 通过继承Selector迭代遍历
*/
public class Sequence  extends Selector<Integer>{
  private Object  [] items;
  private int next =0;

  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()+"我记录了日志");
 }
}

这个时候可以使用内部类来解决

  1. 使用内部类
/**
* 用类包装一个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<Integer>{
     private  int index=0;
     @Override
     public boolean hasNext() {
         return !(index==items.length);
     }

     @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();
 }
}

我们来看内部类的好处:

  1. 使用内部类解决了java中不能继承多个类的问题
  2. Sequence1创建的private内部类来实现Selector 隐藏了Selector的具体实现。(jdk源码中ArrayList的迭代器就是这种方法)
  3. 嵌套小类会使代码更靠近使用位置,使代码更加利于维护、

静态内部类的场景

  1. 普通类中创建一个静态类
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();
  1. 总结
  • 如果类的构造器或者静态工厂中有多个参数,设计这样类时,最好使用builder模式,特别是大多数参数都是可选的时候。
  • 如果现在不能确定参数的个数,使用构造器即builder模式。
  • 静态内部类提高了封装性,和代码的可读性。
  1. 接口中的内部类 在接口中我们定义的内部类只能是静态内部类。关于使用场景可以参考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 {
         
     }
}

总结

  • 使用内部类解决了多继承的问题
  • 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
  • 使代码更靠近使用位置,使代码更加利于维护