java 内部类 嵌套类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 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模式。
- 静态内部类提高了封装性,和代码的可读性。 

总结


























































































以上是关于java 内部类 嵌套类的主要内容,如果未能解决你的问题,请参考以下文章

java嵌套类和内部类详解

Java内部类

java-深入理解java嵌套类内部类以及内部类builder构建构造函数

Java嵌套类的作用、用法和调用机制是怎么样的?

java 内部类 嵌套类

java中,类走之间可以嵌套吗?