最近博主在阅读Java 中HashMap 的时候遇到了静态内部类,由于平时项目中静态内部类使用较少,
除此之外,实际工程中,我还在内部类形式的单例模式使用过静态内部类,
传送门:
对这个知识点进行一下总结,加深认识。
下面讲解下静态内部类与内部类的区别:
静态内部类的使用限制
将某个内部类定义为静态类,跟将其他类定义为静态类的方法基本相同,引用规则也基本一致。不过其细节方面仍然有很大的不同。具体来说,主要有如下几个地方要引起各位程序开发人员的注意。
一: 是静态成员(包括静态变量与静态成员)的定义。
在非静态内部类中不可以声明静态成员。如现在在一个student类中定义了一个内部类age,如果没有将这个类利用static关键字修饰,即没有定义为静态类,那么在这个内部类中如果要利用static关键字来修饰某个成员方法或者成员变量是不允许的。在编译的时候就通不过。故程序开发人员需要注意,只有静态内部类才能够定义静态的成员变量与成员方法。
注意: 此条规则在 Java1.8 中并没取到实际作用。
示例代码 :
package chapter8;
class Outer1 {
class Outer1_Inner1 {
static final String QQ = "QQ1";
String dd = "dd1";
}
static class Outer1_Inner2 {
static final String QQ = "QQ2";
String dd = "dd2";
}
}
/**
* Created by szh on 2018/11/9.
*
* @author szh
*/
public class StaticMain {
public static void main(String[] args) {
Outer1 s = new Outer1();
Outer1.Outer1_Inner1 inner1 = s.new Outer1_Inner1();
System.out.println(Outer1.Outer1_Inner1.QQ);
System.out.println(inner1.dd);
Outer1.Outer1_Inner2 inner2 = new Outer1.Outer1_Inner2();
System.out.println(Outer1.Outer1_Inner2.QQ);
System.out.println(inner2.dd);
}
}
输出:
QQ1
dd1
QQ2
dd2
二: 是在成员的引用上,有比较大的限制。
一般的非静态内部类,可以随意的访问外部类中的成员变量与成员方法。即使这些成员方法被修饰为private(私有的成员变量或者方法)。因为在其他类中是无法访问被定义为私有的成员变量或方法。
但是如果一个内部类被定义为静态的,那么在引用外部类的成员方法或则成员变量的时候,就会有诸多的限制。如不能够从静态内部类的对象中访问外部类的非静态成员(包括成员变量与成员方法)。这是什么意思呢?如果在外部类中定义了两个变量,一个是非静态的变量,一个是静态的变量。静态内部类只能引用外部类中的静态的成员(变量或方法),而不能够访问非静态的变量。对于那些非静态的成员变量与成员方法,在静态内部类中是无法访问的。这就是静态内部类的最大使用限制。在普通的非静态内部类中是没有这个限制的。也正是这个原因,决定了静态内部类只应用在一些特定的场合。其应用范围远远没有像非静态的内部类那样广泛。
示例代码:
package chapter8;
class Outer2 {
private String outer1 = "obj non-static outer1";
private static String outer2 = "obj static outer2";
class Outer2_Inner1 {
static final String QQ = "QQ1";
String dd = "dd1";
void getNonStaticOuter1(){
System.out.println(outer1);
}
void getStaticOuter2(){
System.out.println(outer2);
}
}
static class Outer2_Inner2 {
static final String QQ = "QQ2";
String dd = "dd2";
void getNonStaticOuter1(){
System.out.println(outer1);
}
void getStaticOuter2(){
System.out.println(outer2);
}
}
}
/**
* Created by szh on 2018/11/9.
*
* @author szh
*/
public class StaticMain2 {
public static void main(String[] args) {
Outer2.Outer2_Inner1 outer2_inner1 = new Outer2().new Outer2_Inner1();
outer2_inner1.getNonStaticOuter1();
outer2_inner1.getStaticOuter2();
Outer2.Outer2_Inner2 outer2_inner2 = new Outer2.Outer2_Inner2();
outer2_inner2.getNonStaticOuter1();
outer2_inner2.getStaticOuter2();
}
}
编译错误:
Error:(31, 32) java: 无法从静态上下文中引用非静态 变量 outer1
三: 是在创建静态内部类时不需要将静态内部类的实例绑定在外部类的实例上。
注意 : 该处为静态内部类的一个优势,也就是HashMap中 Node, TreeNode 定义为静态内部类的原因。
通常情况下,在一个类中创建成员内部类的时候,有一个强制性的规定,即内部类的实例一定要绑定在外部类的实例中。也就是说,在创建内部类之前要先在外部类中要利用new关键字来创建这个内部类的对象。如此的话如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。
也就是说,普通非静态内部类的对象是依附在外部类对象之中的。通常情况下,程序员在定义静态内部类的时候,是不需要定义绑定在外部类的实例上的。也就是说,要在一个外部类中定义一个静态的内部类,不需要利用关键字new来创建内部类的实例。
示例代码:
package chapter8;
class Outer3 {
class Inner1 {
String qq = "qq";
}
static class Inner2 {
String qq2 = "qq2";
}
}
/**
* Created by szh on 2018/11/9.
*
* @author szh
*/
public class StaticMain3 {
public static void main(String[] args) {
Outer3.Inner1 inner1 = new Outer3().new Inner1();
//Outer3.Inner1 inner2 = new Outer3.Inner1(); //编译报错
Outer3.Inner2 inner3 = new Outer3.Inner2();
Outer3.Inner2 inner4 = new Outer3.Inner2();
inner3.qq2 = "cc1";
inner4.qq2 = "cc2";
//可以静态内部类 : 不同实例的非静态成员 并不会相互影响。
System.out.println(inner3.qq2 + " " + inner4.qq2);
System.out.println(inner3.qq2 + " " + inner4.qq2);
}
}
输出:
cc1 cc2
cc1 cc2
牢记两个差别:
一、如是否可以创建静态的成员方法与成员变量(静态内部类可以创建静态的成员,而非静态的内部类不可以)
二、对于访问外部类的成员的限制(静态内部类只可以访问外部类中的静态成员变量与成员方法,而非静态的内部类即可以访问所有的外部类成员方法与成员变量)。
总结 :
从以上的分析中可以看出,静态内部类与非静态的内部类还是有很大的不同的。一般程序开发人员可以这么理解,非静态的内部类对象隐式地在外部类中保存了一个引用,指向创建它的外部类对象。
静态内部类在Java语言中是一个很特殊的类,跟普通的静态类以及非静态的内部类都有很大的差异。作为程序开发人员,必须要知道他们之间的差异,并在 实际工作中在合适的地方采用合适的类。不过总的来说,静态内部类的使用频率并不是很高。但是在有一些场合,如果没有这个内部静态类的话,可能会起到事倍功半的反面效果.
https://www.cnblogs.com/aademeng/articles/6192954.html
其他的一些东西:
下面说一说内部类(Inner Class)和静态内部类(Static Nested Class)的区别:
定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明public、protected、private等访问限制,可以声明 为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。外部类按常规的类访问方式使用内部 类,唯一的差别是外部类可以访问内部类的所有方法与属性,包括私有方法与属性。
(1)创建实例
OutClass.InnerClass obj = outClassInstance.new InnerClass(); //注意是外部类实例.new,内部类
AAA.StaticInner in = new AAA.StaticInner();//注意是外部类本身,静态内部类
(2)内部类中的this
内 部类中的this与其他类一样是指的本身。创建内部类对象时,它会与创造它的外围对象有了某种联系,于是能访问外围类的所有成员,不需任何特殊条件,可理 解为内部类链接到外部类。 用外部类创建内部类对象时,此内部类对象会秘密的捕获一个指向外部类的引用,于是,可以通过这个引用来访问外围类的成员。
(3)外部类访问内部类
内部类类似外部类的属性,因此访问内部类对象时总是需要一个创建好的外部类对象。内部类对象通过‘外部类名.this.xxx’的形式访问外部类的属性与方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);
(4)内部类向上转型
内部类也可以和普通类一样拥有向上转型的特性。将内部类向上转型为基类型,尤其是接口时,内部类就有了用武之地。如果内部类是private的,只可以被它的外部类问,从而完全隐藏实现的细节。
(5)方法内的类
方法内创建的类(注意方法中也能定义类),不能加访问修饰符。另外,方法内部的类也不是在调用方法时才会创建的,它们一样也被事先编译了。
(6)静态内部类
定义静态内部类:在定义内部类的时候,可以在其前面加上一个权限修饰符static。此时这个内部类就变为了静态内部类。
通常称为嵌套类,当内部类是static时,意味着:
[1]要创建嵌套类的对象,并不需要其外围类的对象;
[2]不能从嵌套类的对象中访问非静态的外围类对象(不能够从静态内部类的对象中访问外部类的非静态成员);
嵌 套类与普通的内部类还有一个区别:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段, 也不能包含嵌套类。但是在嵌套类里可以包含所有这些东西。也就是说,在非静态内部类中不可以声明静态成员,只有将某个内部类修饰为静态类,然后才能够在这 个类中定义静态的成员变量与成员方法。
另外,在创建静态内部类时不需要将静态内部类的实例绑定在外部类的实例上。普通非静态内部类的 对象是依附在外部类对象之中的,要在一个外部类中定义一个静态的内部类,不需要利用关键字new来创建内部类的实例。静态类和方法只属于类本身,并不属于 该类的对象,更不属于其他外部类的对象。
(7)内部类标识符
每个类会产生一个.class文件,文件名即为类名。同样,内部类也会产生这么一个.class文件,但是它的名称却不是内部类的类名,而是有着严格的限制:外围类的名字,加上$,再加上内部类名字。
(8)为何要用内部类?
1. 内部类一般只为其外部类使用;
2. 内部类提供了某种进入外部类的窗户;
3. 也是最吸引人的原因,每个内部类都能独立地继承一个接口,而无论外部类是否已经继承了某个接口。因此,内部类使多重继承的解决方案变得更加完整。