在一个类中,如果此类对象共同拥有一些资源如何表示呢?比如“张三”和“李四”同属于人类,共同拥有10个苹果,那么我们不能简单写int apple=10;作为人类的成员属性,而必须加一个static关键字
static关键字可以修饰成员属性、成员方法、成员代码块,被static修饰后,分别叫做
- 类属性(或静态属性)
- 类方法 (静态方法)
- 类代码块(静态代码块)
在被static修饰后,该属性、方法,由该类所拥有。
调用方式
可以通过类名.属性(或方法)调用
public class Human {
public static int apple = 10; // 人类共有的
public int banana = 10; // 人类对象特有的
public static void main(String[] args) {
System.out.println(Human.apple); // 不需要实例化对象就可以调用
System.out.println(apple); // 类的内部可以直接调用静态方法
Human zs = new Human();
System.out.println(zs.apple); // 可以对象名调用
}
}
可以使用 对象名.属性(或方法)调用,但是不推荐,这样在阅读时很容易误解为成员变量。
在同一个类中,(被static修饰后)任意地方均可以直接使用名称调用。
如何证明static修饰的由类所拥有?请参考以下代码:
public class Human {
public static int apple = 10; // 人类共有的
public int banana = 10; // 人类对象特有的
public Human(){
Human.apple--;
this.banana--;
}
public static void main(String[] args) {
Human zs = new Human();
Human ls = new Human();
System.out.println(zs.banana);
System.out.println(ls.banana);
System.out.println(apple);
}
}
程序执行结果:
- 9
- 9
- 8
注意,不可以使用 this.属性(或方法)调用,即不可以使用this、super关键字
静态代码加载
静态代码加载优先于非静态方法。你可以这么理解,静态代码是属于类的,而非静态是属于对象的,类在被加载时就会给静态代码创建内存空间,而非静态必须实例化对象。
那么静态方法不可以调用非静态方法,因为此时非静态方法还未被加载到内存,反过来却是可以的,例如以下代码:
public class Human {
public static int apple = 10; // 人类共有的
public int banana = 10; // 人类对象特有的
public void sub(){
add();
}
public static void add(){
sub(); // 编译报错
}
}
静态代码块
静态代码块,在类被初始化时(本节不讨论此问题,假设被调用),就会触发。
静态代码块只会执行一次,成员代码块在每次实例化均会执行,参考以下代码:
public class Human {
public static int apple = 10; // 人类共有的
public int banana = 10; // 人类对象特有的
{
System.out.println(1);
}
static {
System.out.println(2);
}
public static void main(String[] args) {
Human zs = new Human();
Human ls = new Human();
}
}
程序执行结果:
- 2
- 1
- 1
上述代码能证明2件事,①静态代码优先于非静态②静态代码只会执行一次
方法区
方法区,又叫静态区(实际并不等价,仅粗略介绍),主要包含了类信息,以及存放了被static修饰的变量等资源
这里并不对方法区进行详细的讨论,仅表示static修饰变量在内存中的位置。
方法区是线程共享的,开销比较大,故方法区对每个类存放的内容大小进行了限制,一个类中被static修饰的代码编译而成的字节码不得超过64kb。
这里要表达的意思是,要合理的使用static而不要滥用,否则不但不能减少内存使用,反而增加开销。