面向对象程序设计中和面试中会经常问到有关静态类或静态方法的问题。如“java中静态方法不能调用非静态方法或变量”;“静态类中能不能有非静态方法”;“非静态类中是否可以有静态方法”等。这个是对静态类及静态成员和普通类及实例化方法的概念及JVM处理机制的考核
静态类与非静态类(普通类)
普通类:在面向对象中一个普通类只有创建实例才可以使用,普通类中的创建实例时首先会执行构造函数完成初始化,普通类中非静态方法依赖这些初始化的结果的或其他方法的执行结果,和它所在的存在实例。如:普通类中某个方法需要调用所在实例中的某个对象。
public class Context {
// 当前策略
private Istrategy strategy;
public void setStrategy(Istrategy strategy) {
this.strategy = strategy;
}
// 计算价格
public double cul(double consumePrice) {
double realPrice = this.strategy.realPrice(consumePrice);
// 格式化保留小数点后1位,即:精确到角
BigDecimal bd = new BigDecimal(realPrice);
bd = bd.setScale(1, BigDecimal.ROUND_DOWN);
return bd.doubleValue();
}
}
这里的计算价格(cul)方法,依赖于Context类创建的对象在运行时注入的Istrategy 对象。
如果一个方法与他所在类的实例对象无关,那么它就可以设置为静态方法。
普通类是创建实例时才分配内存的,不会常驻内存,当实例对象被JVM 回收之后,也跟着消失,普通类在类加载时仅将其静态的资源读入内存。
静态类:静态类则无需创建实例,用户可以直接使用类中的方法和属性,这时我们可以将静态类中的方法想象成面向过程函数,这些函数由于完成某一种相近的功能,封装在一起,对于程序中任何实例的调用都是一样的,和它所在的实例无关。如我们就可以将数据位制的转换封装成一个独立的静态类,无论那个实例调用,2进制转16进制、8进制转10进制都是一样的。
静态类在JVM类加载时就被装载到内存,属于全局性,随时可以使用,不自动进行销毁,会一直存在于内存中,直到JVM关闭。
因此在静态方法不能调用普通类的非静态方法或变量。那么加载的时候初始化static的成员,而普通类尚未实例化,此时其中非静态方法还没有被加载到内存,当然不能使用。
静态类中不能包含非静态方法,如果不按照这种规则静态类编译器会检查报错
常用的工具类方法,没有对其进行重载的必要,那么将它们声明为 static,可以加速方法的调用
小结
- 没有属性的类,一般会定义静态方法,就是一个方法的集合,类似面向过程中的函数集。
- 静态类中所有的成员必须是静态成员,不能包含非静态方法
- 普通类中可以包含静态方法,静态成员不一定都在静态类中
- 静态成员等同于全局变量,整个系统中存在静态区中,是共享的
- 静态方法可以被继承但是不能被覆盖,不能使用override重置