(1)静态方法中可以使用this/super吗?
不可以,因为静态方法先于对象存在。而this/super表示的是对象。故不可以。
(2)静态方法中可以调用本类的非静态方法吗?
不可以 在本类中调用demo()相当于this.demo,因为静态方法中不可以使用this,所以静态方法不能调用非静态方法
(3)静态方法可以被继承吗? 可以
(4)静态方法可以被重写吗?
不可以 如果父子类中出现了同名的静态方法,称之为隐藏(hide)。
如果父子类中有同名方法,要么都是静态(隐藏),要么都是非静态(重写)
隐藏也遵循"两等两小一大"原则
(5)例题
class A{
static String name;
}
public class StaticDemo {
public static void main(String[] args) {
A a = new A();
A a1 = new A();
a.name = "hello";
a1.name = "world";
System.out.println(a.name);
System.out.println("============");
System.out.println(a1.name);
}
}
结果:
world
============
world
分析:static变量是在类加载的时候被加载,而且只被加载一次。被所有实例化该类的对象所共享。
(6)例题
public class StaticDemo2 {
public static void main(String[] args) {
new B();
}
}
class A{
static{
System.out.println("Static-A执行了");
}
{
System.out.println("代码块-A执行了");
}
public A(){
System.out.println("构造方法-A执行了");
}
}
class B extends A{
static C c = new C();
static{
System.out.println("Static-B执行了");
}
{
System.out.println("代码块-B执行了");
}
public B(){
System.out.println("构造方法-B执行了");
}
}
class C{
public C(){
System.out.println("构造方法-C执行了");
}
}
结果:
Static-A执行了
构造方法-C执行了
Static-B执行了
代码块-A执行了
构造方法-A执行了
代码块-B执行了
构造方法-B执行了
分析:根据static变量、static方法、static代码块先于类对象加载。故实例化之前,先去加载static~。
- 实例化B对象
- 通过方法区,得知B对象信息,继承A,发现A中含有静态代码块,故先执行A中的Static代码块
- 此外,在B对象中有静态变量C,故去执行static C c = new C();然后输出构造方法-C执行了。
- 在B对象中还有静态代码块,故在去执行静态代码块中的内容
- 然后执行父类A中的构造代码块和构造方法(构造代码块先于构造方法执行)
- 最后在执行父类B中的构造代码块和构造方法
补充:如果
static{
System.out.println("Static-B执行了");
}
在static C c = new C();上面,则会先打印“Static-B执行了”,在打印C的构造方法中的内容。
(7)例题
public class StaticDemo3 {
public static void main(String[] args) {
System.out.println(StaticDemo.i);
}
}
class StaticDemo{
static{
i = 1;
}
static int i;
}
结果:1
分析:根据static用法,我们知道static变量是随着类加载到方法区的,而类加载又分为加载-校验-准备-解析-初始化五个步骤。
其中,我们要关注准备阶段和初始化阶段。
- 在准备阶段,给i开辟内存空间,并且设定一个标记值。
- 然后在初始化阶段先执行静态代码块 i = 1代码,舍弃标记值,
- 然后再执行静态变量,但是没有赋值操作,所以保留i=1的结果。
(8)例题
public class StaticDemo3 {
public static void main(String[] args) {
System.out.println(StaticDemo.i);
}
}
class StaticDemo{
static{
i += 5;
}
static int i = 3;
}
结果:编译不通过
分析:当变量处于标记值状态,只能够赋值,不能够用于其他操作。在准备阶段,给i开辟内存空间,并且设定一个标记值,然后在初始化阶段直接进行相加的操作,因为i还是处于标记值状态,所以直接编译不通过。
public class StaticDemo3 {
public static void main(String[] args) {
System.out.println(StaticDemo.i);
}
}
class StaticDemo{
static int i;
static{
i = 5;
}
}
结果:5
分析:在准备阶段,给i开辟内存空间,并且设定一个标记值。然后在初始化阶段先执行静态变量,再执行静态代码块将5赋值给i,并且舍弃标记值。所以结果就是5。
(9)例题
public class StaticDemo3 {
public static void main(String[] args) {
System.out.println(StaticDemo.i);
}
}
class StaticDemo{
static{
i = 5;
}
static int i = 3;
}
结果:3
分析:在准备阶段,给i开辟内存空间,并且设定一个标记值。然后在初始化阶段先执行静态代码块中的i=5的代码,舍弃标记值,将5赋值给i,再执行i = 3代码,将3赋值给i,所以结果就是3。