java 内存溢出,java声明静态变量
静态
静态的最大原因是节约内存,只存储一部分,对象共享此属性。
静态作用是什么?
场景:
如果每个对象具有相同的属性(如country='China ' ),则会为每个对象所在的堆内存分配一个空间,以保留此属性值country='Chian '。
每个对象的country属性值相同,所以是否只需要一个存储空间? 这将节省堆的内存容量。
答案很好。
静态限定的属性的值由所有对象共享。
注意:由于静态是共享的,因此不能将特定于对象的属性定义为静态。 像Person类这样的name不能是静态的。
例如,如果饮水机是共享的,而所有人都在共享同一台饮水机,则它是静态的;
例如,如果杯子是特有的,每个人都有属于自己的杯子,就不是静态的。
静态特征:
静态限定成员。 优先于对象的存在。
静态限定成员。 随着类的加载进入内存。
静态静态限定成员是共享的,并且存储在对象中是唯一的。
静态静态限定成员不仅可以直接用于对象,还可以直接用于类;
静态好处:
实现共享数据在内存中的唯一存储,节约内存空间;
各对象不需要在堆内存中单独预留空间进行保存,直接使用共享数据即可。
静态缺点:
它驻留在内存中,内存释放周期长,并且只会随着类的消失而消失。
班级什么时候消失?
实际上,类也是一个对象,在JVM启动时加载类路径目录下的类。 如果内存中加载的类太多,JVM GC会根据某种算法清理几个加载的类,从而释放空间。
JVM关闭后,类将消失。
类变量和成员变量的区别
类变量不是类的成员变量
存储位置不同
成员变量。 堆内存中每个对象都有不同的成员变量存储
静态变量在方法区域中是唯一的,是类变量,每个对象共享使用该变量
生命周期不同
成员变量随对象的创建而存在,并随对象回收而释放
静态变量随类加载而存在,并随类丢失而释放
调用方法不同
成员变量。 仅由对象调用
静态变量。 通常直接使用类名调用
成员变量---实例变量,特定于对象的属性
静态变量---对象具有相同属性的类变量
静态限定属性
静态变量也称为类变量
静态变量存储在方法区域的静态区域内存中。
如果每个对象的属性值相同,请考虑使用静态来限定属性。
公共静态字符串计数=' cn ';
方法区域:
方法/函数的存储位置。
方法区域分为静态数据区域、常数区域、代码区域(保存方法代码的区域)等。
需要说明的地方:
类中的代码是如何存储的?
类中可定义的内容:成员变量、类变量、构造方法、常规方法和静态方法。
其中,
成员变量是对象特定的数据,存在于成对内存中
构建方法、一般方法存储在方法区域的非静态区域中
类变量,静态方法。 存储在方法区域的静态区域中
=====================================
静态修饰方法
静态限定的方法是有限的,只能使用静态变量或调用静态方法。
不需要创建方法、工具类或对象
方法可以定义为静态方法,除非有特定于操作对象的数据;
1 .创建对象以调用静态方法,浪费时间、空间,没有意义
---专用结构方法(单实例模式),防止外部通过对象调用静态工具方法;
2 .静态方法无法引用对象,因此静态方法无法处理对象特定的数据();静态存在于对象之前);
由于静态方法先于对象加载到内存中,因此:
静态方法可以使用静态成员(静态属性、静态方法);
静态方法不能使用this/super关键字;
=====================================
静态什么时候使用?
1 .静态变量/类变量(从堆内存节约方面来看) ) ) ) ) )。
对象中成员变量的所有值都相同,如果需要仅使用该值而不进行更改,则将其定义为静态。
如果至少有一个对象可能更改此值,则必须将其定义为成员变量并将其存储在堆内存中。 在这种情况下,不能静态定义。
好处:
每个对象不需要为堆内存中的同一数据分配空间,而只需要在方法区域中存储一个数据。
前提:对象只读取该数据,不修改该数据。 因为大家都共享那个数据。
2.静态方法(从执行代码上考虑,从方法的调用上考虑)
方法能否被定义为静态,就看一点:
方法中是否使用到了对象的特有数据或者调用到了普通方法,如果没有,则定义为静态方法!
好处:
1.不需要创建对象,因为创建对象耗费时间空间,而且静态方法的执行中没有使用到对象的数据。
(创建对象需要在堆内存开辟空间,调用构造方法进行初始化等操作)
2.调用简单,直接通过类名即可调用方法。
注意:不管是静态方法还是非静态方法,都只是一段代码,在方法区中都只存一份,只是存放的区域不同而已!不存在节约内存的说法。
=========================================================================
扩展:主函数main为什么设计成static的
首先,主函数的功能:程序的入口,由JVM调用
主函数专注于:
* 在函数体中创建其它类的对象,指挥这些对象调用它们各自的方法来完成某种功能!
* 代码按功能封装到函数中
* 函数都封装到类中
* 主函数只做一件事:创建那些封装好的类的对象,再调用类的方法!
Java代码
publicclassStaticTest {
/**
* 对象的特有属性,每个对象的id都不同
*/
intid;
/**
* 讨论主函数为什么是静态static的
* 1.主函数是程序的入口。
* 2.主函数中调用其它函数的2种方式:
* a.静态方法,由类名调用;
* b.非静态方法,由对象调用
* a.静态方法,被主函数调用,由于静态方法中只能使用类变量,使得静态方法的功能具有局限性(对象的特有属性无法在静态方法中使用,因为对象还未创建),不能满足大多数的功能需求;
* 这样就只留另一条路,调用非静态方法
* b.非静态方法的调用,必须由对象来操作,所以,主函数中必须先创建对象,再通过对象来调用,使得大多数功能的调用都以对象为起点进行
* Java面向对象,以对象为核心,将主函数设计为静态的,强制开发人员通过对象来调用方法!
*
* 哦也!
* @param args
*/
publicstaticvoidmain(String[] args) {
//say(); //静态方法中不能调用非静态方法
//只能通过对象来调用
StaticTest test = newStaticTest();
test.say();
//把say()也变为静态的,也能直接调用啊!其后果是,say()要能执行,那么id也必须静态,静态即共享--->id是对象的特有属性,不同对象有不同的id
//所以,主函数中调用方法,遵从Java的规范,用对象来调用方法!!!
}
publicvoidsay() {
System.out.println(this.id);
}
}public class StaticTest {
/**
* 对象的特有属性,每个对象的id都不同
*/
int id;
/**
* 讨论主函数为什么是静态static的
* 1.主函数是程序的入口。
* 2.主函数中调用其它函数的2种方式:
* a.静态方法,由类名调用;
* b.非静态方法,由对象调用
* a.静态方法,被主函数调用,由于静态方法中只能使用类变量,使得静态方法的功能具有局限性(对象的特有属性无法在静态方法中使用,因为对象还未创建),不能满足大多数的功能需求;
* 这样就只留另一条路,调用非静态方法
* b.非静态方法的调用,必须由对象来操作,所以,主函数中必须先创建对象,再通过对象来调用,使得大多数功能的调用都以对象为起点进行
* Java面向对象,以对象为核心,将主函数设计为静态的,强制开发人员通过对象来调用方法!
*
* 哦也!
* @param args
*/
public static void main(String[] args) {
//say(); //静态方法中不能调用非静态方法
//只能通过对象来调用
StaticTest test = new StaticTest();
test.say();
//把say()也变为静态的,也能直接调用啊!其后果是,say()要能执行,那么id也必须静态,静态即共享--->id是对象的特有属性,不同对象有不同的id
//所以,主函数中调用方法,遵从Java的规范,用对象来调用方法!!!
}
public void say() {
System.out.println(this.id);
}
}