Java中的静态内部类详解及代码示例

1. 什么是静态内部类

在Java中有静态代码块、静态变量、静态方法,当然也有静态类,但Java中的静态类只能是Java的内部类,也称为静态嵌套类。静态内部类的定义如下:

public class OuterClass {
  static class StaticInnerClass {
    ...
  }
}

在介绍静态内部类之前,首先要弄清楚静态内部类与Java其它内部类的区别。

2. 内部类

什么是内部类?将一个类的定义放在另一个类的内部,就是内部类。Java的内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

2.1 成员内部类

成员内部类是最普通的内部类,就是一个普通的类定义在另一个类的内部,形式如下:

public class OuterClass {
  class InnerClass {
    ...
  }
}

注:

在成员内部类中,可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问。

成员内部类中不能存在任何静态变量和静态方法。

成员内部类是依附于外部类的,只有先创建了外部类才能够创建内部类。

成员内部类的创建形式如下:

//定义成员内部类的方式一
OuterClass test = new OuterClass();
InnerClass innerA = test.new InnerClass();
//定义成员内部类的方式二
OuterClass.InnerClass innerB = new OuterClass().new InnerClass();

2.2 局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,形式如下:

public void methodInnerClass() {
  class InnerClass {
    ...
  }
  InnerClass A = new InnerClass();
}

注:

局部内部类就像是方法里面的一个局部变量一样,不能有public、protected、private以及static修饰符。

可以直接访问外部类的属性、方法,即使是private类型也可以访问。

2.3 匿名内部类

用过Swing的人应该对匿名内部类非常熟悉,Swing中使用了大量的匿名内部类。匿名内部类的形式如下:

Button button = new Button();
button.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
    ...
  }
});

注:

匿名内部类没有名字,没有构造方法。

匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

2.4 静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。其定义形式如下:

public class OuterClass {
  static class StaticInnerClass {
    ...
  }
}

注:

静态内部类的创建不依赖外部类。

静态内部类不能访问外部类的非静态成员和非静态方法。

2.5 静态内部类与其它内部类的区别

静态内部类与其它内部类最大的区别在于非静态内部类在编译完成之后会隐含地保存一个引用,该引用是指向创建它的外部类,但是静态内部类却没有。静态内部类只是嵌套在外部类中,因此也被称为嵌套内部类。

2.6 为什么要使用内部类

方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建外部类的对象。典型的情况是Effective Java 2.0中Item 2讲述的构建器模式。

使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

3. 为什么要使用静态内部类

使用静态内部类主要是因为静态内部类的两个优点:

增强了类的封装性
提高了代码的可读性

以下面的例子为例:将Builder放在NutritionFacts的内部,说明二者之间有一定的关系,比起将两个类分开要好很多,因此增强了类的封装性。其次,二者放在一起,能很明显的看出Builder类是用来创建NutritionFacts类的,提高了代码的可读性。

4. 静态内部类的例子

静态内部类的创建:

//Builder Pattern
public class NutritionFacts {
  private final int servingSize;
  private final int servings;
  private final int calories;
  private final int fat;
  private final int sodium;
  private final int carbohydrate;
  public static class Builder {
    // Required parameters
    private final int servingSize;
    private final int servings;
    // Optional parameters - initialized to default values
    private int calories = 0;
    private int fat = 0;
    private int carbohydrate = 0;
    private int sodium = 0;
    public Builder(int servingSize, int servings) {
      this.servingSize = servingSize;
      this.servings = servings;
    }
    public Builder calories(int val) {
      calories = val;
      return this;
    }
    public Builder fat(int val) {
      fat = val;
      return this;
    }
    public Builder carbohydrate(int val) {
      carbohydrate = val;
      return this;
    }
    public Builder sodium(int val) {
      sodium = val;
      return this;
    }
    public NutritionFacts build() {
      return new NutritionFacts(this);
    }
  }
  private NutritionFacts(Builder builder) {
    servingSize = builder.servingSize;
    servings = builder.servings;
    calories = builder.calories;
    fat = builder.fat;
    sodium = builder.sodium;
    carbohydrate = builder.carbohydrate;
  }
}

静态内部类的使用:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();

总结

以上就是本文关于Java中的静态内部类详解及代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:Java编程子类能否重写父类的静态方法探索、Java单例模式实现静态内部类方法示例等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

时间: 2017-10-25

Java编程中静态内部类与同步类的写法示例

java静态内部类 将某个内部类定义为静态类,跟将其他类定义为静态类的方法基本相同,引用规则也基本一致.不过其细节方面仍然有很大的不同.具体来说,主要有如下几个地方要引起各位程序开发人员的注意.     (一)一般情况下,如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态成员变量与静态成员方法的.也就是说,在非静态内部类中不可以声明静态成员.     (二)一般非静态外部类可以随意访问其外部类的成员变量以及方法(包括声明为private的方法),但是

深入浅析Java中Static Class及静态内部类和非静态内部类的不同

java中的类可以是static吗?答案是可以.在java中我们可以有静态实例变量.静态方法.静态块.类也可以是静态的. java允许我们在一个类里面定义静态类.比如内部类(nested class).把nested class封闭起来的类叫外部类.在java中,我们不能用static修饰顶级类(top level class).只有内部类可以为static.      静态内部类和非静态内部类之间到底有什么不同呢?下面是两者间主要的不同. (1)内部静态类不需要有指向外部类的引用.但非静态内部

Java单例模式实现静态内部类方法示例

Singleton是众多设计模式中最容易理解的一种,也是众多设计模式中较为重要的一种设计模式.接下来我们看看具体介绍. Singleton模式实现的重点在于将构造函数私有化(private),并通过提供静态公有函数(public synchronized static xxx getInstance)来获取定义在类中的静态私有成员(private static xxx instance),通过一个简单的判断静态实例是否为空来控制这个类只能够new一次,即控制了一个类只能有单个实例,一般的实现如下

java 内部类(匿名类,匿名对象,静态内部类)详解及实例

内部类的介绍 定义在另外一个类中的类,叫内部类 成员内部类 1..new 创建成员内部类必须先创建外部类的实例,然后通过.new 创建内部类的对象 2..this 可以通过外部类的类名.this去访问外部类的所有属性和方法. public class Test1 { String name = "asnd"; public static void main(String[] args) { Test1 test1 = new Test1(); Inner mInner = test1.

java 中使用匿名类直接new接口详解及实例代码

java:使用匿名类直接new接口 java中的匿名类有一个倍儿神奇的用法,见下面代码示例: package contract; public interface ISay { void sayHello(); } 上面是一个简单的接口,下面是如何使用: package jimmy; import contract.ISay; public class Program { public static void main(String[] args) { ISay say = new ISay()

java对象拷贝详解及实例

java对象拷贝详解及实例 Java赋值是复制对象引用,如果我们想要得到一个对象的副本,使用赋值操作是无法达到目的的: @Test public void testassign(){ Person p1=new Person(); p1.setAge(31); p1.setName("Peter"); Person p2=p1; System.out.println(p1==p2);//true } 如果创建一个对象的新的副本,也就是说他们的初始状态完全一样,但以后可以改变各自的状态,

java 单播、广播、组播详解及实例代码

java 单播.广播.组播详解及实例代码 在当前网络通信中(TCP/IP也不例外)有三种通信模式:单播.广播.组播(又叫多播, 个人感觉叫多播描述的有点不恰当),其中多播出现的时间最晚,但同时具备单播和广播的优点,最具有发展前景. 一.通信方式分类: 1.单播:单台主机与单台主机之间的通信: 2.广播:单台主机与网络中所有主机的通信: 3.组播:单台主机与选定的一组主机的通信: 二.单播:    单播是网络通信中最常见的,网络节点之间的通信 就好像是人们之间的对话一样.如果一个人对另外一个人说话

java 用泛型参数类型构造数组详解及实例

java 用泛型参数类型构造数组详解及实例 前言: 前一阵子打代码的时候突然想到一个问题.平时我们的数组都是作为一个参数传入方法中的,如果我们要想在方法中创建一个数组怎么样呢?在类型明确的情况下,这是没什么难度的.如果我们传入的参数是泛型类型的参数呢? public static <T> T[] creArray (T obj){ T[] arr = new T[10]; } 像上面这种用T来直接new数组的方法是错误的,会编译时出现一个:Cannot create a generic arr

Java 两种延时thread和timer详解及实例代码

Java 两种延时thread和timer详解及实例代码 在Java中有时候需要使程序暂停一点时间,称为延时.普通延时用Thread.sleep(int)方法,这很简单.它将当前线程挂起指定的毫秒数.如 try { Thread.currentThread().sleep(1000);//毫秒 } catch(Exception e){} 在这里需要解释一下线程沉睡的时间.sleep()方法并不能够让程序"严格"的沉睡指定的时间.例如当使用5000作为sleep()方法的参数时,线 程

Java泛型映射不同的值类型详解及实例代码

Java泛型映射不同的值类型详解 前言: 一般来说,开发人员偶尔会遇到这样的情形: 在一个特定容器中映射任意类型的值.然而Java 集合API只提供了参数化的容器.这限制了类型安全地使用HashMap,如单一的值类型.但如果想混合苹果和梨,该怎样做呢? 幸运的是,有一个简单的设计模式允许使用Java泛型映射不同的值类型,Joshua Bloch在其<Effective Java>(第二版,第29项)中将其描述为类型安全的异构容器(typesafe hetereogeneous Containe

java 中JDBC连接数据库代码和步骤详解及实例代码

java 中JDBC连接数据库代码和步骤详解 JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤:  1.加载JDBC驱动程序:  在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String  className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver") ; }catch(Class

Java 异常的栈轨迹(Stack Trace)详解及实例代码

Java 异常的栈轨迹(Stack Trace)详解 捕获到异常时,往往需要进行一些处理.比较简单直接的方式就是打印异常栈轨迹Stack Trace.说起栈轨迹,可能很多人和我一样,第一反应就是printStackTrace()方法.其实除了这个方法,还有一些别的内容也是和栈轨迹有关的. 1.printStackTrace() 首先需要明确,这个方法并不是来自于Exception类.Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的.而和异常相关的方法都是从jav

Java 创建线程的两个方法详解及实例

Java 创建线程的两个方法 Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线程,有两种方法: ◆需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法: ◆实现Runnalbe接口,重载Runnalbe接口中的run()方法. 为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢?

Java内部类之间的闭包和回调详解

前言 闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域.通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用城内,内部类有权操作所有的成员,包括private成员. Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调(callback).通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象.如果回调是通