SentralLiu

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

java中的五大存储区域:
栈、堆、方法区、寄存器区、本地方法区
寄存器区:主要是线程的存储区域
本地防区:第三方语言的存储区域,例如:c/c++

重点分析三大区域:堆,栈,方法区
栈:存局部变量  (引用对象,基本变量)

堆:new对象,成员属性
方法区:class文件,静态区(static修饰),常量池(字符串常量)-往往方法区的东西只有一份

 

1 静态属性

=========================成员属性案例=========================

class MyClass{
    int a;  //成员属性
}


public class Test1 {
    public static void main(String[] args) {
        MyClass obj1 = new MyClass();
        MyClass obj2 = new MyClass();
        
        obj1.a = 3;
        obj2.a = 5;
        
        System.out.println(obj1.a+"---"+obj2.a);
    }
}

 

=======================静态属性案例==========================

实例属性 VS 静态属性
实例属性: 在堆区,属于对象,通过对象调用;每个对象独有的一份
静态属性: 在方法区,属于类,推荐使用类名调用;所有对象共享同一份

class MyC{
    static int a;
}
public class Test2 {
    public static void main(String[] args) {
        MyC obj1 = new MyC();
        MyC obj2 = new MyC();
        
        //The static field MyC.a should be accessed in a static way
        obj1.a = 3;  //MyC.a = 3; 静态属性属于类,推荐通过类名调静态属性
        obj2.a = 5;
        
        System.out.println(obj1.a+"---"+obj2.a);
    }
}

===================静态属性课堂案例====================

案例: 统计对象new了多少次
分析: 先编写面向对象; 每new一次,则次数++

class A{
    static int count;  //初始为0
    public A(){
        count++;  //使用静态属性进行统计
    }
}
public class Test3 {
   public static void main(String[] args) {
      new A();
      
      new A();
      
      new A();
      
      System.out.println("总共new了"+A.count+"次");
   }
}

2 静态方法

=====================静态方法应用====================

问题:在静态方法中,能否使用成员属性;--不能  
      在成员方法中能否使用静态属性?--能  为什么?

思考: 函数入口为何要这么设计?    public  static void main()
public:公开权限,使得外部jvm有权限调用
static:优先加载,无需new对象,提高性能
void:  无需反馈结果到jvm 

class MyClass{
    static int a;   //静态属性
    int  b;         //成员属性
    
    //静态方法中不能使用this与super关键字--加载时机问题
    //静态方法可以继承,但不能重写
    public static void test() {  //静态方法
        System.out.println("测试的方法...");
        //加载时机问题,静态区在类加载时就进行加载了,这时还不知道对象属性; 静态区优先对象加载
        //System.out.println(b); 
    }
    
    public void print() {
        System.out.println(a);
    }
}

class Son extends MyClass{
    /*@Override   
    public static void test() {  //静态方法,不能重写
    }*/
}

public class Test1 {
    public static void main(String[] args) {
        //之前方法调用,因为是调当前类的方法,所有省略了类名的调用
        System.out.println(add(1,2));  //调当前类的方法  等价Test1.add(1,2);
        
        //The static method add(int, int) from the type Test1 should be accessed in a static way
        System.out.println(new Test1().add(3, 5)); //可以通过对象调静态方法,但是不推荐
        
        //调用系统提供的静态方法
        int[] a = {1,2,3};
        System.out.println(Arrays.toString(a)); //调其他类的方法: 类名.方法
        
        MyClass.test();  //调用自定义类的静态方法
        
        //new Son().test();  //静态方法具有继承性
    }

    //静态方法:属于类,推荐使用类名调用
    public static int add(int a, int b) {
        return a+b;
    }
}

=====================静态的应用场景====================

静态属性和静态方法的应用场景:
静态属性: 一般作为状态值去使用(往往变量全大写)---固定值,不用更改,直接使用-做逻辑判断
状态值的好处: 可读性更强 ,可维护性更强(变更数值了,不用每个地方都去改)

静态方法:作为工具类来使用(工具类:统一供外部调用的公共类;例如:Arrays,所有数组操作的静态方法都放到该类)

class MyC{
    static int SEX_MAN = 11;  //代表男
    static int SEX_WOMAN = 10;  //代表女
}

public class Test2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入性别:1.男性,0.女性:  ");
        int sex = sc.nextInt();
        if(sex==MyC.SEX_MAN) {
            System.out.println("你输入的是男性");
        }else if(sex==MyC.SEX_WOMAN) {
            System.out.println("你输入的是女性");
        }
        
        
        /*
        if(sex==MyC.SEX_MAN) {
            System.out.println("你输入的是男性");
        }else if(sex==MyC.SEX_WOMAN) {
            System.out.println("你输入的是女性");
        }*/
            
    }
}

3 动态代码块与类加载
=====================动态代码块案例====================
动态代码块: 就是类中的一块区域,只要在类中加入{},就是一个代码块;
通过实例化对象可以触发到动态代码块
执行流程:
成员属性>动态代码块>构造方法
作用: 给属性赋予初始值

类加载过程:
jvm根据classpath查找class文件,并将class文件中的所有信息(包名,类名,对象,属性,方法等)加载到内存中
需要在入口main中触发执行类加载

class MyClass{
    String a = "成员属性";
    static String b = "静态属性";
    {
        System.out.println(a);
        System.out.println("动态代码块");
    }

    public MyClass() {
        System.out.println("构造方法");
    }
    
    public static void show() {
        System.out.println("调用静态方法");
    }
}

class Son extends MyClass{
    
}
public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //new MyClass();  //实例化对象触发
        //new Son();        //实例化子类对象
        //System.out.println(MyClass.b);  //静态属性触发类加载
        //MyClass.show();   //使用静态方法触发类加载
        Class.forName("com.qf.c_statickuai.MyClass");  //加入全限定名,触发类加载-反射后面学
    }
}


=====================静态代码块的执行====================
静态代码块的执行:
先执行静态属性>静态代码块(通过反射触发)

class MyC{
    static String a = "静态属性";
    //静态代码块
    static {
        System.out.println(a);
        System.out.println("静态代码块");
    }
    
}

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("com.qf.c_statickuai.MyC");
    }
}


=====================动态代码块与静态代码块====================
对象的执行过程(动态代码块+静态代码块):
规则: 先静态,后动态     静态属性->静态代码块->成员属性->动态代码块->构造方法
再new一个对象: 再执行一次,成员属性->动态代码块->构造方法
结论:static与对象无关,静态代码块只加载一次,优先于非静态的执行

class Super{
    static String a = "父类静态属性";
    String  b = "父类成员属性";
    static {
        System.out.println(a);
        System.out.println("父类静态代码块");
    }
    
    {
        System.out.println(b);
        System.out.println("父类动态代码块");
    }
    
    public Super() {
        System.out.println("构造方法");
    }
}

public class Test1 {
    public static void main(String[] args) {
        new Super();  //实例化当前类的构造方法    先静态,后动态
        System.out.println("===============");
        new Super();  //再new一个对象
    }
}


=====================子类的实例化过程====================
案例:子类继承Super类,观察子类实例化过程
规则: 先父类,再子类,先静态,后动态执行流程:父类静态属性>父类静态代码块>子类静态属性>子类静态代码块>父类成员属性>父类动态代码块
       父类构造方法>子类成员属性>子类动态代码块>子类构造方法

class Son extends Super{
    static String a = "子类静态属性";
    String b = "子类成员属性";
    {
        System.out.println(b);
        System.out.println("子类动态代码块");
    }
    
    static {
        System.out.println(a);
        System.out.println("子类静态代码块");
    }
    
    public Son() {
        System.out.println("子类构造方法");
    }
}

public class Test2 {
    public static void main(String[] args) {
         new Son();
    }
}

 final

final:表示最终的,可以修饰类,方法,属性
修饰类:最终类(太监类),被final修饰的类不能有子类
修饰方法: 该方法不能被重写
修饰属性: 变量变为了常量,往往在静态属性中final与static配合使用(状态值)-静态常量
 

//final修饰类,该类不能有子类
/*final*/ class Super{
    //静态常量必须初始化时要赋值
    //静态常量赋值时机:1.初始时赋值   2.静态代码块
    public final static int COUNT=1;  //状态值往往是不能被改变的,+final修饰则变为了常量
    /*static {
        COUNT = 2;
    }*/

    //成员常量必须初始化时要赋值
    //成员常量赋值时机: 1. 初始时赋值   2.动态代码块   3.构造方法
    public final int d=1;
    /*{
        d = 3;
    }*/
    
    /*public Super() {
        d = 5;
    }*/
    
    
    
    //final修饰方法,该方法不能被重写
    public /*final*/ void test(){
        
    }
}

//The type Son cannot subclass the final class Super
class Son extends Super{
    int b;
    @Override
    //Cannot override the final method from Super
    public void test(){
        
    }
}

public class Test1 {
    public static void main(String[] args) {
        //Super.COUNT = 5;  //The final field Super.COUNT cannot be assigned
        
        //基本类型的局部变量中的final修饰: 该变量值不能改变
        final int a = 3;
        //a = 5;  不能改变
        
        //引用类型的局部变量中加final修饰: 该变量地址不能改变,与属性值无关
        final Son son = new Son();
        //son.b = 6;
        //son = new Son();  //地址不能改变
        
        //数组也是引用类型,修饰数组后,地址不能变,里面的元素值可以变
        final int[] c = {1,2,3};
        //c = new int[]{4,5};  //地址不能改变
        c[0] = 6;
        
    }
}

posted on 2021-10-27 17:45  SentralLiu  阅读(32)  评论(0)    收藏  举报