一、成员变量和局部变量的区别
成员变量:
1、成员变量定义在类中,在整个类中都可以被访问。
2、成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
3、成员变量有默认初始化值。
局部变量:
1、局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
2、局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
3、局部变量没有默认初始化值
二、静态方法只能访问静态成员,不可以访问非静态成员的原因
1、在类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,会导致静态方法会先于对象而存在所以无法访问。
三、static
1.static 加载
1.1 静态代码块会在jvm加载类(生命周期的初始化时)时执行这些静态代码块,并且只执行一次,如果有多个静态代码块则按照顺序执行。
1.2 静态变量;准备阶段 jvm会为静态变量分配空间,并且为其赋上默认值。(常量直接赋我们需要的值)
2.初始化
2.1 类会在首次被主动使用时为静态变量赋初始值,一个正确的初始值是通过类变量初始化语句或者静态初始化块(没有静态代码块且已经为静态变量赋值的情况下会提供一个static块)给出的。类的主动使用有一下几种方式:
1.创建类的实例
2.调用类的静态方法
3.使用类的非常量 静态字段
4.初始化类的子类(初始化一个类的时候,如果存在直接父类且其还未初始化,先初始化其父类)
5.使用反射调用类的方法
6.用java命令启动一个类
2.2 类的初始化方法 不是指某种特定的方法指的是 类的初始化规则。
3.如果静态代码块和申明时都对静态变量进行了赋值操作时静态变量的值
会按照声明和静态代码块的先后顺序进行赋值(只执行最后一个赋值的操作):jvm执行静态代码块时会按照其声明的先后顺序执行,最后执行静态变量的赋值操作
4.static 的特殊之处
被static 修饰的变量和方法不属于任何一个对象,而是被这些变量所共享。
5.静态变量的生命周期
同 类的生命周期相同;在类加载时创建,在类卸载时删除
6.静态变量的内存地址
静态变量在内存中只有一个,存放在方法区,属于类变量,被所有变量共享
四、jvm中几个比较重要的内存区域
1.方法区
jvm中有一块专门用来存放已经加载的类信息,静态变量、常量已经方法代码的内存区域,称为方法区 ;运行时常量池放在方法区中
2.堆区
用来存放类的对象实例,字符串常量池放在堆内存中(1.8版本之前放在方法区中)
3.栈区
也叫jvm虚拟机栈,是由一个个栈帧组成的先进后出的栈式结构;栈帧中用来存放方法运行时产生的局部变量,方法出口等信息;当调用一个方法时,虚拟机栈就会创建一个栈帧来存放这些数据,调用完成栈帧消失,如果方法调用其他方法,会在栈顶创建新的栈帧。
五、类的生命周期
参考:详解java类的生命周期_java的生命周期-CSDN博客
指的是类的字节码文件(.class)从加载到卸载的全过程。一个java类的生命周期主要有加载、连接、初始化、使用、卸载五个阶段,也有跳过初始化直接使用的情况
1、加载
jvm找到需要加载的类,并把类信息加载到jvm的方法区,然后再堆区中实例化一个java.lang.class对象作为方法区中这个类信息的入口。
2.连接
连接阶段比较复杂一般和加载阶段交替进行,有时不会等加载阶段结束再开始连接,可能类信息加载到一半就开始连接,但两个阶段的开始时间和结束时间是固定的,加载阶段总是在连接阶段开始之前开始,连接阶段总是在加载阶段结束之后结束。
这个阶段的任务是做加载之后的验证工作和初始化阶段开始之前的准备工作;这个阶段可以进一步细分为 验证、准备、解释三个阶段:
1.验证
1.当一个类被加载之后jvm需要验证一下这个类信息是否合法;验证的内容包括这个类是不是符合字节码的形式、变量与方法是不是有重复、数据类型是不是有效、继承与实现是否合乎标准等等
2.这个阶段的目的是保证加载的类是jvm能够运行的;
2.准备
1.此阶段的目的是为静态变量分配内存并设置为jvm的默认值
2.对于非静态的变量则不会为他分配空间
3.常量的默认值为我们在代码中设的值
3.解析
这一阶段的任务是把常量池中的符号应用(接口名,字段名,方法名等)转化为直接应用(内存地址)
3.初始化
-
如果一个类被直接引用就会触发类的初始化
-
我们常说的类加载指的便是类生命周期中的加载、连接、初始化
4.使用
类的使用包括主动引用和被动引用;主动引用会引起类的初始化,被动引用不会引起初始化。
-
主动引用
1. 读取设置静态变量,调用静态方法
2.创建一个实例(new)
3.使用反射调用类的方法
4.初始化类的子类
5.作为程序的入口(mian())
-
被动引用
1. 调用父类中相关方法,变量
2.定义类的数组
3.调用类的常量
5.卸载
jvm会在方法区垃圾回收的时候对类进行卸载,清空类的相关信息,类的生命周期就结束了。类卸载需要满足一下三个条件
1. 类在堆内存中的所有实例都被回收
2.类的classloader已被回收
3.类在堆内存中的java.lang.class 对象没有任何引用,在任何地方都没办法通过类的反射调用该类
六、一些常见问题
-
为什么重写equals的同时必须重写hashCode
将对象存入依赖于哈希码的数据结构时,会先比较对象的哈希码,如果两个对象的哈希码不同,就判断两个对象不相等;可能会导致一些问题。
-
访问修饰符
访问范围从小到大 : private ,default,protected, public
以此添加访问权限:本身,加本包的其他类,加子类,加其他报的非子类