什么是静态?
概念:
静态可以修饰属性和方法。
称为静态属性(类属性)、静态方法(类方法)。
静态成员是全类所有对象共享的成员。对象而产生
在全类中只有一份(是全类对象共享的),不因创建多个对象而产生多份。
静态属性代码:
package day11; public class TestStatic { public static void main(String[] args) { ClassA a1=new ClassA(); ClassA a2=new ClassA(); a1.m++; a1.n++; System.out.println(a2.m);//11 System.out.println(a2.n);//21 } } class ClassA{ int m=10; static int n=20; public static void print() { //System.out.println(m);error System.out.println(n); //ma();这个会报红,因为在静态方法中调用了非静态方法 //mb();这个正确 } public void ma() {} public static void mb() {} }
static:
属性:静态属性(静态属性不是在创建对象时有的)全类共有,可以直接拿类名访问。如ClassA.n
静态变量跟对象没有关系,初始化是先于成员变量的。
静态方法:静态能修饰属性,也能修饰方法。在静态方法中,不能访问非静态成员(方法和属性)。
静态方法可以用类名引用。例子见如下图12行。
在print()方法中,是不能直接调用ma()方法的,但是却可以通过对象的创建来引用:
public static void print() { //System.out.println(m);error System.out.println(n); //ma();这个会报红,因为在静态方法中调用了非静态方法 ma指的默认是this.ma() this:当前对象 ClassA a=new ClassA();
a.ma();//运行结果:21
问题:在静态方法中能有this吗? 不能 因为this指的是当前对象,而静态方法没有对象
}
静态方法与静态方法之间的覆盖:
package day11; public class TestStatic { public static void main(String[] args) { Super s=new Sub(); s.m(); } } class Super{ public static void m() { System.out.println("Super"); } } class Sub extends Super{ public static void m() { System.out.println("Sub"); } }
运行结果:
分析一下运行结果:按照之前的多态的思想(子类与父类有一样的方法,子类方法覆盖父类的方法),运行结果应该是Sub。思考:为什么会出现这样的结果呢?在静态方法中,是例外。静态方法的覆盖的情况下,编译器对引用类型去调用一个静态方法,结果输出引用类型的静态方法。结果为Super就不奇怪了。
非静态方法不能覆盖父类的静态方法。因为会报错。静态方法自能被子类的静态方法覆盖,而且没有多态(只根据引用类型,调用相应的静态方法)。
注:带有静态二字的都和对象没有什么关系。
代码:
package day11; public class TestDynamicBlock { public static void main(String[] args) { new MyClass(); } } class MyClass{ String field="实例属性"; { System.out.println(field); System.out.println("动态代码块"); } public MyClass(){ System.out.println("构造方法"); } }
运行结果:
初始代码块:静态初始代码块在类加载的时候执行。静态修饰静态初始代码块。
类加载:
当JVM第一次使用一个类时,读入这个类所对应的.class文件,并保存起来。
加载时机:
创建对象。
创建子类对象。(加载子类之前,先加载父类)
访问静态属性。
调用静态方法。
Class.forName(“全限定名”)指名道姓的我要加载某个类
将.class文件中对类的描述信息加载到内存中,进行保存。
如:包名、类名、父类、属性、方法、构造方法...
如果只是声明一个类的引用,不需要类加载。如A a; A a=null;变量的本身不需要存对象,存的是对象的地址。
类加载的步骤:
1)如果需要,先加载父类。
2)按顺序初始化静态属性,或执行静态初始代码块。按顺序执行。
静态代码块例子1:
package day11; public class TestDynamicBlock { public static void main(String[] args) { // new MyClass(); // new A(); System.out.println(A.m); // new A(); } } class MyClass{ static String field="实例属性"; static { System.out.println(field); System.out.println("动态代码块"); } public MyClass(){ System.out.println("构造方法"); } } class A{ static int m=10; static { System.out.println("Load A");//类加载的时候执行 } public A(){ System.out.println("A"); } }
运行结果:
例子2:
package day11; public class TestDynamicBlock { public static void main(String[] args) { // new MyClass(); // new A(); // System.out.println(A.m); // new A(); new B(); } } class MyClass{ static String field="实例属性"; static { System.out.println(field); System.out.println("动态代码块"); } public MyClass(){ System.out.println("构造方法"); } } class A{ static int m=10; static { System.out.println("Load A");//类加载的时候执行 } public A(){ System.out.println("A"); } } class B extends A{ static { System.out.println("Load B"); } public B() { System.out.println("B"); } }
运行结果:
为什么会出现这样的结果? new B();先加载B(加载B得先加载父类),再实现B对象(先调用父类方法)