static关键字
关于java中的static关键字:
1、static翻译为:静态的;
2、static修饰的方法称为静态方法;
3、static修饰的变量称为静态变量;
4、所有static修饰的元素都称为静态的,都可以使用“类名.”的方式访问,当然也可以用引用.的方式访问【但不建议】;
5、static修饰的所有元素都是类级别的特征,和具体的对象无关;
1 static修饰的变量——静态变量
不使用静态变量的程序:
public class User {
String country;
String name;
String cardId;
int num; //成员变量[实例变量]
public User(String country, String name, int num){
this.country = country;
this.name = name;
this.num = num;
}
}
如上,声明在类体中的称为成员变量,这些变量同时也是实例变量,需要根绝创建的对象进行调用,调用语法格式:引用.变量名。这样带来新的问题是:如果该用户类的"country"属性始终为“中国”,但是每次调用对象都需要在堆区内存中开辟空间并赋值,造成浪费。这个时候可以将该属性使用static进行修饰,如此不必伴随对象创建开辟空间而不断赋重复的值。
public class User {
static String country = "中国";
/*
由于所有对象国籍都相同,这种特征属于类级别的特征,可以提升为类级别的特征,
即提升为整个模板的特征,可以在变量前添加static关键字修饰。
*/
String name;
String cardId;
int num; //成员变量[实例变量]
public User(String name, int num){ //有参构造器
this.name = name;
this.num = num;
}
}
静态变量在类加载的时候进行初始化,不需要创建对象,就已经开辟内存了。
在测试类中对比:
public class UserTest {
public static void main(String[] args){
User you = new User("you",0);
User me = new User("me",1);
User him = new User("him",2); //创建3个实例对象
System.out.print("姓名:"+you.name+",编号:"+you.num+",国籍:"+User.country);
System.out.print("姓名:"+me.name+",编号:"+me.num+",国籍:"+User.country);
System.out.print("姓名:"+him.name+",编号:"+him.num+",国籍:"+User.country);
//带有static修饰的成员变量是“类”级别的
}
}
在上面的测试类程序中观察到,静态变量的访问方式为:类名.变量名。
这里对成员变量什么时候声明为实例变量和什么时候声明为静态变量做一下区分:
什么时候成员变量声明为实例变量呢?
* 所有对象都有这个属性,但是这个属性的值会随着对象的变化而变化【不同对象的这个属性具体的值不同】
什么时候成员变量声明为静态变量呢?
* 所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销。
提出小问题:如果在上述的测试类中使用创建的对象对静态变量访问会发生什么情况?
//对静态变量用正常方式访问
System.out.print(User.country); //输出为:中国
//使用创建的对象访问静态变量
System.out.print(you.country); //输出为:中国
//虽然这里可以正常输出,但是改变对象指向,将创建的对象you指向空
you = null;
System.out.print(you.country); //输出为:中国
//在对象指向空的情况下,仍然能访问到该变量中存储的值,说明内部依然采用的类名.静态变量的方法访问
2 static定义的“静态代码块”
可以使用static关键字来定义“静态代码块”:
1、语法格式:
static{
java语句;
}2、静态代码块在类加载时执行,并且只执行一次。
3、静态代码块可以在一个类中编写多个,并且遵循自上而下的顺序依次执行。
4、静态代码块的作用是什么?怎么用?用在哪儿?什么时候用呢?
-比如项目中要求在类加载的时刻/时机执行代码完成日志的记录。那么这段记录日志的代码可以编写到静态代码块当中,完成日志记录。
-静态代码块是java为程序员准备的特殊时刻(类加载时刻),如果希望这个时候执行一段特殊的程序,就可以直接放到静态代码块当中。根据业务需求:业务日志可以添加在这里静态代码块中,方便程序员。可以在开发过程中完成一些初始化工作。————预备机。
下面代码中定义了静态代码块:
public class StaticTest {
static{
System.out.println("类加载的时候执行!");
System.out.println("不能写第二句吗?可以!");
}
static{
System.out.println("第二个语句~");
}
public static void main(String[] args) {
System.out.println("main begin!");
}
}
观察输出:
类加载的时候执行!
不能写第二句吗?可以!
第二个语句~
main begin!
由此可见,静态代码块在类加载时执行(在main()方法前面执行)。
3 实例语句块/代码块(了解内容)
从静态代码块联想实例代码块对比,实例代码块作为了解内容。
实例代码块-了解内容:
1、实例代码块可以编写多个,遵循自上而下的顺序执行;
2、实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次;
3、实例代码块也是java语言为程序员准备的一个特殊的时机;这个特殊时机被称为对象初始化时机;
下面程序中定义了实例代码块、main()方法以及构造方法,观察输出的顺序:
public class Test {
//构造函数
public Test(){
System.out.println("缺省构造器执行!");
}
//实例代码块1
{
System.out.println(1);
}
//实例代码块2
{
System.out.println(2);
}
//实例代码块3
{
System.out.println(3);
}
public static void main(String[] args) {
System.out.println("main begin!");
new Test();
new Test(); //警告:Class initializer may be 'static'
}
}
输出结果:
main begin!
1
2
3
缺省构造器执行!
1
2
3
缺省构造器执行!
由此可见,实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次。该输出顺序和构造方法放在程序中main()方法的前面还是后面没有关系。
4 方法什么时候定义为静态的?
方法什么时候定义为静态的?
方法描述的是动作,当所有的对象执行这个动作的时候,最终产生的影响是一样的。那么 这个动作已经不属于某一个对象的具体操作,可以将该方法提升为类级别的方法,作为模板级别的操作。
使用static修饰的静态方法比如有main()方法:
public class MainTest {
//构成方法重载的3个main方法
public static void main(String[] args) {
main(10);
main("打印字符串内容~");
}
public static void main(int i){
System.out.println(i);
}
public static void main(String args){
System.out.println(args);
}
}
对比静态方法和动态方法:
public class Test {
int i = 10; //实例变量
public void doSome(){ //实例方法
System.out.println("实例方法doSome执行!");
}
public static void main(String[] args) {
//想要访问实例元素需要创建对象
StaticTest st = new StaticTest();
System.out.println(st.i);
st.doSome();
st.doOther();
}
public void doOther(){
//实例方法访问实例元素才可以使用this,是当前调用当前创建的同一个对象的元素
System.out.println("doOther执行区间-头");
System.out.println(this.i);
this.doSome();
//这里this还可以省略,除非局部变量的变量名和实例变量名重复,产生冲突,这时候this才不能省去。
System.out.println("doOther执行区间-尾");
}
}
经过对比,静态方法无法直接访问实例变量和实例方法。 大多数方法都定义为实例方法,一般一个行为或者一个动作在发生的时候,都需要对象的参与。
例外:“工具类”中的方法都是静态方法,因为工具类就是方便编程,为了方便方法的调用,不用new对象比较方便。
“工具类”例如将System.out.print()该输出语句进行封装,可以定义类名为S,创建引用p,在测试程序中创建该对象,这个时候使用输出语句则为S.p(); 简化了输出写法。
5 总结
一个类中可以编写的内容:
class 类名{
静态代码块; //类加载的时候执行
实例代码块; //构造器执行之前执行,构造器执行一次,实例代码块执行一次
//属性/状态
实例变量; //引用.实例变量名;
静态变量; //类名.静态变量名;
//方法/动作
构造器;
实例方法; //引用.方法名;
静态方法; //类名.方法名;
}
//除了上述的还讲了this关键字和static关键字。