在《Java编程思想》中有这样一段话:“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:方便在没有创建对象的情况下来进行调用(方法/变量)。
下面我们开始探索我们不可不知的static。首先,为什么引入static,请看这一段代码:
首先我们定义一个人(类):
class Person{
private String name;
private int age;
private String country;
// private static String country;
static int num = 100;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person(String name, int age, String country) {
super();
this.name = name;
this.age = age;
this.country = country;
}
@Override
public String toString() {
return "人 [姓名=" + name + ", 年龄=" + age + ", 国籍=" + country
+ "]";
}
// public static String getCountry() {
// return country;
// }
// public static void setCountry(String country) {
// Person.country = country;
// }
}
public class StaticTest {
/**
* 权兴权意-2016.10.8
* static关键字的引入、特点
*/
public static void main(String[] args) {
Person p1 = new Person("甲",18,"中国");
Person p2 = new Person("乙",18,"中国");
Person p3 = new Person("丙",18,"中国");
// Person p2 = new Person("乙",18);
// Person p3 = new Person("丙",18);
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
// p3.setCountry("德国");
// System.out.println("p3.setCountry('德国')");
//
// System.out.println(p1);
// System.out.println(p2);
// System.out.println(p3);
//
// System.out.println("Num:");
// System.out.println(p3.num);
// System.out.println(Person.num);
//
// new Test();
}
}
人 [姓名=甲, 年龄=18, 国籍=中国]
人 [姓名=乙, 年龄=18, 国籍=中国]
人 [姓名=丙, 年龄=18, 国籍=中国]
对于一个人,姓名、年龄一般都不同,但如果都是中国人,国籍一样。
每次创建对象都在堆内存开辟这样的空间,这是一种浪费。
此时,当多个对象有共同的成员变量值-我们用static关键字修饰。(可以修饰成员变量和成员方法)
我们修改代码:
// private String country;
private static String country;
Person p1 = new Person("甲",18,"中国");
// Person p2 = new Person("乙",18,"中国");
// Person p3 = new Person("丙",18,"中国");
Person p2 = new Person("乙",18);
Person p3 = new Person("丙",18);
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
通过static共用国籍变量。
输出结果如下:
人 [姓名=甲, 年龄=18, 国籍=中国]
人 [姓名=乙, 年龄=18, 国籍=中国]
人 [姓名=丙, 年龄=18, 国籍=中国]
为static(Java面向对象)点赞。
下面我们看一下static关键字特点
public static String getCountry() {
return country;
}
public static void setCountry(String country) {
Person.country = country;
}
p3.setCountry("德国");
System.out.println("p3.setCountry('德国')");
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
p3.setCountry('德国')
人 [姓名=甲, 年龄=18, 国籍=德国]
人 [姓名=乙, 年龄=18, 国籍=德国]
人 [姓名=丙, 年龄=18, 国籍=德国]
因此,务必三思static的使用场景。
我们试试通过类名和对象名调用:
System.out.println("Num:");
System.out.println(p3.num);
System.out.println(Person.num);
输出结果ok:
Num:
100
100
最后,我们看一道关于static的面试题:
class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
new Test();
base static
test static
base constructor
test constructor
至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,
在执行开始,先要寻找到main方法,因为main方法是程序的入口,
但是在执行main方法之前,必须先加载Test类,
而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,
在加载Base类的时候,发现有static块,便执行了static块。
在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。
在加载完所需的类之后,便开始执行main方法。
在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。
因此,便出现了上面的输出结果。