关于static关键字,我想它应该让不少人都很烦。因为我们可能经常遇到static关键字在这个地方能用,在那个地方又不能用的情况。而它到底在哪些地方能用、哪些地方又不能用,总感觉不是很好说清楚。今天这篇博客就是对static的用法做一个全面的梳理。
首先明确一定:static关键字被创建的原因是为了“实现共享”,所以静态成员会随着类的加载而加载,而静态成员则是发生类的实例化时才会被加载。
还想提一下无关的题外话:除了类中,其他的地方都不能定义方法。
1.static不能用于修饰外部类;
2.外部类静态成员在自己的内部调用外部类其他成员时,只能调静态的;
3.外部类非静态成员在自己的内部调用外部类其他成员时,调静态和非静态的都可以;
4.只有外部类的静态成员内部类可以在自己的内部定义静态的局部成员;其他的外部类静态或非静态成员都不能在自己的内部定义静态的局部成员。
注:以上的2-4条规范中,很多次提到一个词“成员”,这个成员指的是各种字段、各种方法、各种代码块或各种内部类。
外部类的修饰符只有public/package、abstract/final这四种,其中“/”的意思表示这两种修饰符不能同时出现。所以static不能用于修饰外部类,否则都无法通过编译。
先看第2点:外部类静态成员在自己的内部调用外部类其他成员时,这个时候很可能只是外部类被加载了,而外部类的实例化还没有发生。这时外部类的非静态成员都压根不存在,没法调用。
再看第3点:外部类非静态成员在自己的内部调用外部类其他成员时,这个时候必然发生了外部类的实例化,而外部类在这之前必被加载了。这时外部类的静态或非静态成员都已经存在,可以调用。
以下为示例代码(为了测试方便,选择了相互调用的方式,会发生无限迭代的情况,所以外部类Outer不建议执行new操作,否则会抛出StackOverflowError异常):
package com.blogs;
class Outer {
// 外部类非静态成员字段
FieldTest fTest1 = new FieldTest() {
@Override
void say() {
// 外部类非静态成员字段内部调用外部类非静态、静态成员皆可
System.out.println(fTest1); //外部类非静态成员字段
System.out.println(fTest2); //外部类静态成员字段
func1(); //外部类非静态成员方法
func2(); //外部类静态成员方法
new Inner1(); //外部类非静态成员内部类
new Inner2(); //外部类静态成员内部类
}
};
// 外部非类静态成员方法
void func1() {
// 外部类非静态成员方法内部调用外部类非静态、静态成员皆可
System.out.println(fTest1); //外部类非静态成员字段
System.out.println(fTest2); //外部类静态成员字段
func1(); //外部类非静态成员方法
func2(); //外部类静态成员方法
new Inner1(); //外部类非静态成员内部类
new Inner2(); //外部类静态成员内部类
}
// 外部类非静态成员代码块
{
// 外部类非静态成员代码块内部调用外部类非静态、静态成员皆可
System.out.println(fTest1); //外部类非静态成员字段
System.out.println(fTest2); //外部类静态成员字段
func1(); //外部类非静态成员方法
func2(); //外部类静态成员方法
new Inner1(); //外部类非静态成员内部类
new Inner2(); //外部类静态成员内部类
}
// 外部类非静态成员内部类
class Inner1{
void innerFun1() {
// 外部类非静态成员内部类内部调用外部类非静态、静态成员皆可
System.out.println(fTest1); //外部类非静态成员字段
System.out.println(fTest2); //外部类静态成员字段
func1(); //外部类非静态成员方法
func2(); //外部类静态成员方法
new Inner1(); //外部类非静态成员内部类
new Inner2(); //外部类静态成员内部类
}
}
// 外部类静态成员字段
static FieldTest fTest2 = new FieldTest() {
@Override
void say() {
// 外部类非静态成员字段内部只能调用外部类静态成员
// System.out.println(fTest1); //外部类非静态成员字段,编译不通过
System.out.println(fTest2); //外部类静态成员字段
// func1(); //外部类非静态成员方法,编译不通过
func2(); //外部类静态成员方法
// new Inner1(); //外部类非静态成员内部类,编译不通过
new Inner2(); //外部类静态成员内部类
}
};
// 外部类静态成员方法
static void func2() {
// 外部类非静态成员方法内部只能调用外部类静态成员
// System.out.println(fTest1); //外部类非静态成员字段,编译不通过
System.out.println(fTest2); //外部类静态成员字段
// func1(); //外部类非静态成员方法,编译不通过
func2(); //外部类静态成员方法
// new Inner1(); //外部类非静态成员内部类,编译不通过
new Inner2(); //外部类静态成员内部类
}
// 外部类静态成员代码块
static {
// 外部类非静态成员代码块内部只能调用外部类静态成员
// System.out.println(fTest1); //外部类非静态成员字段,编译不通过
System.out.println(fTest2); //外部类静态成员字段
// func1(); //外部类非静态成员方法,编译不通过
func2(); //外部类静态成员方法
// new Inner1(); //外部类非静态成员内部类,编译不通过
new Inner2(); //外部类静态成员内部类
}
// 外部类静态成员内部类
static class Inner2{
void innerFun1() {
// 外部类非静态成员内部类内部只能调用外部类静态成员
// System.out.println(fTest1); //外部类非静态成员字段,编译不通过
System.out.println(fTest2); //外部类静态成员字段
// func1(); //外部类非静态成员方法,编译不通过
func2(); //外部类静态成员方法
// new Inner1(); //外部类非静态成员内部类,编译不通过
new Inner2(); //外部类静态成员内部类
}
}
}
abstract class FieldTest{
abstract void say();
}
在这里给出一下我自己认为还比较可以的解释吧。static修饰的局部成员,其上一级必须是类,而且因为java的加载机制,必须随着外部类的加载而加载。要做到这样的,也就只有外部类的静态成员内部类中的静态局部变量可以做到。
以下为示例代码(太长,可以不看,记住上述两句话就好了):
package com.blogs;
class InnerDefine {
// 外部类非静态成员字段
InnerDefineTest INT1 = new InnerDefineTest() {
@Override
void say() {
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
final class jhh{
}
class hhjj{
}
}
};
// 外部非类静态成员方法
void func1() {
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
}
// 外部类非静态成员代码块
{
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
}
// 外部类非静态成员内部类
class Inner1{
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败"; //默认是final修饰
final int age = 2;
// string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
// static void gfj() { //定义静态内部类方法失败
// System.out.println("我是静态内部类方法");
// }
void gfty() {
System.out.println("我是非静态内部类方法");
}
}
// 外部类静态成员字段
static InnerDefineTest INT2 = new InnerDefineTest() {
@Override
void say() {
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
}
};
// 外部类静态成员方法
static void func2() {
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
}
// 外部类静态成员代码块
static {
// static String hjbh = "uyu"; //定义静态局部字段失败,只能用final或空修饰
String string = "定义静态字段失败";
final int age = 2;
string = "hjhg";
// static{ //定义静态局部代码块失败,只能用空修饰
// System.out.println("gyiu");
// }
{
System.out.println("gyiu");
}
// static class hh{ //定义静态局部内部类失败,只能用"abstract/final/空"修饰,同时只能有一个修饰符
//
// }
class hhjj{
}
}
// 外部类静态成员内部类
static class Inner2{
static String hjbh = "uyu"; //定义静态局部字段成功
String string = "定义静态字段失败"; //默认是final修饰
final int age = 2;
// string = "hjhg";
static{ //定义静态局部代码块成功
int j=4;
System.out.println("gyiu");
}
{
System.out.println("gyiu");
}
static class hh{ //定义静态局部内部类成功
}
class hhjj{
}
static void gfj() {
System.out.println("我是静态内部类方法");
}
void gfty() {
System.out.println("我是非静态内部类方法");
}
}
}
abstract class InnerDefineTest{
abstract void say();
}