Java中的static关键字
来源:互联网 发布:淘宝卖家更换支付宝 编辑:程序博客网 时间:2024/06/01 22:57
什么是static?static关键字可以用来做什么?
static表示“全局” 或者“静态”的意思,它是一个修饰符,可以用来修饰方法、变量、代码块、类。
静态对象和非静态对象的区别(这里对象的意思不是指实例化对象,用来代表方法、变量):
1)静态对象是所有实例化对象所共同拥有的,即共享的,而非静态变量是类的各个实例化对象独立拥有的;
2)静态对象随着类的加载而加载,也意味着随着类的消失而消失。生命周期最长;
3)静态对象的内存空间是固定的,而非静态变量的内存空间是在实例化对象时才会被分配;
4)静态对象可以直接被类名调用,是属于类的,
非静态对象被对象调用的,是属于具体对象的;
1、修饰变量
静态变量与成员变量最大的特点是,静态变量在整个程序中都是唯一的,例:
public class Test2 { public static void main(String[] args) { Animal t1 = new Animal(); Animal t2 = new Animal(); //类名.变量调用 System.out.println(Animal.voice); //对象.变量调用 System.out.println(t1.voice); t1.voice += " world"; System.out.println(t2.voice); //再次类名.变量调用 System.out.println(Animal.voice); }}class Animal {public static String voice="hello";}
输出结果为:
hellohellohello worldhello world
可以看出静态变量的方法的值是唯一的,一旦改变,再次调用该静态变量时只会是改变后的值
2、修饰方法
调用方法和静态变量调用方法一致,可以直接使用类名来调用静态方法,静态方法有几点需要注意:
1)它们仅能调用其他的static方法。
2)它们只能访问static数据。
3)它们不能以任何形式引用this或super。
package com.good;public class Test3 {public static void main(String[] args) {Cat.run();Cat cat = new Cat();cat.run();}}class Cat {private static int count=0;private String s1 = "s1";private static String s2 = "s2";public static void run(){System.out.println("猫跑了" + count++ + "步");String s3 = "s3";//System.out.println(s1);//错误!只能调用static数据;//System.out.println(this.s1);//错误!无法调用this或superSystem.out.println(s2);//调用类里的静态变量System.out.println(Cat.s2);System.out.println(s3);//调用方法里的变量System.out.println(Dog.s4);//调用其他类里的静态变量Dog.run();//调用其他类里的静态方法}}class Dog {public static String s4 = "s4";private static int count = 0;public static void run(){System.out.println("狗跑了" + count++ + "步");}}
输出结果:
猫跑了0步s2s2s3s4狗跑了0步猫跑了1步s2s2s3s4狗跑了1步
3、修饰类
通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的类可以直接作为一个普通类来使用,而不需要实例一个外部类
public class StaticCls { public static void main(String[] args) { OuterCls.InnerCls oi = new OuterCls.InnerCls(); }} class OuterCls { public static class InnerCls { InnerCls() { System.out.println("InnerCls"); } }}
结果为:InnerCls
4、修饰代码块
static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法
1)在程序的一次执行过程中,static{}语句块中的内容只被执行一次,看下面的示例:
package com.good;public class StaticBlockTest {public static void main(String args[]) {try {Class.forName("com.good.Test");Class.forName("com.good.Test");Test t1 = new Test();Test t2 = new Test();} catch (Exception e) {e.printStackTrace();}}}class Test {public static int X = 100;public final static int Y = 200;public Test(){ System.out.println("Test构造函数执行"); }static {System.out.println("static语句块执行");}public static void display() {System.out.println("静态方法被执行");}public void display_1() {System.out.println("实例方法被执行");}}
运行结果:
static语句块执行Test构造函数执行Test构造函数执行
可以看出虽然执行了两条Class.forName("com.good.Test")语句,但是,只输出了一条"static语句块执行";其实第二条Class.forName()语句已经无效了,因为在虚拟机的声明周期中一个类只被加载一次;又因为static{}是伴随类的加载而执行的,所以不管你new多少次实例对象,static{}都只执行一次
static{}的应用:
1)jdbc中的应用
熟悉JDBC的读者应该知道,java中有一个DriverManager类,用于管理各种数据库驱动程序、建立新的数据库连接。DriverManager类包含一些列Drivers类,这些Drivers类必须通过调用DriverManager的registerDriver()方法来对自己进行注册,那么注册是什么时候发生的呢?下面会给出答案:
所有Drivers类都必须包含有一个静态方法,利用这个静态方法可以创建该类的实例,然后在加载该实例时向DriverManage类进行注册。我们经常用Class.forName()对驱动程序进行加载,那么注册就发生在这条语句的执行过程中,前面说的Drivers的静态方法是放在static{}中的,当对驱动程序进行加载的时候,会执行该static{},便完成了注册。
2)hibernate中的应用hibernate中的SessionFactory是一个重量级的类,创建该类的对象实例会耗费比较多的系统资源,如果每次需要时都创建一个该类的实例,显然会降低程序的执行效率,所以经常将对该类的实例化放在一个static{}中,只需第一次调用时执行,提高程序的执行效率,如下:
static { try { configuration.configure(configFile); sessionFactory = configuration.buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } }
二、类的加载特性
在虚拟机的生命周期中一个类只被加载一次
类加载的原则:延迟加载,能少加载就少加载,因为虚拟机的空间是有限的
类加载的时机:
1)第一次创建对象要加载类
2)调用静态方法时要加载类,访问静态属性时会加载类
3)加载子类时必定会先加载父类
4)创建对象引用不用加载类
5)子类调用父类的静态方法时
a、当子类没有覆盖父类的静态方法时,只加载父类,不加载子类
b、当子类有覆盖父类的静态方法时,既加载父类,又加载子类
6)访问静态常量,如果编译器可以计算出常量的值,则不会加载类,例如:public static final int a = 123;否则会加载类,例如:public staticfinal int a=math.PI;
三、趣题小练
1:猜一猜输出结果
package com.good;public class StaticTest {public static void main(String[] args) {staticFunction();}static StaticTest st = new StaticTest();static{System.out.println("1");}{System.out.println("2");}StaticTest(){System.out.println("3");System.out.println("a=" + a + "b=" + b);}public static void staticFunction(){System.out.println("4");}int a = 110;static int b;}
输出结果:
23a=110b=014
分析:
1、类的生命周期是:加载->验证->准备->解析->初始化->使用->卸载,只有在准备阶段和初始化阶段才会涉及类变量的初始化和赋值,因此只针对这两个阶段进行分析;
2、类的准备阶段需要做是为类变量分配内存并设置默认值,因此类变量st为null、b为0;(需要注意的是如果类变量是final在加载阶段就已经完成了初始化,可以把b设置为final试试);
3、类的初始化阶段需要做是执行类构造器,先执行第一条静态变量的赋值语句即st = new StaticTest (),此时会进行对象的初始化,对象的初始化是先初始化成员变量再执行构造方法,因此打印2->设置a为110->执行构造方法(打印3,此时a已经赋值为110,但是b只是设置了默认值0,并未完成赋值动作),等对象的初始化完成后继续执行之前的类构造器的语句
4、接下来再按顺序输出1、4
2:
package com.good;public class StaticTest2 {public static void main(String[] args) {new Child().printX();}}class Child extends Father{static{System.out.println("child--static");}private String n = "20";{n = "30";}//public int x = 200;static{System.out.println("child--static");}public Child(){this("the other constructor");System.out.println("child constructor Body:" + n);}private static String ff = "ddd";public Child(String s) {System.out.println(s);}public void age(){System.out.println("age="+n);}public void printX(){System.out.println("x="+x);}}class Father{static{System.out.println("super--static");}public static String n= "a";public int x = 100;public Father(){System.out.println("super's x="+x);age();}public void age(){System.out.println("nothing");}public void printX(){System.out.println("x="+x);}}
输出结果:
super--static
child--static
child--static
super's x=100
age=null
the other constructor
child constructor Body:30
x=100
分析:
1、加载Child()类时,发现这个类需要一个父类Father,所以先加载父类Father,输出super--static,以及将静态变量n初始化
2、再来加载子类的静态块,输出child--static,child--static
3、加载完父类和子类的static部分,再来加载成员变量和构造方法,因为是先加载父类Father,所以先加载父类的构造方法,输出super's x=100
4、执行父类构造方法里的age()方法,age方法已经被子类重写,因此输出子类里的age()方法,因为此时尚未加载子类的成员变量以及构造方法,所以输出age=null
5、加载完父类构造方法后,再加载子类成员变量和构造方法,输出the other constructor、child constructor Body:30
6、最后输出x的值,x继承于父类,在父类Father加载成员变量和构造方法时已经赋值完毕,为100,因此输出x=100
趣题总结:
1、静态变量、静态方法>变量、初始化块>构造器
2、如果存在继承关系,那么加载顺序应该为:父类static>子类static>父类成员变量>父类构造方法>子类成员变量>子类构造方法
- Java中的static关键字
- JAVA中的static关键字
- JAVA中的static关键字
- java中的static关键字
- java中的static关键字
- Java中的static关键字
- Java 中的 static 关键字
- java中的static关键字
- Java中的static关键字
- java中的static关键字
- Java 中的static关键字
- JAVA中的static关键字
- java中的static关键字
- java中的static关键字
- java中的static关键字
- Java中的static关键字
- java中的static关键字
- Java中的关键字static
- 欢迎使用CSDN-markdown编辑器
- 关于win8删除启动项后,不能正常启动(Status 0xc0000098)的解决方案
- JAVA编程思想读书笔记——什么是对象(一)
- ActiveX com插件在某些电脑安装不上问题 gpsvc.dll ieshims.dll
- List使用注意点
- Java中的static关键字
- 吐血中, 调用分享到微信好友,加载的网络图片显示不出来,微信分享,自定义分享标题、内容描述关键词限制(红包)
- python——双重列表推导式+函数,优雅而强大
- iOS中的静态库与动态库,区别、制作和使用
- MFC-在Picture控件中画橡皮筋线
- 移动web性能测试要点
- iPhone开发技巧之调试篇(3)— 程序Crash后的调试技巧
- Java集合框架详解(一)——初步认识集合框架
- 仿映客吐司形式