1.背景案例 代码及结果展示
- 在一个文件夹下有两个类:狗类、人类
/**
* 狗类.
* 用于静态方法的展示
*/
public class Dog{
public static void main(String[] args) {
bark();
new Dog().bark();//两者均可
cry();
new Dog().cry();//两者均可
new Dog().sleep();//只能先实例化,再调用
new Dog().eat();//只能先实例化,再调用
}//main方法结束
public static void bark(){
System.out.println("汪汪汪...");
}
private static void cry(){
System.out.println("哼哼唧唧...");
}
public void sleep(){
System.out.println("zZZ...");
}
private void eat(){
System.out.println("舔舔舔...");
}
}//Dog类结束
>java Dog
运行结果如下:
汪汪汪...
汪汪汪...
哼哼唧唧...
哼哼唧唧...
zZZ...
舔舔舔...
/**
* 人类.
* 用于调用狗类,展示静态方法与非静态方法的区别.
*/
public class Human{
public static void main(String[] args) {
Dog.bark();
new Dog().bark();
// Dog.cry();//会报错 : Human.java:11: 错误: cry() 在 Dog 中是 private 访问控制
/* Dog.sleep();
Human.java:13: 错误: 无法从静态上下文中引用非静态 方法 sleep()
Dog.sleep();
^ */
// 两者均可
new Dog().sleep();//第一张
Dog myDog = new Dog();
myDog.sleep();//第二种
// new Dog().eat();//会报错 : Human.java:23: 错误: eat() 在 Dog 中是 private 访问控制
}
}
>java Human
运行结果如下:
汪汪汪...
汪汪汪...
zZZ...
zZZ...
2.代码分析及应用
-
内部调用
1.在类内部,静态方法可以被其他方法直接以methodName(paraList);
方式调用。
2.在类内部,想要调用非静态方法,必须先实例化本对象,再调用,
即以new thisClassName().methodName(paraList);
方式调用。 -
外部调用
1.在类外部,静态方法可以直接用className.methodName(paraList)
方式调用。
2.在类外部,想要调用非静态方法,必须先实例化该类对象,再调用,
即以new thisClassName().methodName(paraList);
方式调用。 -
不管是静态方法还是非静态方法,均遵循访问权限的规则(public default protected private)
3.原理分析
-
问题:jvm什么时候会立即对类进行初始化:
-
虚拟机规范严格规定了有且只有四种情况必须立即对类进行初始化:
1)使用new关键字实例化对象
2)读取一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
3)设置一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
4)调用一个类的静态方法
具体请参见博文:Java类初始化顺序 -
也就是说,在调用一个类的静态方法时,这个类就立即会被初始化,类的初始化会进行 : 类变量赋值 和 执行静态代码块
-
因此,静态方法是不需要先用new关键字实例化一个对象的。