目录
一、static的用法:
使用:
1、修饰类的成员变量:
2、修饰类的成员方法:
3、修饰代码块:形成静态代码块以优化程序性能。
4、修饰内部类:
二、static的误区(问题思考)
1、static关键字会改变类中成员的访问权限吗?
2、static能作用于局部变量么?
3、在静态的方法内,不能使用this和super关键字:
三、问题思考
1、java中为什么要有static关键字?
①static可以不需要实例化对象就可以访问类中的属性和方法。
②main方法必须用static修饰
③资源必须要优先加载时要static修饰。
关于Java运行的过程大概分为两个步骤:
2、使用static的作用
前端静态资源与java的static修饰的资源类比
3、开发时,如何确定一个属性和方法是否要声明为static
static可以用来修饰类的成员方法、类的成员变量、类中的内部类(以及用static修饰的内部类中的变量、方法、内部类),另外可以编写static代码块来优化程序性能。
方便在没有创建对象的情况下来进行调用(方法/变量)。
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static修饰的成员变量称为静态变量:
静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
static修饰的成员方法称为静态方法:在静态方法中不能访问类的非静态成员方法和非静态成员变量。但是在非静态方法中可以访问静态成员方法和静态成员变量。
public class Person {
//声明静态成员变量:公有的name 和 私有的age——验证访问范围
public static String name = "huahua";
private static int age = 31;
//声明公有的非静态成员变量 tags
public String tags = "sing";
//静态成员方法
public static void print1() {
System.out.println(name);
System.out.println(age);
//静态方法中调用非静态成员变量和非静态成员方法报错!
// System.out.println(tags);//报异常
// print2();//报异常
}
//非静态成员方法——可调用静态成员方法和静态成员变量
public void print2() {
System.out.println(name);
System.out.println(age);
System.out.println(tags);
print1();
}
说到静态函数,就不得不提Java另一个关键词this,指的是当前的引用。意思是调用这个函数的对象,这意味着和static修饰的函数水火不容。被static修饰的函数,不能出现this关键字,否则便会报错。
参考博客:Java关于static的作用 - 一剑天门 - 博客园
static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。
参考:Java中的static关键字解析 - Matrix海子 - 博客园
public class Car extends AbsCar {
//静态内部类中可以用static继续修饰内部类
static class A {
static class B {
static int num0 = 10;
}
}
//静态内部类C
static class C {
int num1 = 10;
}
//普通内部类D
class D{
int num2 =10;
}
public static void main(String[] args) {
int num = A.B.num0;
C c = new C();
int a = c.num1;
}
}
Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。
public class Main {
public static void main(String[] args) {
//通过类直接访问静态成员变量和静态成员方法
System.out.println(Person.name);//公有name,私有的age访问不到
Person.print1();
// 通过类直接访问非静态成员变量和非静态成员方法不可以!——无论公有还是私有
//System.out.println(Person.tags);//非静态的公有tags不可以通过类直接访问
//Person.print2();//通过类直接访问非静态成员方法不可以!
Person person = new Person();
//通过对象访问非静态的公有tags属性和非静态成员方法
System.out.println(person.tags);
person.print2();
}
}
在C/C++中static是可以作用域局部变量的,但是在Java中切记:static是不允许用来修饰局部变量。
理由:
①局部变量最好不要设成静态变量,局部变量是有生命周期的,用完后JAVA很快就回收资源了。
如果设成静态变量,那JAVA怎么回收被其占用的内存。
②在方法里面定义的变量是局部变量,就是说他有一定的作用范围和生命周期,就只能在方法里面使用而不能将其扩展到别的地方,这个变量在方法结束后就会被回收器回收,就不再存在了,而你要强制将其加上static就是要把它的作用范围扩展到整个类,这就与你开始定义这个变量时违背了,这是语法上的错误。
③static 变量是给类用的。这样类初始化的时候,就会给static进行初始化
如果你在方法里面定义一个static。这时候编译器就不知道你这个变量怎么初始化了,这个是和java的设计相关的。java全是面向对象设计的,单独一个方法不能持有一块空间。
④一个类中,一个static变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间。所以声明为static的变量实质上就是全局变量。所以static不能修饰局部变量。
此外,局部变量是存放在栈中的,程序运行完立即释放。它只能在定义它的方法内部使用。所以不用static修饰符。
参考:Java static关键字为什么不能应用于局部变量? - 调试易
this,指的是当前的引用。意思是调用这个函数的对象,这意味着和static修饰的函数水火不容。被static修饰的函数,不能出现this关键字,否则便会报错。
a. 程序被打包成.jar文件后(相当于.exe文件),给外界唯一的接口就是main方法。使用者双击.jar文件,其实就是让虚拟机执行main方法。
b. main方法不是提供给程序员的,而是提供给虚拟机和使用客户的。 一个软件你没法让客户知道你内部的详情,当然客户也就没办法知道怎么去实例化对象,更不知道实例化对象时需要输入什么参数了。所以只能采用静态方法。
java类中所有public和protected的实例方法都采用动态绑定机制,所有私有方法、静态方法、构造器及初始化方法
初始化顺序是先静态对象后非静态对象。当JVM创建一个类的对象时,会先在方法区里边找该类的信息,如果没有,会马上加载该类,把该类的类型信息放到方法区中。简而言之:在JVM创建类对象之前要把类的类型信息(静态变量、静态方法等)放到方法区中。
(1)类的加载
类被加载到虚拟机内存中开始,到卸载出内存为主,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中验证、准备、解析3个阶段称为连接(Linking)(参考《深入了解Java虚拟机》)。类的生命周期如图:
加载:通过一个类的全限定名来获取定义此类的二进制字节流(Class文件);将这个二进制字节流所代表的静态存储结果转化为方法区的运行时数据结构;在内存中生成一个java.lang.Class对象,注意:存放在方法区!
验证:验证目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全;使用纯粹的Java代码无法做到诸如访问数组边界意外的数据、将一个对象转型为它未实现的类型、跳转到不存在的代码之类的事情,如果这样做了,编译器将拒绝编译!
准备:准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。首先这时候进行内存分配的仅包括类变量(static修饰的变量),而不是实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
public static int value = 123;
变量value在准备阶段过后的初始值为0而不是123,因为这时候尚未开始执行任何Java方法,在类初始化的时候才会将value的值赋为123.
解析:解析阶段是虚拟机将class常量池内的符号引用替换为直接引用的过程。
符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可;
直接引用:是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。有了直接引用,那引用的目标必定已经在内存中存在。
初始化:类初始化阶段是类加载过程的最后一步;在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源:初始化阶段是执行类构造器
( )方法的过程。
( )方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static { }块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。
(2)类的执行
需要说明的一点的是:JVM主要在程序第一次运行时主动使用类的时候,才会立即去加载,加载完毕就会生成一个java.lang.Class对象,并且存放在方法区。换言之,JVM并不是在运行时就会把所有使用到的类都加载到内存中,而是用到,不得不加载的时候,才加载进来,而且只加载一次,初始化类构造器
()方法也只执行一次,所以static{} 块,类变量赋值语句也就只执行一次,只生成一个java.lang.Class对象!
参考博客:Java 代码 编译和执行过程_春天的早晨的博客-CSDN博客
Java程序编译和运行的过程 - 邱明成 - 博客园
Java编译程序和运行过程详解 - helloworldhaha - 博客园
Java类加载器 — classloader 的原理及应用_阿里巴巴淘系技术团队官网博客的博客-CSDN博客
①效率,加快速度。
②被static修饰的变量属于类变量,通过字面意思就说明了这个变量的归属(类),与之相对的是没有被static修饰的成员变量,也称为实例变量,说明这个变量是属于某个具体的对象。
static修饰的有状态,对象级创建对象都是新的。
③static节省内存(全局唯一)。
web中什么是静态资源和动态资源
静态资源:html、css、images等,我们访问服务器地址时就直接拿编译好的静态的html,css文件,直接去渲染成页面,而js文件不是静态的,是动态的,js这个文件是我们在动态点击页面的时候随点随访问这个js文件,点击的时候触发响应的代码。
静态资源是一切的基础,要提前编译好,在动态资源显示前就渲染出来接收动态的数据。
java中static修饰的变量也可以看成是静态资源,而static修饰的方法可以看成是静态资源对外提供的接口,以便访问和调用静态资源,与web中的静态资源有异曲同工之妙,也是要在类初始化对象之前,在类加载时就开辟了内存空间,便于为类和对象的访问提供资源。
属性:
-属性可以被多个对象所共享,不会随着对象的不同而不同
-类中的常量也常常声明为static方法:
-操作静态属性的方法,通常设置为static的
-工具类中的方法,习惯上声明为static的,比如Math,Arrays,Collections
参考:Java中的static关键字解析 - Matrix海子 - 博客园
static关键字作用总结 - 罗纳德 - 博客园