Java面试系列之static关键字

Java面试系列之static关键字

static概述
Java中的 static 关键字,主要是用来做内存管理的,static修饰的变量称之为静态变量,static修饰的方法称之为静态方法,static修饰的代码块叫做静态代码块。
static 可以修饰:
变量(即 class variable)
方法(即 class method)
代码块(即 block)
内部类(即 nested class)
凡是被 static 修饰的这四种元素,都属于class的元素,即类的,而不是类的实例的。


1、静态变量
在声明变量的时候加上static 关键字,该变量即是静态变量,静态变量和非静态变量的区别是静态变量被所有的对象所共享,在内存中只有一个副本,*它当且仅当在类初次加载时会被初始化*。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
**PS:**Java的静态变量也叫做类变量,它开始于类的创建,结束于类的消亡。非静态变量叫做实例变量,它开始于类的实例的创建,结束于类的实例的消亡。
在《Java编程思想》有这样一段话:

static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的
前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

方便在没有创建对象的情况下来进行调用(方法/变量)。
另外一个好处在于内存利用率高,看下下面两个demo:

 class Student{  
     int No;  
     String name;  
     String college="CZC";  
}  

假设这个学校有500000000个学生,那么当每一个学生被创建的时候,都会初始化学号、姓名、学校,每个学生都有自己的学号和姓名,这样做没问题;但是每个学生的college字段都相同,如果每次都声明一遍的话,是比较耗内存的。这里的college变量其实是被该类的所有实例所共享的,因此可以将它声明为 static 的。

class Student{  
   int rollno;  
   String name;  
   static String college ="CZC";    
   Student(int r,String n){  
       rollno = r;  
       name = n;  
   }  
 void display (){
     System.out.println(rollno+" "+name+" "+college);
 }  
 public static void main(String args[]){  
     Student8 s1 = new Student8(111,"Karan");  
     Student8 s2 = new Student8(222,"Aryan");   
     s1.display();  
     s2.display();  
 }  
}

这个demo,静态变量分配在了方法区,堆中该类的所有实例共享方法区中的college。


2、静态方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。

静态方法属于类而不是对象。
静态方法可以直接通过类名调用,而不需要创建类的对象。
静态方法可以修改静态变量,而非静态方法不可以。

PS:静态方法的两个注意点:
静态方法不能操作非静态变量,也不能调用非静态方法。(这个可以这样理解:因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用,而静态方法属于类,直接通过类名就可以调用,此时可能没有任何实例,更谈不上操作实例变量和调用实例方法了)
静态方法中不能使用 this 和 super 关键字。(道理同上)

为什么Java的main方法是static的?
为了使得在调用main方法之前不需要创建任何实例对象。

3、静态代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

用来初始化静态变量。
在类加载时,在执行main方法之前执行相关操作。
 static{
2         System.out.println("");
4     }

4、静态内部类
被static修饰的类,并且处于某个类的内部。

它可以访问外部类的静态成员,包括private成员。
它不能访问外部类的非静态成员。(原因前面说过)
class TestOuter1{  
  static int data=30;  
  static class Inner{  
   void msg(){
       System.out.println("data is "+data);}  
  }  
  public static void main(String args[]){  
      TestOuter1.Inner obj=new TestOuter1.Inner();  
      obj.msg();  
  }  
}

data is 30

main方法中创建了一个静态内部类的实例,并且调用了其msg() 方法。但是这里并没有创建外部类的实例,因为这里的Inner类是static的,并且可以访问外围类的static成员。如果把Inner之前的static去掉,那么这里要这样写:

TestStaticInnerClass.Inner obj=new TestStaticInnerClass().new Inner();

需要先创建外一个部类实例,然后才能创建内部类实例。静态内部类不仅高效利用内存,而且使得代码简洁。

以上内容参考了文章 https://www.cnblogs.com/HarrisonHao/p/6102343.html


5、静态导包
静态导包就是java包的静态导入,用import static代替import静态导入包是JDK1.5中的新特性。一般我们导入一个类都用 import com…..ClassName;而静态导入是这样:import static com…..ClassName.;这里的多了个static,还有就是类名ClassName后面多了个.* ,意思是导入这个类里的静态方法。当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用
好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一个静态方法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写来的方便

当你想使用static成员时,可以使用静态导入(在API中的类和你自己的类上,都可以使用该特性)。下面是静态导入前后的代码实例:

在静态导入之前:

public class TestStatic {
    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.toHexString(42));
    }
}

在静态导入之后:
import static java.lang.System.out;
import static java.lang.Integer.*;
public class TestStaticImport {
public static void main(String[] args) {
out.println(MAX_VALUE);
out.println(toHexString(42));
}
}
两个类都产生相同的输出:

2147483647
2a

让我们看一下使用静态导入特性的代码中将发生什么:
1、虽然该特性通常称为“静态导入”,但语法必须是import static,后面跟你想导入的static成员的完全限
定名称,或者通配符。在本例中,我们在System类的out对象上进行静态导入。
2、在本例中,我们可能想使用java.lang.Integer类的几个static成员。该静态导入语句使用通配符来表达“
我想在此类中的所有静态成员上进行静态导入”。
3、现在我们终于看到静态导入特性的好处!我们不必在System.out.println中键入System。太好了!另外,
我们不必在Integer.MAX_VALUE中键入Integer。因此,在这行代码中,我们能够将快捷方式用于静态方法和一
个常量。
4、最后,我们进行更多的快捷操作,这次针对Integer类的方法。
关于该特性,我们已经有点儿讽刺意味儿了,但不仅我们是这样的。我们不认为节省少量的击键次数会让代码
难于阅读一点,但许多开发人员要求将它添加到语言中。
下面是使用静态导入的几条原则:
你必须说import static, 不能说static import。
提防含糊不清的命名static成员。例如,如果你对Integer类和Long类执行了静态导入,引用MAX_VALUE将导致
一个编译器错误,因为Integer和Long都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。
你可以在static对象引用、常量(记住,它们是static 或final)和static方法上进行静态导入。

你可能感兴趣的:(Java菜鸟面试突破系列)