static关键字
static关键字的含义
static:静态的。
static可以修饰属性、修饰方法、修饰类、修饰代码块。
static修饰属性
static修饰属性,则我们称该属性为静态变量或类变量
静态变量:静态变量是每个对象所共有的,当一个对象修改某个静态变量时,其余对象的相同静态变量也会被修改。
static修饰属性的说明:
① 静态变量随着类的加载而加载。
② 静态变量的加载早于实例变量的加载。
③ 由于类只会加载一次,则静态变量在内存中也只存在一份。
④ 静态变量可以使用对象调用,也可以使用类调用。实例变量(即非static修饰的属性)只能通过对象调用。
public class TestDemo1 {
public static void main(String[] args) {
Chinese c1 = new Chinese("张三",26);
Chinese c2 = new Chinese("李四",29);
c1.nation = "中国";
System.out.println(c1.nation); //输出 中国
System.out.println("*********************");
System.out.println(c2.nation); //输出 中国
//我们并没有修改对象c2的 nation属性,结果却显示 中国。 这就是由于我们将nation声明为static的
//则nation为每个对象所共有的。
}
}
class Chinese{
public String name;
public int age;
public static String nation;
public Chinese(){
}
public Chinese(String name,int age){
this.name = name;
this.age = age;
}
}
static修饰方法
static修饰方法:
① 随着类的加载而加载,通过“类名.方法名”的方式去调用,同时也可以使用对象调用。
② 在静态方法中只能调用静态方法和静态属性
③ 非静态方法中可以调用静态方法和属性,也可以调用非静态方法和属性。
④ 在静态方法中,不能使用super、this关键字。(因为super是父类对象的引用,this是本类对象的引用,静态方法是随着类加载而加载的,早于对象的加载。)
static修饰代码块
static修饰代码块:
① 静态代码块,随着类加载而加载且只执行一次。如果在类中声明了多个静态代码块,则按照先后声明的顺序执行。
② 静态代码块的执行要优先于非静态代码块的执行,静态代码块只能调用静态属性和静态方法。
static修饰类:
static修饰类只能作为内部类出现。
如何实例化静态内部类的对象?
使用 new 外部类.内部类();
public class TestDemo1 {
public static void main(String[] args) {
Chinese c1 = new Chinese();
// 实例化非静态内部类。 通过 外类对象.new 内部类();
Chinese.XiAn x1 =c1.new XiAn();
// 实例化静态内部类。通过 new 外部类.内部类();
Chinese.JiangSu js = new Chinese.JiangSu();
x1.introduce();
js.told();
}
}
class Chinese{
public String name;
public int age;
public static String nation;
class XiAn{
public void introduce(){
System.out.println("西安市");
}
}
static class JiangSu{
public void told(){
System.out.println("江苏省");
}
}
public Chinese(){
}
}
关于static关键字加载顺序问题
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时,发现它有静态代码块,则先执行静态代码块: test static。
③ 紧接着,执行new Myclass();,创建Myclass的对象,则去加载Myclass类,在加载Myclass类时发现,Myclass类继承了Test类,则应先加载父类Test,之前已经加载过父类
Test了,所以不用再加载了。
④ 接着,发现子类Myclass中有静态代码块,则执行静态代码块: myclass static。
⑤ 接着,子类要想创建对象,则必须先加载完父类的成员变量和构造器,于是又去加载父类的成员变量: Person person = new Person(“Test”);
⑥ 此时发现 Person类还没有被加载,则加载Person类,发现Person类中有静态代码块,则加载静态代码块: person static。接着加载Person类构造器: person Test。
⑦ 加载完Person后,接着又返回来加载父类Test的构造器: test constructor。
⑧ 父类的成员变量和构造器加载完后,返回来加载子类的成员变量:Person person = new Person(“MyClass”); 则会输出: person Myclass,再接着加载子类的构造器,输出: myclass constructor;