一、static基本描述
对于关键字static,一定不陌生,因为我们天天写:
public static void main(String[]args){...}
那么static表示什么呢?
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但需要注意一点:java语言中没有全局的概念。
二、使用static定义属性(类属性)
首先来看一个表示Person的操作类,所有的人都来自中国。
class Person{
String name;
int age;
String Country = "中国";
public Person(String name,int age) {
super();
this.age = age;
this.name = name;
}
public void getPersonInfo() {
System.out.println("姓名:"+this.name+",年龄:"+this.age
+",国家:" +this.Country);
}
}
public class TestDemo {
public static void main(String[]args){
Person p1 = new Person("张三", 18);
Person p2 = new Person("李四", 3);
p1.Country = "美国";
p2.Country = "加拿大";
p1.getPersonInfo();
p2.getPersonInfo();
}
}
运行结果如下:
姓名:张三,年龄:18,国家:中国
姓名:李四,年龄:3,国家:中国
内存分配图如下:
传统属性所具备的特征:保存在堆内存中,且每个对象独享属性。
那么问题来了,既然这个类中所有的人均来自中国,那么每个图示对象还有必要占有重复的属性信息吗?
假设有1000个Person类对象,要求所有的国家更换名称,这意味着什么?
修改上述主方法如下:
public class TestDemo {
public static void main(String[]args){
Person p1 = new Person("张三", 18);
Person p2 = new Person("李四", 3);
p1.Country = "美国";
p2.Country = "加拿大";
p1.getPersonInfo();
p2.getPersonInfo();
}
}
运行结果:
姓名:张三,年龄:18,国家:美国
姓名:李四,年龄:3,国家:加拿大
这意味着要修改1000个对象的内容,如果将对象的属性定义为普通属性,这就意味着每一块堆内存都保存着各自的信息。
描述共享属性,只需在属性前加static关键字即可
static属性又称为类属性,保存在全局数据区的内存中,所有的对象都可以进行数据区的访问
对于范例来说,既然每个Person类的Country内容是一样的,那么应该将其定义为一个共享的属性,所有的对象都共享Country属性。
static String Country = "中国";
主方法为:
public class TestDemo {
public static void main(String[]args){
Person p1 = new Person("张三", 18);
Person p2 = new Person("李四", 3);
p1.Country = "美国";
p1.getPersonInfo();
p2.getPersonInfo();
}
}
运行结果:
姓名:张三,年龄:18,国家:美国
姓名:李四,年龄:3,国家:美国
我们发现,一旦属性定义上使用了static之后,只要有一个对象修改了属性的内容,那么所有的对象的这个static属性的内容都一起修改,此时Country就是一个公共属性。
于是,内存分配图也变为了如下这样:
static声明的属性与普通属性(非static属性)最大的区别就是:保存区域的不同。
既然static定义的属性是公共属性,那么如果只是简单的单由一个对象去修改这个属性的做法是不合适的。合适的做法就是:由所有对象的公共代表——类来修改,即“类名称.static属性”来修改。
就以上范例来说就是将
p1.Country = "美国";
用下面这个来替代
Person.Country = "美国";
小结:
- 使用static定义的属性不在堆内存之中保存,保存在全局数据区;
- 使用static定义的属性表示类属性,类属性可以通过类名称直接调用;
- static属性虽然定义在类中,但其实可以在没有实例化对象的时候进行调用(普通属性保存在堆内存里,而static属性保存在全局数据区中)
在定义属性的时候,什么时候要static定义?什么时候不使用static定义呢?
在开发中,尽量不使用static定义属性,如果需要描述共享信息的时候,才使用static定义,主要是为了方便集体修改,且不重复分配内存空间。
三、static定义方法
static可以定义属性外,方法上也可以使用static进行定义,那么很明显使用static定义的方法也可以在没有实例化对象产生的情况下由类名称直接进行调用。
范例(观察下面的static方法):
class Person{
String name;
int age;
static String Country = "中国";
public Person(String name,int age) {
super();
this.age = age;
this.name = name;
}
//static 方法
public static void setCountry(String C){
Country = C;
}
public void getPersonInfo() {
System.out.println("姓名:"+this.name+",年龄:"+this.age
+",国家:" +this.Country);
}
}
public class TestDemo {
public static void main(String[]args){
//在对象产生前进行调用
Person.setCountry("冰岛");
Person p1 = new Person("张三", 18);
Person p2 = new Person("李四", 3);
p1.getPersonInfo();
p2.getPersonInfo();
}
}
运行结果:
姓名:张三,年龄:18,国家:冰岛
姓名:李四,年龄:3,国家:冰岛
关于static方法有以下两点说明:
- 所有的static方法不允许调用非static定义的属性或方法
- 所有的非static方法允许访问static方法或属性
使用static定义的方法目的只有一个:某些方法不希望受到对象的控制,即可以在没有实例化对象的时候执行(广泛存在于工具类中)
什么时候使用static方法呢?
如果一个类中没有任何属性,只有方法,建议可以将所有的方法定义为static方法,这样每次调用方法得时候就可以不进行实例化了,在实际开发中,建议优先考虑非static方法和非static属性。
四、java主方法
java方法定义时,如果一个方法在主类中定义,并且方法直接调用的时候,那么前面必须有 public static,格式如下:
public static 返回值类型 方法名称(参数列表) {
[return [返回值];]
}
范例:
public class TestDemo1 {
public static void print() {
System.out.println("Hello wfg");
}
public static void main(String[]args) {
print(); //直接调用
}
}
运行结果:
Hello wfg
此时,表示的是一个static方法调用其他的static方法,但是如果这个print()方法没有static呢?
public class TestDemo1 {
public void print() {
System.out.println("Hello wfg");
}
public static void main(String[]args) {
print(); //直接调用
}
}
运行结果:
Error:(13, 9) java: 无法从静态上下文中引用非静态 方法 print()
所有的非static方法几乎都有一个特点:方法要由实例化对象调用。正确写法如下:
public class TestDemo1 {
public void print() {
System.out.println("Hello wfg");
}
public static void main(String[]args) {
new TestDemo1().print(); //对象调用
}
}
运行结果:
Hello wfg
回过头看主方法的组成:
public static void main(String[]args) {...}
(1)public:是一种访问权限,表示公共;
(2)static:此方法由类名称直接调用;
(3)void:主方法是程序执行的开始;
(4)main:系统规定的一个方法名称,执行类的时候默认找到此名称,不能更改;
(5)String arg[] :表示程序运行时传递的参数,通过字符串接收。
五、static实用实例
统计一个类产生的实例化对象个数
分析:一个类肯定有多个实例化对象产生,增加一个统计操作,可以统计一个类中的所产生的实例化对象个数,如果现在要产生新的实例化对象,则一定会调用类的构造方法,所以可以在构造方法中增加统计,而且这个统计的变量是所有对象共享的,应该讲其定义为static属性
范例:
class Obj{
private static int count = 0;
public Obj() {
System.out.println("count"+ ++count);
}
}
public class TestDemo1 {
public static void main(String[]args){
new Obj();
new Obj();
new Obj();
new Obj();
new Obj();
new Obj();
new Obj();
}
}
运行结果:
count1
count2
count3
count4
count5
count6
count7