一、概念
在《Java编程思想》P86页有这样一段话:
“static方法就是没有this的方法。在 static 方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用 static 方法。这实际上正是 static 方法的主要用途。”
C/C++/OC 中存在全局变量、全局方法的概念,而 Java 中,除了一些特殊的代码,比如 import、enum的声明等,所有的代码都必须写在类中。因此,在 Java 中就不存在全局变量、全局方法这种概念。
而全局变量就是存储在全局区的变量,直到程序结束时,生命周期才被销毁,Java 中也肯定存在这种需求,所以肯定需要一个替代方案,而 static 就是一种选择。
静态的概念:
- 存储在 data 区(全局区);
- 只有一份内存,修改之后影响全局;
- Java 中以类为维度,所以会存在一个归属问题,在哪个类中定义,那么这个静态变量/方法就只能通过这个类或者这个类的实例来访问;
二、场景
1. static 修饰局部变量
Java 中的 static 不能修饰局部变量!!!
其原因可能涉及到:
- Java 语言的设计理念问题;
- Java 编译器的实现问题,实现一个非必要的功能徒增工作量;
- 是否有必要或者已有替代方案(比如类的静态成员变量就可以实现相同的需求);
2. static 修饰成员变量
本质上而言,static 修饰成员变量就是和 C 中的 static 一样,将成员变量转移到了 data 区,不改变作用域,改变了生命周期。但是 Java 中代码都写在类中,没有全局变量的概念,所以需要使用类作为承载。
而 OC 中则不一样。 Java 的设计更加面向对象,就连 main 函数都是对象驱动的,而 OC 中则存在更多面向过程的影子。main 函数的地址是通过 dyld 加载 mach-O 文件时找到并将命令行指向那个位置的。
因此,OC 中不能使用 static 修饰类成员变量:
OC是不能使用static修饰成员属性究其原因有几点:
- 没必要
OC 中没有以类的维度来划分代码。需要一个全局静态变量直接写在全局代码区(文件的非类、函数区域)即可,需要一个局部静态变量,直接写在栈代码区(函数内部)即可。
- 歧义
如果真这么做了,那么静态变量就和类之间建立了关联,还需要存储和类相关的信息。本质上而言, static 只是改变变量的生命周期,如果和类关联起来,按照 OC 中 ARC 谁持有谁管理的观念,难道类在释放之后,或者在类对象加载时,还要去管理这个静态变量?无意义还引起误会。
3. static 修饰方法
static 修饰方法可以用一句话概括:
- static方法就是没有this的方法。
其有几个特点:
- 不需要对象实例就可以直接调用,作用有点类似于 OC 中的类方法;
- 因为没有 this,所以静态方法中不能访问类的非静态成员变量和非静态成员方法;
- 静态变量是属于类的,但是也可以通过对象访问(本质还是因为静态意味着data,权限足够而且有办法找到函数地址就可以访问);
使用示例:
public class Main {
public static void main(String[] args) {
// 不需要对象就可以直接访问
XKPerson.StaticFunc();
// 虽然静态方法属于类,但是也可以通过对象访问
new XKPerson().StaticFunc();
}
}
class XKPerson {
static final String COUNTRY = "CHINA";
int age;
static public void StaticFunc(){
System.out.println("StaticFunc");
// static方法中没有this,不能访问非静态成员变量
System.out.println(age); //compile error
// 可以访问静态成员变量(本质上就是data区的数据)
System.out.println(COUNTRY);
}
}
特殊情况:
- 对象为 null 时调用静态方法不会出现空指针异常;
正常情况下,如果一个对象为 null,调用该对象的任何示例方法都将引起空指针异常,但是如果是调用静态方法则可以正常调用:
对象:
class XKPerson {
static final String COUNTRY = "CHINA";
static public void StaticFunc(){
System.out.println("123");
}
public void InstanceFunc(){
System.out.println("456");
}
}
main函数:
XKPerson p1 = null;
p1.StaticFunc();
p1.InstanceFunc();
结果:
123
Exception in thread "main" java.lang.NullPointerException
at com.company.Main.main(Main.java:15)
四、static 修饰类
修饰个屁的类哦,你喝多了吧...
Java 里面 static 一般用来修饰成员变量或函数,但有一种特殊用法是用 static 修饰内部类。
普通类是不允许声明为静态的,只有内部类才可以。被static修饰的内部类可以直接作为一个普通类来使用,而不需实例一个外部类,最常见的使用是解决 AsyncTask 内存泄漏问题:
public class MainActivity extends AppCompatActivity {
MainAsyncTask asyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
asyncTask = new MainAsyncTask();
// 入参会被传递到doInBackground方法中,可以传递多个值
asyncTask.execute(100);
}
public static class MainAsyncTask extends AsyncTask<Integer,Integer,String> {
// asyncTask 逻辑
}
}
此时静态内部类 MainAsyncTask 已经不引用 MainActivity 了,所以当 MainActivity 被 destory 打包 MainAsyncTask 还在执行任务时,不会影响 MainActivity 的销毁;
于此同时
被 static 修饰的内部类:
- 已经不是严格意义上的内部类了;
- 不能再使用外部类中的实例方法和属性了(因为相当于和外部类平行,除非传一个外部类的实例对象过来才可以使用);
- 内部类不再引用外部类(非静态内部类默认引用外部类);
- 因此,使用静态内部类解决 AsyncTask 的内存泄漏问题时,局限性很大,只适用于 AsyncTask 和 外部类 Activity 没有交互时;
参考:https://blog.csdn.net/vcliy/article/details/85235363
五、总结
static 的适用范围,在 C/C++/OC 中:
- 修饰局部变量;
- 不能修饰成员变量;
- 修饰全局变量;
- 修饰方法;
在 Java 中:
- 不能修饰局部变量;
- 修饰成员变量;
- Java 中无全局变量一说;
- 修饰方法;
网友评论