About Me
欢迎各位读者访问,大家一起学习。
优秀是一种习惯♡♡♡
做更好的自己!
本人见识有限,写到博客难免有错误或疏忽的地方,还望各位大佬多多指点,在此表示感激不尽。♡♡♡
static关键字理解
1. 理解静态
问题:为什么是静态,有静是不是就有动啊?这个静是相对于什么来说?
-
要想明白上面这个问题,首先得知道什么是类和对象
-
类:是具有共同特征事物的抽象【属性 — 方法】
-
对象:是根据类产生的具体实例
举例:张三和李四都属于学生: 学生有自己的学号,姓名,年龄,等这些就称为属性,张三和李四是具体实例对象,有具体数据。如:姓名:张三,年龄23,学号123456 | 姓名:李四,年龄66,学号888888,这些数据都是随着对象变化而变化,随对象储存,这就是"动"。
-
-
既然动是随对象变化而变化,那静就是不随对象变化而变化,而是这类事物共享的数据,随类储存,也称为类变量。
* 核心:静态是所属于类,非静态是所属对象。
2. 静态存在的意义
-
创建独立于具体对象的域变量或方法,即使没有对象也可以使用属性和方法。
-
可以形成**静态代码块**以优化程序性能。
静态代码块:Java中static{}代码块,主要用来初始化类,为类的静态变量赋予初始值
2.1 静态代码块可以放到类中任意位置,不存在于任何方法体中。
2.2 可以有多个static块。
2.3 当类首次加载,会按照static块依次执行,并且只执行一次。
3. 静态的使用
-
什么时候使用静态变量?
当类中出现所有的对象共享的数据,这个字段就可以使用static修饰。
-
什么时候使用静态方法?
确定不会变化的工具行为,也就是方法中没有用到非静态数据时可以使用静态方法。常见的工具类
-
注意事项:
3.1 静态方法只能访问静态成员(属性和方法)
3.2 非静态方法可以访问静态成员也可以访问非静态成员(属性和方法)
3.3 因为静态优先于对象的存在而存在,所以静态方法中不能使用this,super关键字
4. 静态的特点
4.1 静态是从属于类的,随类的加载而加载。 【类】
4.2 静态是优先于对象,所以说static不允许修饰局部变量
public class Demo02 {
//定义成员变量使用static修饰
static int a = 10;
//定义一个方法
public void m1(){
//static int b = 20; 编译报错,因为static不允许修饰局部变量
}
}
4.4 静态修饰后可以被所有对象共享 【共享】
static 的5个特点:
1. static随着类的加载而加载
2. static只会执行一次
3. static类被所有的对象共享
4. static中不能有this关键字
5. static方法中不能使用非静态的方法 *****
*/
public class Demo01 {
public static void main(String[] args) {
//创建不同的对象,但是用static修饰的成员变量可以被该类所有的对象共享
Demo02 d2 = new Demo02();
System.out.println(d2.a); // 10
Demo02 d3 = new Demo02();
System.out.println(d3.a); // 10
}
}
class Demo02 {
//定义成员变量使用static修饰
static int a = 10;
}
4.5 可以直接通过类名调用【推荐】,也可以通过对象调用【不推荐】
public class Demo01 {
public static void main(String[] args) {
//调用成员变量,使用类名.调用
System.out.println(Demo02.a); // 10
//调用成员方法,使用类名.调用
Demo02.method();
//创建对象,使用对象的方式调用
Demo02 d2 = new Demo02();
d2.method();
}
}
//创建一个类Demo02
class Demo02 {
//定义成员变量使用static修饰
static int a = 10;
//定义一个成员方法使用static修饰
public static void method() {
System.out.println("Demo02方法");
}
}
4.6 静态只能随着类的加载只执行一次 【一次】
4.7 静态中是不能有this和super的。 【this】
class A{
static int a = 10;
public static void method(){
// System.out.println(this.a); 编译报错,static中不能使用this关键字
}
}
class B{
int a = 10;
public void method(){
System.out.println(this.a); //编译成功
}
}
4.8 静态中不能访问非静态 【 先后人】
//创建一个类A
class A{
//创建一个成员变量
int a = 10;
static int b = 20;
public static void method(){
// System.out.println(a); //编译报错,静态中不能使用非静态成员
System.out.println(b); // 编译成功,静态可以访问静态
}
}
5. 静态的利弊
-
利:节省空间,方便调用。
因为使用静态变量修饰之后所有对象可以共享同一份数据,不必重新new对象,这样可以节省空间,调用的时候可以通过类名直接调用,方便调用。
-
弊:生命周期长,强耦合,局限性
因为静态是随着类的加载而存在,静态变量如果多次被引用赋值,可能会导致参数混乱,有一定的局限性,访问也只能访问静态成员。
6. 代码块
6.1:静态代码块
静态代码块是随着类的加载而加载,而且只能执行唯一一次。
//创建一个类A
class A{
//创建一个静态代码块
static {
System.out.println("静态代码块");
}
}
6.2:构造代码块
构造代码块每次在调用构造方法的时候,都会先执行构造代码块,而且都是比构造方法优先执行。
作用:所有构造方法里面相同的代码提取出来,放到构造代码块中。构造代码块每次创建对象就会执行一次。
public class Demo001 {
public static void main(String[] args) {
//创建对象,构造代码块没创建一次对象就会执行一次
A a = new A(); //构造代码块
A a1 = new A(); //构造代码块
}
}
//创建一个类A
class A{
//创建一个构造代码块
{
System.out.println("构造代码块");
}
}
6.3:局部代码块
局部代码块是在方法中定义,目的是尽量的把变量从内存清理出去。
注意:局部代码块中的成员变量只在当前{}中有效
//创建一个类A
class A{
//定义一个成员方法
public void method(){
//创建局部代码块
{
System.out.println("局部代码块");
}
}
}
7. 面试题
第一题:
public class Test {
public static int count = 0;
{
count++;
System.out.println("非静态代码块 count=" + count);
}
static {
count++;
System.out.println("静态代码块1 count=" + count);
}
static {
count++;
System.out.println("静态代码块2 count=" + count);
}
public static void main(String[] args) {
System.out.println("*************** Static1 执行 ***************");
Test sct1 = new Test();
System.out.println("*************** Static2 执行 ***************");
Test sct2 = new Test();
}
}
1. 执行结果:
静态代码块1 count=1
静态代码块2 count=2
*************** Static1 执行 ***************
非静态代码块 count=3
*************** Static2 执行 ***************
非静态代码块 count=4
执行流程: static{…}为静态代码块会随着类的加载而依次执行,所以首先执行静态代码块1和2
{…}为非静态代码块会随着对象的创建而自动执行,所以就有非静态代码块3和4
第二题:
public class Test extends Base {
static {
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base {
static {
System.out.println("base static");
}
public Base() {
System.out.println("base constructor");
}
}
2. 执行结果
base static
test static
base constructor
test constructor
执行流程: 执行开始找main方法,因为main方法是执行程序的入口,但是在执行main方法之前必须先加载Test类,而在加载Test类的时候发现继承Base类,所以转去加载Base类,在Base类中有一个静态代码块会随着类的加载 而执行,所以先打印base static ,然后回到Test类中也有一个static块,接着打印test static,当加载完所有的类时,开始加载方法。然后到main方法中执行new Test(),会先去父类中调用父类的构造器也就是执行base constructor 最后执行本类构造器 test constructor 。
第三题:
public class Test {
Person person = new Person("Test");
static {
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person {
static {
System.out.println("person static");
}
public Person(String str) {
System.out.println("person " + str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static {
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
3. 执行结果
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
执行过程:首先加载Test类然后执行static静态代码块打印test static,然后执行main方法中的new MyClass()类,而此时MyClass类还没有加载,在加载MyClass类之前发现继承Test类,又发现Test类已经被加载所以只需要执行MyClass中的静态代码块打印 myclass static,加载完后通过构造器生成对象,因为继承Test所以先执行父类的构造器,而执行之前必须先初始化父类的成员变量,所以执行Person person = new Person(“Test”);而此时Person类还没有加载,因此先会执行person类中的静态代码块打印person static,然后执行Person的构造方法打印person Test,接着执行Test类中构造器,打印test constructor, 最后初始化自身打印pereson MyClass, 执行MyClass的构造方法打印myClass constructor
第四题:
public class Test {
static {
System.out.println("test static 1");
}
public static void main(String[] args) {
}
static {
System.out.println("test static 2");
}
}
4. 执行结果
test static 1
test static 2
执行流程: 虽然main方法中没有任何语句,但是还是会输出,原因就是静态代码块是随着类的加载而执行。static可以写到类中的任意位置,但是不能写到方法的内部。
8. 思维导图
不要在最能吃苦的年纪选择了安逸!!! — Tornado♥