zoukankan      html  css  js  c++  java
  • java 内部类 嵌套类

    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 {
             
         }
    }
    

    关于这个设计模式可以参考

    总结

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

    参考

    博客中的源码地址

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

    努力学习,每天进步一点点。加油
  • 相关阅读:
    如何给女朋友解释什么是分布式和集群?【转】
    彻底理解cookie、session、token 【转】
    API到底是什么? 【汇总,转】
    代理的基本原理【转】
    从未如此简单:10分钟带你逆袭Kafka!【转】
    一口气说出Kafka为啥这么快? 【转】
    kafka官网 http://kafka.apache.org/intro
    网络相关命令配置【汇总 更新中】
    Kafka的四个基础概念学习【转】
    Kafka简介及各个组件介绍 【转】
  • 原文地址:https://www.cnblogs.com/yalunwang/p/8059807.html
Copyright © 2011-2022 走看看