static关键字用途
《Java编程思想》中讲到:
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通关过类本身来调用static方法。这实际上正是static方法的主要用途。
简而言之:方便在没有创建对象的时候进行调用(方法/变量)
显然,被static关键字修饰的方法或变量不需要依赖对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
(1)static变量
static变量又被称为静态变量,静态变量和非静态变量的区别:静态变量被所有对象共享,在内存中只有一个副本,当且仅当在类被初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
(2)static方法
static方法又被称为静态方法,在静态方法中不能访问非静态成员变量和非静态成员方法,但非静态方法可以调用静态方法和静态成员变量。因为静态方法不依附任何对象,而非静态成员方法/变量都是必须依赖具体的对象才能够被调用的。
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
(3)static代码块
static代码块的作用就是形成静态代码块以优化程序性能。static块可以置于类中任何地方,类中可以有多个static代码块。在类被初次加载的时候,会按照每个static代码块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以优化性能,那是因为static在类加载时只执行一次。
常见误区
- static是否会改变类中成员的访问权限?
java中的static关键不会影响成员或方法的作用域,影响其作用域的只有private, public, protected这几个关键字。
- this能访问静态成员变量吗?
public class STATICAPP {
static int num = 3;
public void printValue(){
int num = 33;
System.out.println(this.num);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
STATICAPP sa = new STATICAPP();
sa.printValue();
}
}
输出结果:3
this表示当前实例对象,和成员方法中的局部变量无关。
- static能作用于局部变量吗?
记住:static是不允许用来修饰局部变量的,Java语法规定
常见面试题
下面列举一些面试笔试中经常遇到的关于static关键字的题目,仅供参考,如有补充欢迎下方留言。
1.下面这段代码的输出结果是什么?
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
base static
test static
base constructor
test constructor
开始执行时,首先要找到main方法,在执行main方法前,要首先加载Test类,当加载Test类时,发现它继承Base类,要首先加载Base类,这个时候发现Base类中存在static代码块,加载执行static块,加载Base完成后加载Test类,Test类中也存在static代码块,执行后开始执行main方法,首先调用Test父类的构造方法,然后调用Test自身的构造方法,就出现了上面的结果。
2.这段代码的输出结果是什么?
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
同样的道理,在执行开始,要先找到main方法,在执行main方法前,加载Test类,执行Test中的static块,然后执行main方法,new MyClass()之前先加载MyClass类,然后开始创建对象:因为MyClass继承Test类,所以要先初始化父类的成员变量(此时父类Test已经加载),因此会执行Test中的Person person = new Person(“Test”),此时还没有加载Person类,加载Person类执行Person类中static块,调用Person构造方法,实例化Person类,然后调用父类Test构造器,然后初始化自身,同样的道理,先初始化自己的成员变量,调用Person类的构造函数(此时Person已经加载过),最后执行MyClass的构造器。
3.这段代码的输出结果是什么?
public class Test {
static{
System.out.println("test static 1");
}
public static void main(String[] args) {
}
static{
System.out.println("test static 2");
}
}
test static 1
test static 2
参照上述的分析过程:在执行main方法前,加载Test类,顺序执行Test类中的static块