目录
一、JAVA的内存分析
1.内存概述:
java的内存存储总共分为5大区域:堆、栈、方法区、本地方法区、寄存器区
其中本地方法区(存第三方语言-C/C++)和寄存器区(多线程资源)不用区分析,没法跟踪这两个区域
重点分析:堆,栈,方法区
堆:存new对象,成员属性,常量池(放字符串常量,之前方法区,现在放堆区-性能考虑,但沿用了方法区特点)
栈:存局部变量
方法区:class资源,static资源; 特点:优先于对象的加载,且相同资源只维护一份
接下来,使用简单的面向对象案例,说明内存的执行过程
2.案例分析
//案例:小明在打游戏
//分析:类-Person,对象:new 属性-姓名,方法:打游戏
//内存分析流程:
//1.类加载Test1.class与Person.class---方法区
//2.new对象开辟空间-------堆区
//3.将地址赋值给引用变量person-------栈区
class Person{
String name;
public void play() {
System.out.println(name+"正在打游戏");
}
}
public class Test1 {
public static void main(String[] args) {
Person person = new Person();
person.name = "小明";
person.play();
}
}
二、静态-修饰属性
1.静态属性和成员属性
//案例:女朋友帮忙洗衣服
//成员变量结论:实例化多个对象,每个对象都有独立的成员属性
//静态变量结论:实例化多个对象,共享同一份静态变量
//成员变量 VS 静态变量
//1.存储位置 静态变量-方法区 成员变量-堆
//2.所属资源 静态变量-类 成员变量-对象
//3.执行顺序 静态变量优先于成员变量进行加载;在类加载时,就已经加载了静态资源
//4.调用方式 静态变量-推荐用类调 成员变量-对象调
class Girl{
//String name; //成员变量
static String name; //静态变量
public void wash() {
System.out.println("女朋友"+name+"正在帮忙洗衣服");
}
}
public class Test1 {
public static void main(String[] args) {
Girl lyf = new Girl();
Girl.name="刘亦菲"; //lyf.name = "刘亦菲";
Girl fj = new Girl();
Girl.name = "凤姐";
lyf.wash(); //凤姐
fj.wash(); //凤姐
//说明:在面向对象中,直接使用静态变量场景不多;但有些场景下,还是用得较多
//例如:统计全局资源及作为状态值(静态常量)的使用
}
}
2.场景-统计全局资源3
//案例:统计某个对象被new了多少次
//分析:实例化对象后,使用构造方法来记录次数
class A{
//int count; //初始为0 //成员变量:每个对象都是独立的一份
static int count; //静态变量:所有对象共享同一份
public A() {
count++; //每次new了之后,然后+1
}
}
public class Test2 {
public static void main(String[] args) {
new A();
new A();
new A();
System.out.println("次数:"+A.count);
}
}
3.场景-状态值应用
//状态值---静态常量 static+final
//final最终的,修饰变量,变为常量;所存的数值不可改变
//往往这种静态常量可以用于状态值,也就是系统给定值(也可自定义),用于判断,不要改变它
//好处:可读性很强,维护性很强
案例:
//案例:200响应码-成功 404-找不到访问页面 500-服务器报错
//模拟代码实现:
public class Test3 {
public static final int HTTP_OK = 200; //状态值
public static final int HTTP_ERR = 404;
public static final int SERVER_ERR = 500;
public static void main(String[] args) {
int repcode = getResponseCode();
//HTTP_OK = 400; final修饰的不能更改
switch (repcode) {
case HTTP_OK:
System.out.println("返回成功页面!");
break;
case HTTP_ERR:
System.out.println("访问页面未找到!");
break;
case SERVER_ERR:
System.out.println("服务器出现异常");
break;
default:
System.out.println("错误的响应码");
break;
}
}
private static int getResponseCode() {
//执行了很多后端操作
return HTTP_OK;
}
}
三、静态-修饰方法
1.特点
修饰方法时,在静态方法中不能使用成员变量
案例:
class A{
String name; //成员变量
static int age;
public void eat() { //成员方法
System.out.println(name+"正在吃");
System.out.println(age); //在成员方法中,可以使用静态变量
}
public static void test() { //静态方法
//在静态方法中不能使用成员变量,因为加载时机问题-static优先加载,不认识成员
//System.out.println(name);
//System.out.println(this.name); //静态方法中不能使用this或super关键字
//静态方法可以继承,但不能重写
}
}
class B extends A{
/*@Override //静态方法不能重写
public static void test() {
}*/
}
public class Test1 {
public static void main(String[] args) {
B.test(); //静态方法具有继承性
}
}
2.工具类
//工具类的应用---通过类名直接调静态方法
//好处:不需要通过new对象进行调用;如果需要多次调用,可节约内存
//例如系统提供的:System,Arrays都是工具类的用法
//System.arraycopy; Arrays.sort Array.copyOf Arrays.toString
案例:
class MyArrays{
public static void sort(int[] a) {
//冒泡排序:
for(int i=0;i<a.length-1;i++) {
for(int j=0;j<a.length-1-i;j++) {
if(a[j]>a[j+1]) {
int t = a[j];
a[j] = a[j+1];
a[j+1]= t;
}
}
}
}
}
public class Test2 {
public static void main(String[] args) {
int[] a = {2,6,4,8,3};
MyArrays.sort(a); //自定义工具类
System.out.println(Arrays.toString(a));
}
}
四、静态-修饰代码块
1.动态代码块
在类中写入{},就是一个动态代码块,只要实例化一次对象,即可触发一次代码块
执行时机:属性赋值>动态代码块>构造方法
作用:可用于给属性赋值
案例:
//动态代码块应用:
class A{
String name = "成员属性";
public A() { //构造方法
System.out.println("构造方法");
}
//动态代码块
{
System.out.println(name);
System.out.println("动态代码块");
}
}
public class Test1 {
public static void main(String[] args) {
new A();
}
}
2.类加载
//类加载机制:
//JVM首次使用某个类,通过classpath找到.class文件,并将类资源加载到内存中
//这些类资源包括:包名,类名,属性,方法,对象...
//类加载的触发时机:run 配置--verbose
//1.实例化对象
//2.实例化子类对象
//3.静态属性触发
//4.静态方法触发
//5.使用反射触发
案例:
class B{
static String name="静态属性";
public static void show() {
System.out.println("静态方法触发");
}
}
class C extends B{
}
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
//new B(); //类加载只有一份;与实例化多次对象无关
//new B();
//new C(); //实例化子类对象
//System.out.println(B.name); //静态属性
//B.show(); //静态方法
Class.forName("com.qf.d_block.B"); //全限定名 反射应用(后面学)
}
}
3.静态代码块
//静态代码块: static{}
//执行顺序:静态属性>静态代码块
//作用:用于给静态属性赋值
class D{
static String name="静态属性";
static {
System.out.println(name);
System.out.println("静态代码块");
}
}
public class Test3 {
public static void main(String[] args) {
new D();
}
}
4.实例化过程
//将静态代码块与动态代码块综合应用:
class Super{
String name = "成员属性";
public Super() { //构造方法
System.out.println("构造方法");
}
//动态代码块
{
System.out.println(name);
System.out.println("动态代码块");
}
static String name2="静态属性";
static {
System.out.println(name2);
System.out.println("静态代码块");
}
}
public class Test1 {
public static void main(String[] args) {
new Super(); //静态属性>静态代码块>成员属性>动态代码块>构造方法
System.out.println("---------------");
new Super(); //成员属性>动态代码块>构造方法 静态的只加载一次
}
}
实例化子类对象的执行过程:
//静态属性>静态代码块>子类静态属性>子类静态代码块>成员属性>动态代码块>构造方法
//>子类成员属性>子类动态代码块>子类构造方法
//规则:先静态后动态,先父类后子类
class Son extends Super{
String name = "子类成员属性";
public Son() { //构造方法
System.out.println("子类构造方法");
}
//动态代码块
{
System.out.println(name);
System.out.println("子类动态代码块");
}
static String name2="子类静态属性";
static {
System.out.println(name2);
System.out.println("子类静态代码块");
}
}
public class Test2 {
public static void main(String[] args) {
new Son(); //实例化子类对象的过程
}
}
五、final的使用
final表示最终的,不可更改的;
应用:可以修饰类,修饰属性,修饰变量
修饰类: 最终类,该类不能有子类----太监类
修饰方法:最终方法,该方法不能被重写
修饰变量:最终变量,变为了常量
1.修饰类和方法
案例:
/*final*/ class Animal{ //最终类-不能有子类 ; 例如String
public /*final*/ void eat() { //最终方法,子类不能重写
}
}
class Dog extends Animal{ //The type Dog cannot subclass the final class Animal
@Override
public void eat() { //Cannot override the final method from Animal
}
}
public class Test1 {
public static void main(String[] args) {
}
}
2.修饰变量
final修饰变量,有多种变量,成员变量,静态变量,局部变量(其中局部变量包含了基本和引用变量)
案例:
//成员属性+final赋值:1.直接赋值 2.动态代码块 3.构造方法
//静态属性+final赋值: 1.直接赋值 2.静态代码块
class Pig{
//The blank final field name may not have been initialized
final String name/*="张三"*/; //成员变量会变成常量,需要初始赋值
/*{
name = "张三丰";
}*/
public Pig() {
name = "张三疯";
}
static final String sex/*="男"*/; //状态值的使用--常用
static {
sex = "女";
}
int count = 5;
}
public class Test2 {
public static void main(String[] args) {
final int a = 3;
//a = 5; //final修饰基本类型变量,值不能改变
//final修饰应用类型变量:数组、对象
//1.final修饰数组
final int[] as = {1,3,5}; //new 空间的简写
as[0] = 66; //值可变
//as = new int[] {2,4}; //final修饰引用变量, 地址不可变
//2.final修饰对象
final Pig pig = new Pig();
//pig = new Pig(); //地址不可变
pig.count = 3; //里面的属性值可改变
}
}
六、总结
1.内存分析
内存存储的5大区域;重点分析:堆,栈,方法区(重点)
通过案例说明了内存的执行流程
2.静态属性
静态属性与成员属性的区别(重点)
应用场景:统计全局资源; 状态值的使用(重点)
3.静态方法
静态方法的特点;应用场景:作为工具类使用(重点)
4.静态代码块
动态代码块的执行与作用;类加载的过程与触发机制
静态代码块的执行(重点)
实例化过程:实例化当前对象与子类对象的静态和动态代码块综合案例
5.final的使用
修饰类,修饰方法,修饰变量(修饰静态变量用得多-静态常量)