深度分析:Java 静态方法/变量,非静态方法/变量的区别,今天一并帮你解决!
静态/非静态 方法/变量的写法
大家应该都明白静态方法/字段比普通方法/字段的写法要多一个static关键字,简单写下他们的写法吧,了解的可以直接略过
class Test{
// 静态变量
public static int id = 1;
// 普通变量
public int usualId = 2;
// 静态常量
public static final int finalNextId = 3;
// 静态方法
public static void A(){
// 静态方法只能访问静态字段,不能访问非静态字段
System.out.println("this is static function A!");
}
// 普通方法
public void B(){
// 普通方法可以访问静态字段和非静态字段
System.out.println("this is usual function B!");
}
}
静态变量
静态变量(带有static关键字的字段)是属于类的,所有该类的对象共用该字段;
非静态变量(普通字段)是属于类的对象的,每一个该类的对象都有自己的非静态字段,他们互不影响。
class Test{
// 静态变量
public static int id = 1;
// 普通变量
public int usualId = 2;
}
class TestA{
// 对于静态字段,不实例化类(即创建对象)就可使用
Test.id; // 对于普通字段,Test.usualId 就会报错
// 对于普通字段,需要先实例化类
Test test = new Test();
test.usualId; // 不会报错
}
静态方法
静态方法与普通方法的区别,与静态字段与普通字段的区别类似
静态方法是不在对象上执行的方法,在调用静态方法时,不需要实例化该类而调用普通方法必须实例化该类。
class Test{
// 静态方法
public static void A(){
// 静态方法只能访问静态字段,不能访问非静态字段
System.out.println("this is static function A!");
}
// 普通方法
public void B(){
// 普通方法可以访问静态字段和非静态字段
System.out.println("this is usual function B!");
}
}
class TestA{
// 对于静态方法,不实例化类(即创建对象)就可调用
Test.A(); // 对于普通字段,Test.B()就会报错
// 对于普通方法,需要先实例化类
Test test = new Test();
test.B(); // 不会报错
}
可以了解下Java中类的生命周期,就能知道为什么访问静态方法/字段不需要实例化类而访问非静态的方法/字段需要实例化类
静态字段/方法在类的连接阶段就存在了,几乎可以理解为类存在,静态字段/方法就存在;
非静态字段/方法在类初始化后(new 类名)才会存在,也就是对象存在后,非静态字段/方法才会存在。
类的生命周期
此部分几乎搬运了“三级小野怪”的文章,参考链接:https://blog.csdn.net/zhengzhb/article/details/7517213
当我们编写一个Java源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在Java虚拟机中运行,Java类的声明周期就是指一个class文件从加载到卸载的全过程。
一个Java类的完整的生命周期会经历加载,连接,初始化,使用,卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况。
jvm中的几个重要的内存区域
方法区:专门用来存放已经加载的类信息,常量,静态变量以及方法代码的内存区域
常量池:是方法区的一部分,主要用来存放常量和类中的符号引用等信息;
堆区:存放类的对象实例
栈区:也叫Java虚拟机栈,由一个个的栈帧组成的后进先出的栈式结构,存放方法运行时产生的局部变量,方法出口等信息。当调用一个方法时,虚拟机栈就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法调用了其他方法,则继续在栈顶创建新的栈帧。
加载
在加载阶段,Java虚拟机会找到需要加载的类,并把类信息放到jvm的方法区中,然后堆中实例化。
是类的生命周期中的第一个阶段,加载阶段之后是连接阶段,但是有时连接阶段并不会等加载阶段完成之后才开始,而是交叉进行,可能一个类只加载了一部分之后,连接阶段就已经开始了。但是两个阶段总的开始时间和完成时间总是固定的:加载阶段总在连接阶段之前开始,连接阶段总是在加载阶段完成之后完成。
连接
连接阶段主要任务是做一些加载后的验证工作以及一些初始化前的准备工作
验证:当一个类被加载会后,验证类是否合法,比如这个类的变量与方法是不是有重复,数据类型是否有效等,目的是保证加载的类能够被jvm所运行。
准备:为类的静态变量分配内存并设为jvm默认的初始值,非静态变量则不分配内存。需要注意的是,这时候静态变量的初值是jvm默认的初始值而不是我们再程序中设定的初值。jvm默认的初值是这样的:
1.基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0。
2.引用类型的默认值为null。
3.常量的默认值为我们程序中设定的值,比如我们在程序中定义final static int a = 100,则准备阶段中a的初值就是100。
解析
初始化
如果一个类被直接引用就会触发类的初始化,直接引用的情况有:
通过new关键字实例化对象,读取或设置类的静态变量,调用类的静态方法
通过反射执行以上三种行为
初始化子类的时候,会触发父类的初始化
作为程序入口直接运行时(也就是直接调用main方法)
除了以上四种情况,其他使用类的方法叫做被动引用,被动引用不会触发类的初始化
主动引用代码示例
class InitClass{
static {
System.out.println("初始化InitClass")
}
public static String a = null;
public static void method(){}
}
class SubInitClass extends InitClass{} public class Test1{
public static void main(){
// 主动引用引起类的初始化:new 对象、读取或者是类的静态变量,调用类的静态方法
new InitClass();
InitClass.a = "";
String a = InitClass.a;
InitClass.method(); // 主动引用引起类的初始化,通过反射实例化对象,读取或设置类的静态变量,调用类的静态方法
Class cls = InitClass.class;
cls.newInstance();
Field f = cls.getDeclaredField("a");
f.get(null);
f.set(null,"s");
Method md = cls.getDeclaredMethod("method");
md.invoke(null, null); // 主动引用引起类的初始化,实例化子类
new SubInitClass();
}
}
初始化过程:按照顺序自上而下运行类中的变量赋值语句和静态语句,如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。
在初始化阶段,只会初始化与类相关的静态赋值语句和静态语句,也就是有static关键字修饰的信息,而没有static修饰的赋值语句和执行语句在实例化对象时才会运行
使用
类的使用包括主动引用和被动引用,主动引用上面说过了,下面主要说下被动引用
引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化;
定义类数组,不会引起类的初始化;
引用类的常量,不会引起类的初始化。
被动引用代码示例
class InitClass{
static{
System.out.println("初始化InitClass");
}
public static String a = null;
public final static String b = "b";
public static void method(){}
} class SubInitClass extends InitClass{
static {
System.out.println("初始化SubInitClass");
}
} public class Test4 {
public static void main(String[] args) throws Exception{
// String a = SubInitClass.a;// 引用父类的静态字段,只会引起父类初始化,而不会引起子类的初始化
// String b = InitClass.b;// 使用类的常量不会引起类的初始化
SubInitClass[] sc = new SubInitClass[10];// 定义类数组不会引起类的初始化
}
}
卸载
如果满足下面的情况,类就会被卸载:
该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收。
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
深度分析:Java 静态方法/变量,非静态方法/变量的区别,今天一并帮你解决!的更多相关文章
- java中静态方法和非静态方法调用的一点小困扰,已解决。
public static void main(String[] args) { // TODO Auto-generated method stub SimpleGui1B gui=new Simp ...
- Java中堆、栈,静态方法和非静态方法的速度问题
一.堆和栈的速度性能分析 堆和栈是JVM内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内容,存储空间大小,存储速度这几个方面来理解的,但是关于堆和栈的存储 ...
- Java中synchronized用在静态方法和非静态方法上面的区别
synchronized 修饰在 static方法和非static方法的区别 在Java中,synchronized是用来表示同步的,我们可以synchronized来修饰一个方法.也可以sync ...
- 在java中静态方法与非静态方法
在java中public void与public static void有什么区别 ? public void 修饰是非静态方法,该类方法属于对象,在对象初始化(new Object())后才能被调用 ...
- 【JVM】深度分析Java的ClassLoader机制(源码级别)
原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...
- 转 C#中静态方法与非静态方法区别比较
C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析. C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用 ...
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)
写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...
- 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题
原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...
- C#静态类 静态方法与非静态方法比较
静态类 在类(class)上加入static修饰,表示该类无法被实例化,并将该类中,无法实例化变量或函数 静态类的主要特性 仅包含静态成员 无法实例化 静态类的本质,时一个抽象的密封类,所以不能被继承 ...
- [转]C#静态方法与非静态方法的比较
http://wenku.baidu.com/view/4e1704084a7302768e9939e0.html C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他 ...
随机推荐
- OSI七层网络
7-应用层 各种应用软件 6-表示层 转换.加密.解密压缩 5-会话层 建立会话,保证会话,终止会话 4-传输层 TCP/UDP 3-网络层 路由 2-数据链路层 交换 1-物理层
- Apache Hudi助力nClouds加速数据交付
1. 概述 在nClouds上,当客户的业务决策取决于对近实时数据的访问时,客户通常会向我们寻求有关数据和分析平台的解决方案.但随着每天创建和收集的数据量都在增加,这使得使用传统技术进行数据分析成为一 ...
- pytest参数化代码笔记
#!/usr/local/bin/python3 # -*- coding: utf-8 -*- import pytest __author__ = "Carp-Li" __da ...
- 【API进阶之路】研发需求突增3倍,测试团队集体闹离职
摘要:最近研发的需求量涨了3倍,开发团队拼命赶进度,可苦了测试团队. 本以为从一线研发转管理后会清闲一些,但是没想到,我还要充当救火队员的角色. 到了第四季度,各业务部门都在憋着劲儿冲业绩,毕竟这跟年 ...
- 在PostgreSQL中CREATE STATISTICS
如果你用Postgres做了一些性能调优,你可能用过EXPLAIN.EXPLAIN向你展示了PostgreSQL计划器为所提供的语句生成的执行计划,它显示了语句所引用的表如何被扫描(使用顺序扫描.索引 ...
- 面试不再慌,看完这篇保证让你写HashMap跟玩一样
今天这篇文章给大家讲讲hashmap,这个号称是所有Java工程师都会的数据结构.为什么说是所有Java工程师都会呢,因为很简单,他们不会这个找不到工作.几乎所有面试都会问,基本上已经成了标配了. 在 ...
- 基于SSH框架的人力资源管理系统设计与实现
- - ->关注博主公众号[C you again],获取更多IT资源(IT技术文章,毕业设计.课程设计系统源码,经典游戏源码,HTML网页模板,PPT.简历模板,!!还可以投稿赚钱!!,点击查 ...
- Linux的top命令及交换分区
TOP命令关键指标 %MEM,在内存中的占用率 %CPU,使用率,如果两核,最大可到200% TIME+, 占用cpu的总时间/s SHR,分享内存 RES, 常驻内存,进程当前使用的内存大小,不包括 ...
- Azure Data Factory(一)入门简介
一,引言 今天分享一个新的Azure 服务-----Azure Data Factory(Azure 数据工厂),怎么理解,参考根据官方解释-----数据工厂解释:大数据需要可以启用协调和操作过程以将 ...
- Luogu P4247 [清华集训2012]序列操作
题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(q\) 次操作,每次操作形如以下三种: I a b c,表示将 \([a,b]\) 内的元素加 \(c\). R a b,表示将 \([a ...