• final、static、代码块、静态代码块、内部类、代码执行顺序


    final

    final域使得确保初始化安全性(initialization safety)成为可能,初始化安全性让不可变形对象不需要同步就能自由地被访问和共享
    作用在类上               则为final类,final类不能被继承。一般用于工具类时,同时把工具类构造函数声明为私有,暴露静态共有方法
    作用在成员变量上    则视为常量。此时赋值方式有三种:(1)声明时赋值(2)构造函数中赋值(3)代码块中赋值。 即不管哪种方式都要保证在使用该变量之前要确保已经有值。使用该特性,可以强制赋值。final变量因为不可变,所以可以安全的存在于多线程中。
    作用在方法上           作用在方法上可以保证该方法不能被重写
    作用在参数上           保证在方法体内部参数值不会被再次赋值,一般好的编程习惯应该把参数值视为final,不管有没有显示使用final(重构)

    static

    static关键字是隶属于类而非对象。这也就意味着不管声明了几个对象,static关键字所修饰的空间只占用一份。改变了之后,所有的引用它的都会发生变化。静态成员变量为所有类的对象共享。不像对象之间的变量是无影响的。所以对于static修饰的成员变量或者静态代码块是在类加载的时候已经装载。这种特性可以做一些初始化的工作而且保证只初始化了一次。
    作用在包上 (import static(注意这里不是static import  com…..ClassName.* 静态导包)这种以后再使用包里面的静态方法或者成员变量时会比较方便。eg:
    import static java.lang.Integer.*;
    int max_value = MAX_VALUE;
    toHexString(max_value);
    这样就导入了Integer类下面所有的静态方法和成员变量。在使用的时候就可以省去Integer,直接使用。
    作用在类上       修饰类则为静态类。只能作为静态内部类,如果直接修饰类,则不能通过编译。
    作用在方法上   修饰方法则为静态方法。静态方法中不能使用非静态变量。因为静态方法中不能确定该方法是否有被初始化。但是非静态方法可以引用静态变量。
    作用在变量上   作用在变量上则为静态变量。静态成员变量一般声明为final的。因为隶属于该类所有对象,可更改存在着危险。

    代码块

    代码块分为普通代码块和构造代码块
    普通代码块:在方法或语句中出现的{},用的比较少。执行顺序是按声明顺序执行。eg:
    1 public static void main(String[] args) {
    2         {
    3             System.out.println("普通代码块-先声明");
    4         }
    5         System.out.println("函数普通");
    6         {
    7             System.out.println("普通代码块-后声明");
    8         }
    9     }
    程序输出结果如下:
    普通代码块-先声明
    函数普通
    普通代码块-后声明
    构造代码块:直接在类中定义且没有static关键字的代码块,比较常用。执行顺序是在构造函数执行之前执行,每声明一个对象都会执行一次。
     1 public class CodeBlock {
     2     {
     3         System.out.println("构造代码块-先声明-执行");
     4     }
     5     public CodeBlock(){
     6         System.out.println("构造器执行");
     7     }
     8     {
     9         System.out.println("构造代码块-后声明-执行");
    10     }
    11     public void plainFunc(){
    12         System.out.println("普通方法执行");
    13     }
    14     public static void main(String[] args) {
    15         System.out.println("main方法");
    16         CodeBlock cb1 = new CodeBlock();
    17         cb.plainFunc();
    18         CodeBlock cb2 = new CodeBlock();
    19     }
    20 }
    程序输出结果如下:
    main方法
    构造代码块-先声明-执行
    构造代码块-后声明-执行
    构造器执行
    普通方法执行
    构造代码块-先声明-执行
    构造代码块-后声明-执行
    构造器执行
    结论:
    执行顺序:main方法->构造代码块->构造函数->普通方法
    每实例化一个对象,则执行一次构造代码块

    静态代码块

    在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。
    如果类中包含多个静态代码块,那么将按照"先定义的代码先执行,后定义的代码后执行"。
    注意:1 静态代码块不能存在于任何方法体内。2 静态代码块不能直接访问静态实例变量和实例方法,需要通过类的实例对象来访问。
     1 class Code{
     2     {
     3       System.out.println("Code的构造块");
     4     }
     5     
     6     static{
     7         System.out.println("Code的静态代码块");
     8         }
     9         
    10     public Code(){
    11         System.out.println("Code的构造方法");
    12         }
    13     }
    14 public class CodeBlock{
    15      {
    16       System.out.println("CodeBlock的构造块");    
    17      }
    18      
    19      static{
    20         System.out.println("CodeBlock的静态代码块");
    21         }
    22         
    23         public CodeBlock03(){
    24              System.out.println("CodeBlock的构造方法");
    25             }
    26         
    27       public static void main(String[] args){
    28             System.out.println("CodeBlock的主方法");
    29             new Code();
    30             new Code();
    31             new CodeBlock();
    32             new CodeBlock();
    33           }
    34     }
    程序输出如下
    CodeBlock的静态代码块
    CodeBlock的主方法 //这里还没有加载Code,所以先执行主方法,再执行Code的静态代码块
    Code的静态代码块 
    Code的构造块
    Code的构造方法
    Code的构造块
    Code的构造方法
    CodeBlock的构造块
    CodeBlock的构造方法

    内部类

    ⒈成员内部类⒉静态内部类⒊局部内部类⒋匿名内部类
    定义
    将一个类的定义放在另一个类的定义内部,这就是内部类
    初见内部类
    内部类的创建就和定义的一样,把一个类定义在另一个类的内部
     1 public class Parcel2 {
     2   class Contents {
     3     private int i = 11;
     4     public int value() { return i; }
     5   }
     6   class Destination {
     7     private String label;
     8     Destination(String whereTo) {
     9       label = whereTo;
    10     }
    11     String readLabel() { return label; }
    12   }
    13   public Destination to(String s) {
    14     return new Destination(s);
    15   }
    16   public Contents contents() {
    17     return new Contents();
    18   }
    19   public void ship(String dest) {
    20     Contents c = contents();
    21     Destination d = to(dest);
    22     System.out.println(d.readLabel());
    23   }
    24   public static void main(String[] args) {
    25     Parcel2 p = new Parcel2();
    26     p.ship("Tasmania");
    27     Parcel2 q = new Parcel2();
    28     // Defining references to inner classes:
    29     Parcel2.Contents c = q.contents();
    30     Parcel2.Destination d = q.to("Borneo");
    31   }
    32 }
    这里在类Parcel2中创建了两个内部类Contents和Destination。同时每个内部类对应的创建了一个外部类方法,该方法用来返回一个指向内部类对象的引用。这种方式很常用!如果不提供指向内部类对象引用的函数,需要借助“.new”来创建内部类对象(后面会有用法)。如果想从外部类的非静态方法之外的任意位置创建某个内部类对象,那么必须像上述main()方法那样,具体指明这个对象的类型:OutClassName.InnerClassName(eg:Parcel2.Contents),为什么要这么做呢?
    注意:非静态内部类对象有着指向外部类对象的引用。
    这可以至少解释两个问题:
    1、内部类拥有外部类的所有元素的访问权(因为当生成内部类时内部类自动产生了指向外部类对象的引用,该引用可以访问外部类的所有成员)
    2、创建内部类对象时,需要指明对象类型,即:
    OutClassName out = new OutClassName();
    OutClassName.InnerClassName=out.new InnerClassName(); 
     
    使用 .this 和 .new
    如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟原点和this。如果需要生成内部类对象,可以使用外部类对象后面紧跟原点和this。
    外部类引用:
    public class DotThis {
      void f() { System.out.println("DotThis.f()"); }
      public class Inner {
        public DotThis outer() {
          return DotThis.this;
          // A plain "this" would be Inner's "this"
        }
      }
      public Inner inner() { return new Inner(); }
      public static void main(String[] args) {
        DotThis dt = new DotThis();
        DotThis.Inner dti = dt.inner();
        dti.outer().f();
      }
    }
    注意:上面代码DotThis.this返回外部类对象引用,如果直接使用this,则是内部类Inner对象引用,不能通过编译。
    创建内部类对象:
    public class DotNew {
      public class Inner {}
      public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();
      }
    }
    内部类语法
    一、成员内部类(非静态):
    1、可以访问外部类所有元素
    2、创建对象两种方式:(1)在外部类中声明方法返回内部类对象的引用(2)通过内部类对象后跟原点和new的方式(eg:DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner();)
    3、成员内部类中不能包含静态数据(成员变量和方法)
    二、静态内部类:
    1、不能访问外部类的非静态元素和方法。(因为静态内部类没有指向外部类对象的引用,只能直接通过类名来调用)
    2、创建方式比较简单
    Outer.Inner inner = new Outer.Inner();
    inner.func();
    3、可以包含静态数据
    三、局部内部类
    局部内部类就是可以定义在方法体内,比较少用
    四、匿名内部类
    interface content{
            int func();
        }
    System.out.println(new content(){
                @Override
                public int func() {
                    return 1;
                }
            }.func());
    内部类优势:
    1、可以访问外部类所有元素
    2、隐藏性好,只有本类可操作
    3、可以解决C++里面的多继承问题。怎么解决?
    我们知道,Java不支持多继承(即一个类同时继承两个或多个类),只支持多重继承(即A继承B,B继承C,那么A间接继承了C),利用Java的内部类机制可以做到多重继承的效果。可以声明多个内部类分别继承相应的类,然后对于外部类来说,就同时拥有了相应内部类的功能。

    代码执行顺序

    1、父类静态代码块->父类静态成员变量初始化->子类静态代码块->子类静态成员变量初始化->(父类代码块->父类成员变量初始化)(这两个谁先声明谁在前面)->子类代码块->子类成员变量初始化->父类构造函数->子类构造函数->...
    • 静态先于非静态执行
    • 代码块可以当做成员变量来看,对于静态代码块,类加载的时候执行;对于非静态代码块,构造函数之前执行,可以想成是在成员变量初始化的时候执行
    • 父类优先于子类执行(因为子类涉及到对父类的重写等操作,只有父类初始完毕了,子类重写和引用才有意义)

    参考文章:

    1、《java编程思想》

    2、http://www.cnblogs.com/sophine/p/3531282.html

  • 相关阅读:
    冲刺2 05
    冲刺02 04
    人月神话阅读笔记01
    进度条
    团队冲刺第十天
    团队冲刺第九天
    学习进度条13
    团队冲刺第八天
    怎样买书更便宜
    冲刺第七天
  • 原文地址:https://www.cnblogs.com/uodut/p/7067195.html
Copyright © 2020-2023  润新知