手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

Static关键字

时间:2021/5/17 22:36:16|来源:|点击: 次

Static关键字

  • Static关键字的使用
    • static修饰方法
          • 静态方法
          • 实例方法
          • 实例方法和静态方法的区别
    • static修饰内部类
          • 内部类
          • 静态内部类
          • 静态内部类和非静态内部类的区别
    • static修饰变量
          • 静态变量
          • 实例变量
          • 静态变量和实例变量的区别
  • 设计模式
    • 单例设计模式
          • 单例模式(饿汉式)
          • 单例模式(懒汉式)
  • 类加载过程
          • 加载
          • 验证
            • 文件格式验证
            • 元数据验证
            • 字节码验证
            • 符号引用验证
          • 准备
          • 解析
          • 初始化
            • 必须对类进行初始化的情况
  • 双亲委派模型

Static关键字的使用

static修饰方法

静态方法

当类的字节码文件加载到内存,类方法的入口地址就会分配完成,所以类方法不仅可以被该类的对象调用,也可以直接通过类名完成调用。

声明为static的方法有以下几条限制:
1)它们仅能调用其他的static 方法。
2)它们只能访问static数据。
3)它们不能以任何方式引用this 或super。

实例方法

当类的字节码文件加载到内存中时,类的实例方法并没有被分配入口地址,只有当该类的对象创建以后,实例方法才分配了入口地址。从而实例方法可以被类创建的所有对象调用,该类的所有对象共享实例方法的入口地址,当该类的所有对象被销毁,入口地址才会消失。

实例方法和静态方法的区别
静态方法实例方法
调用方式依赖于类,通过类的静态方法调用依赖于类的对象,需要创建对象后通过实例方法使用
使用静态方法内部可以定义和使用实例变量,但无法直接调用实例方法实例方法内部不能定义静态变量,但可以直接调用是静态方法
使用场景适用于方法与类的对象无关适用于依赖类的对象的方法
内存占用只占用一份内存空间只占用一份内存空间

static修饰内部类

内部类

内部类是Java语言中重要的组成部分之一。
1.内部类,顾名思义就是在一个类的内部再定义了一个类。例如:

public class TestDemo {
    //内部类
    private  class TestInner{
        }
    }

2.内部类可以访问其所在类的所有属性,内部类创建自身对象需要先创建其所在类的对象
3.可以定义内部接口,且可以定义另外一个内部类实现这个内部接口
4.内部类不能由static修饰的元素
5.内部类可以嵌套

静态内部类

1.静态内部类就是由static所修饰的内部类

public class TestDemo {
    //静态内部类
    private  static class TestInner{
    }
}

2.静态内部类可以定义static元素
3.静态内部类创建自身对象时可以一次性创建出,无需通过所在类的类型创建

静态内部类和非静态内部类的区别
静态内部类非静态内部类
声明不依赖于外部类对象依赖于外部类对象
定义类变量、类方法、常量、成员变量和方法常量、成员变量和方法
访问能访问外部类的静态成员变量和静态方法,不能引用外部类的对象(this)访问外部类的所有成员和方法

static修饰变量

静态变量

静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

实例变量

每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

静态变量和实例变量的区别
静态变量非静态变量
语法由static修饰没有static修饰
运行区别类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象
内存类的静态变量在内存中只有一个实例变量取决于类的实例,每创建一个实例,分配一次内存

设计模式

单例设计模式

单例设计模式:保证一个类只有一个实例,提供一个访问该类对象实例的全局访问点。
(1)不允许其他程序用new对象,保证对象的唯一性。
new就是指开辟新的空间,在这里更改数据只是更改的所创建的对象的数据,每new一次就创建一次新的空间,无法保证不了对象的唯一性。
(2)在该类中创建对象
因为不允许其他程序new对象,所以这里的对象需要在本类中new出来
(3)对外提供一个可以让其他程序获取该对象的方法
因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象。

单例模式(饿汉式)

1)私有化类的构造器
2)内部创造静态对象
3) 提供公共静态方法,返回类的对象(可以直接用类名调用)

//饿汉式
class testDemo{
    //私有化类的构造器
    private testDemo() {
    }
    //内部创造静态对象
    private static testDemo instance=new testDemo();
    //提供公共静态方法,返回类的对象(可以直接用类名调用)
    public static testDemo getinstance(){
        return instance;
    }

}
单例模式(懒汉式)

1)私有化类的构造器
2)声明当前类对象,不初始化(对象在方法内初始化)
3)提供公共静态方法,返回类的对象(可以直接用类名调用)

//懒汉式
class testDemo1{
    //私有化类的构造器
    private testDemo1() {
    }
    //声明类的对象,不初始化
    private static testDemo1 instance=null;
    //提供公共静态方法,返回类的对象(可以直接用类名调用)
    public static testDemo1 getinstance(){
        //判断是否存在对象,如果不存在则创建一个,存在则直接返回对象;
        if(instance==null) {
            instance = new testDemo1();
        }
        return instance;
    }
}

类加载过程

类加载过程主要是加载–连接–初始化,三个方面,其中连接又可以分为验证–准备–解析。

加载

1.通过全类名获取定义此类的二进制字节流,class文件
2.将字节流所代表的静态存储结构转换为方法区运行时的数据结构,即存储到方法区
3.在内存中生成一个代表该类的java.lang.Class 对象,作为方法区这些数据的访问入口

验证

验证的阶段是十分耗时的,它是重要但非必须。验证是为了使得防止字节流中有安全问题产生。Java的安全性是由编译器所保证的,而类加载是在虚拟机中进行的,当无法确保来源的时候则需要验证。
文件格式验证----->元数据验证----->字节码验证---->符号引用验证

文件格式验证

这个阶段主要验证输入的二进制字节流是否符合class文件结构的规范。二进制字节流只有通过了本阶段的验证,才会被允许存入到方法区中。
其是基于二进制字节流的
加载和验证是交叉进行的,在加载开始后,立即启动了文件格式验证,本阶段验证通过后,二进制字节流被转换成特定数据结构存储至方法区中,继而开始下阶段的验证和创建Class对象等操作。

元数据验证

本阶段对方法区中的字节码描述信息进行语义分析,确保其符合Java语法规范。基于类特定的数据结构的。

字节码验证

本阶段是验证过程的最复杂的一个阶段。通过数据流和控制流分析,确定程序语义是合法的,符合逻辑的。基于类特定的数据结构的。

符号引用验证

本阶段验证发生在解析阶段,确保解析能正常执行。基于类特定的数据结构的。

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配,类的静态成员变量也存储在方法区中。
为静态成员变量设置初始值初始值为0、false、null等。

解析

解析阶段是虚拟机将常量池中的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

初始化

初始化阶段就是执行类构造器()的过程,是类加载的最后一步。
对于方法的调用,虚拟机会自己确保其在多线程环境中的安全性。因为 () 方法是带锁线程安全,所以在多线程环境下进行类初始化的话可能会引起死锁,并且这种死锁很难被发现。

必须对类进行初始化的情况

1.当遇到 new 、 getstatic、putstatic或invokestatic 这4条直接码指令时,比如 new 一个类,读取一个静态字段(未被 final 修饰)、或调用一个类的静态方法时。
2.使用 java.lang.reflect 包的方法对类进行反射调用时 。
3.初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。
4.当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。

双亲委派模型

在这里插入图片描述
上图是上面所介绍的这几种类加载器的层次关系,称为类加载器的双亲委派模型。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
优点:使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。
避免了多份同样字节码的加载。
其中loadClass以双亲委派的方式去加载,findClass找class文件 (重写)defineClass从class字节码文件加载Class对象,然后class对象通过反射生成对象。

上一篇:电路PCB设计 下一篇:02-dubbo-consumer

Copyright © 2002-2019 某某自媒体运营 版权所有