深度分析: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#静态方法与非静态方法.那么他们的定义有什么不同呢?他 ...
随机推荐
- C# 使用MySQL事务的使用方法
//使用事务来处理多条数据,如果不成功则回滚 public void getCheckListSubmit() { string _conStr = "................&qu ...
- Linux文件的查找之find命令处理动作
查找到文件之后的处理动作 例如:找出来系统中比较大超过10G的并且存放时间超过一年的log文件并删除 find / -name ".log" -size +10G -mtime + ...
- 使用浏览器抓取QQ音乐接口(排行榜篇)
前言 最近手头比较空闲,再加上看到其他人的博客都差不多有个类似的播放控件,手就会闲不下来,说干就干,所以我们开始吧! 来到QQ音乐的官网,我们就直奔着目标去,寻找排行榜 我们主要用的是最近比较热的歌, ...
- 解决Android RadioGroup跑到输入法上面
Android开发过程中,发现一个小问题,当我们点击屏幕下面的输入框时,我们的RadioGroup会跑到输入法的上面去,如下图 两种解决方法 1.Manifest.xml文件activity标签中添加 ...
- scott lock
账户被锁: cmd --->sqlplus /nolog--->conn sys/change_on_install as sysdba;---->alter user scott ...
- Promise 配合 axios 使用
Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方法,原型上有then.catch等同样很眼熟的方法 很细致的Promise使用详解 自己脑补 vue 工程化的 ...
- 手把手教你使用 cert-manager 签发免费证书
概述 随着 HTTPS 不断普及,越来越多的网站都在从 HTTP 升级到 HTTPS,使用 HTTPS 就需要向权威机构申请证书,需要付出一定的成本,如果需求数量多,也是一笔不小的开支.cert-ma ...
- Hadoop高可用
一.原因 - NameNode是HDFS的黑心配置HDFS有事hadoop的核心组件 NameNode 在Hadoop及群众至关重要 - NameNode的宕机导致集群的不可用 二.解决方案 其中 N ...
- 关于maven下,lombok的安装
1.首先下载lombok的jar包,可至https://mvnrepository.com/下载 2.双击即会自动扫描eclipse.exe,如图: 选择eclipse.exe,点击install/u ...
- DP百题练(二)
目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...