static关键字
如果使用一个类则会在实例化对象时分别开辟栈内存及堆内存,在堆内存中要保存对象中的属性,每个对象都有自己的属性,如果你现在有些属性希望被共享,则就必行将其声明为static属性,而且一个属性声明为static属性,可以直接使用类名称进行调用,如果一个类中的方法想由类调用,则可以声明为static方法。
一. 使用static声明属性
如果程序中使用static声明属性,则属性成为全局属性(有些也称为静态属性),那么声明为全局属性到底有什么用吶?观察以下代码:
class Person{ // 定义Person类
String name ; // 定义name属性,暂时不封装
int age ; // 定义age属性,暂时不封装
String country = "A城" ; // 定义城市属性,有默认值
public Person(String name,int age){
this.name = name ;
this.age = age;
}
public void info(){ // 得到信息
System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ;
}
};
public class StaticDemo01{
public static void main(String args[]){
Person p1 = new Person("张三",30) ; // 实例化对象
Person p2 = new Person("李四",31) ; // 实例化对象
Person p3 = new Person("王五",32) ; // 实例化对象
p1.info() ;
p2.info() ;
p3.info() ;
}
};
运行结果:
姓名:张三,年龄:30,城市:A城
姓名:李四,年龄:31,城市:A城
姓名:王五,年龄:32,城市:A城
以上代码,为了观察方便没有使用private关键字进行封装。以上的程序是一个简单的程序,但是代码中有些不妥之处。
实际上,如果现在假设此城市不叫A城,而改为了B城,而且此类产生了200个对象,那么就意味着要把这些对象的城市属性全部修改一边。这样显然是不行的。最好的方法是修改一次就可以,此时可以把城市属性使用static关键字进行声明,将其变为公共属性。
使用static声明属性:
class Person{ // 定义Person类
String name ; // 定义name属性,暂时不封装
int age ; // 定义age属性,暂时不封装
static String country = "A城" ; // 定义城市属性,有默认值,static
public Person(String name,int age){
this.name = name ;
this.age = age;
}
public void info(){ // 得到信息
System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ;
}
};
public class StaticDemo02{
public static void main(String args[]){
Person p1 = new Person("张三",30) ; // 实例化对象
Person p2 = new Person("李四",31) ; // 实例化对象
Person p3 = new Person("王五",32) ; // 实例化对象
System.out.println("--------------- 修改之前 -------------") ;
p1.info() ;
p2.info() ;
p3.info() ;
p1.country = "B城" ; // 修改static属性
System.out.println("--------------- 修改之后 -------------") ;
p1.info() ;
p2.info() ;
p3.info() ;
}
};
运行结果:
--------------- 修改之前 -------------
姓名:张三,年龄:30,城市:A城
姓名:李四,年龄:31,城市:A城
姓名:王五,年龄:32,城市:A城
--------------- 修改之后 -------------
姓名:张三,年龄:30,城市:B城
姓名:李四,年龄:31,城市:B城
姓名:王五,年龄:32,城市:B城
从程序的运行结果和代码可以看出,只修改了一个对象的城市属性,则全部对象的城市属性内容都发生了变化,说明使用static声明的属性是所有对象共享的。
*PS:Java中常用的内存区域:
(1) 栈内存空间:保存所有的对象名称(更准确的说是保存了引用的堆内存空间的地址)
(2) 堆内存空间:保存每个对象的具体属性内容
(3) 全局数据区:保存static类型的属性
(4) 全局代码区:保存所有的方法定义*
上述代码虽然进行了修改,但是是一个对象修改了类中的属性,这样是不合适的,类的公共属性应该由类进行修改是最合适的。所以以上代码在访问static属性时最好可以由类名称直接调用,那么有时也就把使用static声明的属性成为类属性
【类属性调用】
类名称.static 属性
所以以上代码在访问country属性时最好使用以下代码:
Person.country=”B城”;
二. 使用static声明方法
static既可以在声明属性时使用,也可以用来声明方法,用它来声明方法有时也被称为“类方法”,可以由类名称直接调用。
【使用static声明方法】
class Person
{
private String name;
private int age;
private static String country="A";
public static void setCountry(String c){
country=c;
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void info(){
System.out.println("姓名:"+this.name+",年龄:"+this.age+",城市"+country);
}
public static String getCountry(){
return country;
}
};
public class StaticDemo04
{
public static void main(Stirng[] args){
Person p1=new Person("张三",30);
Person p2=new Person("李四",31);
Person p3=new Person("王五",32);
System.out.println("------修改之前-------");
p1.info();
p2.info();
p3.info();
System.out.println("------修改之后-------");
Preson.setCountry("B城");
p1.info();
p2.info();
p3.info();
}
}
运行结果:
------修改之前-------
姓名:张三,年龄:30,城市A
姓名:李四,年龄:31,城市A
姓名:王五,年龄:32,城市A
------修改之后-------
姓名:张三,年龄:30,城市B城
姓名:李四,年龄:31,城市B城
姓名:王五,年龄:32,城市B城
在以上的程序中,Person类将所有的属性都进行了封装,所以要想设置属性就必须使用setter()方法,但是这里的方法是使用static声明的,所以可以直接使用类名称调用。*另外,在此处需要说明的是,非static声明的方法可以去调用static声明的属性或方法,但是static声明的方法不能调用非static声明的属性或方法。
static是不能调用任何非static内容的,这一点实际上也不理解,因为在程序中所有的属性和方法必须在对象开辟堆内存之后才可以调用,而static类型的方法在对象未被实例化时就可以被类名调用,所以如果直接由static方法调用非static操作,则有可能在属性还没有被初始化时就被调用了,这一点在语法上就讲不通了*。
三. static相关应用
下面介绍两个static的相关引用实例。从前面的讲解中可以知道static属性时所有对象共享的,那么就可以使用static属性来统计类产生了多少个实例化的对象。
class Demo{ // 定义Person类
private static int count = 0 ; // 所有对象共享此属性
public Demo(){
count++ ; // 只要有对象产生就应该自增
System.out.println("产生了" + count + "个对象!") ;
}
};
public class StaticDemo06{
public static void main(String args[]){
new Demo() ; // 增加新对象
new Demo() ; // 增加新对象
new Demo() ; // 增加新对象
}
};
运行结果为:
产生了1个对象!
产生了2个对象!
产生了3个对象!
从代码中可以看出,只要一有实例化对象产生,则一定会调用其中的构造方法,所以在构造方法中将static声明的属性count进行自增,这样就可以计算出类产生了多少个实例化对象
四. 理解main方法
之前在使用main方法时,一直都有static关键字的存在,那么每个参数的含义是什么那:
public:表示此方法可以被外部调用;
static:表示此方法可以由类名称直接调用;
void:表示主方法是程序的起点,所以不需要任何返回值;
main:系统默认调用的方法名称,执行时默认找到main方法名称;
String[] args:表示运行时的参数,参数传递的形式为“java类名称 参数1,参数2,,,,”