• final与 static的区别;static代码块以及嵌套类介绍


    本篇文章主要分为两个模块进行介绍:1.final,staic,static final之间的异同;2. static 模块;3.嵌套类的概念

    1.final,staic,static final之间的异同:

    (1)final

     final可以修饰属性,方法,类,局部变量(静态变量、实例变量和局部变量);

    其中,final修饰的属性表明是个常量,它的初始化可以在编译期,也可以在运行期,初始化后不能被改变;

    final修饰的属性跟具体对象有关,在运行期初始化的final属性,不同对象可以有不同的值;

    final修饰的方法不能被子类方法覆盖,但可以被继承;

    private不能被子类方法覆盖,private类型的方法默认是final类型的

    final修饰的类不能被继承,没有子类,final类中的方法默认是final的

    final不能用于修饰构造方法;

    另外,对于基本类型数据,final会将值变为一个常数(创建后不能被修改);但是对于对象句柄(亦可称作引用或者指针),final会将句柄变为一个常数(进行声明时,必须将句柄初始化到一个具体的对象。而且不能再将句柄指向另一个对象。但是,对象的本身是可以修改的。这一限制也适用于数组,数组也属于对象,数组本身也是可以修改的。方法参数中的final句柄,意味着在该方法内部,我们不能改变参数句柄指向的实际东西,也就是说在方法内部不能给形参句柄再另外赋值)。

    (2)static

    static表示“全局”或者“静态”的意思,可以用来修饰:属性,方法,代码段,内部类(静态内部类或嵌套内部类),static不可以修饰局部变量。
    其中,static修饰的属性的初始化在编译期(类加载的时候),初始化后能改变,并且每个对象都只有一个值,主要强调它们只有一个。

    static修饰的属性、方法、代码段跟该类的具体对象无关,不创建对象也能调用static修饰的属性、方法等,

    static和“this、super”势不两立,因为this、super正好跟具体对象有关。

    也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

    用public修饰的static属性和方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。
     其中:
    - 类成员变量
      - 静态变量(类变量): static修饰
      - 实例变量  : 无static修饰
      - 局部变量 :(方法内部声明)

    (3)static final(等价于final staic,但是一般习惯staic在前)

    static修饰的属性强调它们只有一个,final修饰的属性表明是一个常数(创建后不能被修改)。static final修饰的属性表示一旦给值,就不可修改,并且可以通过类名访问。static final也可以修饰方法,表示该方法不能重写,可以在不new对象的情况下调用

    2.static{}代码块与普通{}代码块的区别

    在类中,可以将某一块代码声明为静态的,这样的程序块叫静态初始化段。静态代码块的一般形式如下:

    1 //静态代码块
    2 static {
    3   语句序列
    4 }
    5 
    6 //普通代码
    7 {
    8   语句序列
    9 }

    其中,静态代码块只能定义在类里面,它独立于任何方法,不能定义在方法里面。

    静态代码块里面的变量都是局部变量,只在本块内有效。

    静态代码块会在类被加载时自动执行,而无论加载者是JVM还是其他的类。

    一个类中允许定义多个静态代码块,执行的顺序根据定义的顺序进行。

    静态方法只能访问静态成员,实例方法可以访问静态和实例成员。之所以不允许静态方法访问实例成员变量,是因为实例成员变量是属于某个对象的,而静态方法在执行时,并不一定存在对象。同样,因为实例方法可以访问实例成员变量,如果允许静态方法调用实例方法,将间接地允许它使用实例成员变量,所以它也不能调用实例方法。基于同样的道理,静态方法中也不能使用关键字this。main()方法是一个典型的静态方法,它同样遵循一般静态方法的规则,所以它可以由系统在创建对象之前就调用。

    例子1:

     1 public class staticBlock{
     2 //定义一个普通的main()方法
     3 public static void main(String args[]){
     4 System.out.println("This is main method.");  
     5 }
     6 //定义一个静态代码块
     7 static{
     8 System.out.println("This is static block.");
     9 int stVar = 0;   //这是一个局部变量,只在本块内有效
    10 }
    11 }

    运行结果:

    This is static block.
    This is main method. 

    从以上输出结果中可以看出,静态代码块甚至在main方法之前就被执行。在main()方法中可以完成的任务在静态代码块中都可以完成。但是二者在执行上仍然有一些区别。

    例子2:

     1 public class staticBlock{
     2 static int stMember = 100;    //定义静态成员变量
     3 public static void main(String args[]){
     4 System.out.println("This is main method.");
     5 }
     6 //第一个静态代码块
     7 static{
     8 System.out.println("This is first static block.");
     9 stMember  = 200;      //访问静态成员变量
    10 staticBlock oa = new staticBlock(); //创建对象
    11 System.out.println("stMember = " + oa.stMember);
    12 statFun();        //调用静态方法
    13 }
    14 //定义一个静态方法
    15 static void statFun(){
    16 System.out.println("This is a static method.");
    17 } 
    18 //第二个静态代码块
    19 static{
    20 System.out.println("This is second static block.");
    21 }
    22 }

    运行结果如下:

    This is first static block.
    stMember = 200
    This is a static method.
    This is second static block.
    This is main method.
    

    静态代码块与普通代码块的差异如下:

    相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,

        一般在代码块中对一些static变量进行赋值。

    不同点:静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。

        静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new

        一次就执行一次。非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行。

    例子:

     1 //普通类
     2 public class PuTong {
     3     public PuTong(){
     4         System.out.print("默认构造方法!-->");
     5     }
     6     
     7     //非静态代码块
     8     {
     9         System.out.print("非静态代码块!-->");
    10     }
    11     
    12     //静态代码块
    13     static{
    14         System.out.print("静态代码块!-->");
    15     }
    16     
    17     public static void test(){
    18         {
    19             System.out.println("普通方法中的代码块!");
    20         }
    21     }
    22 }
    23 
    24 //测试类
    25 publicclass TestClass {
    26     
    27     /**
    28      * 区别两次new静态与非静态代码块执行情况
    29      */
    30     public static void main(String[] args) {
    31         PuTong c1 = new PuTong();
    32         c1.test();
    33         
    34         PuTong c2 = new PuTong();
    35         c2.test();
    36     }
    37 }

    /*
    运行输出结果是:
    静态代码块!-->非静态代码块!-->默认构造方法!-->普通方法中的代码块!
    非静态代码块!-->默认构造方法!-->普通方法中的代码块!
    */

    一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的.

    两者的区别就是:静态代码块是自动执行的;

    静态方法是被调用的时候才执行的.

    作用:静态代码块可用来初始化一些项目最常用的变量或对象;静态方法可用作不创建对象也可能需要执行的代码.

     

    3.嵌套类概念

    可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,最重要的是非静态嵌套类,也即是被称作为内部类(inner)。嵌套类从JDK1.1开始引入。其中inner类又可分为三种:
      其一、在一个类(外部类)中直接定义的内部类;
      其二、在一个方法(外部类的方法)中定义的内部类;
      其三、匿名内部类。

    (1)静态嵌套类

     1 public class StaticTest {   
     2         private static String name = "javaJohn";           
     3   private String id = "X001";  
     4   static class Person{  
     5     private String address = "swjtu,chenDu,China";  
     6     public String mail = "josserchai@yahoo.com";//内部类公有成员  
     7     public void display(){  
     8       //System.out.println(id);//不能直接访问外部类的非静态成员  
     9       System.out.println(name);//只能直接访问外部类的静态成员  
    10       System.out.println("Inner "+address);//访问本内部类成员。  
    11     }  
    12   }  
    13   
    14   public void printInfo(){  
    15     Person person = new Person();  
    16     person.display();  
    17     //System.out.println(mail);//不可访问  
    18     //System.out.println(address);//不可访问  
    19     System.out.println(person.address);//可以访问内部类的私有成员  
    20     System.out.println(person.mail);//可以访问内部类的公有成员  
    21   
    22   }  
    23   public static void main(String[] args) {  
    24   StaticTest staticTest = new StaticTest();  
    25   staticTest.printInfo();  
    26 }  
    27 } 

    在静态嵌套类内部,不能访问外部类的非静态成员,这是由Java语法中"静态方法不能直接访问非静态成员"所限定。若想访问外部类的变量,必须通过其它方法解决,由于这个原因,静态嵌套类使用很少。注意,外部类访问内部类的的成员有些特别,不能直接访问,但可以通过内部类来访问,这是因为静态嵌套内的所有成员和方法默认为静态的了。同时注意,内部静态类Person只在类StaticTest 范围内可见,若在其它类中引用或初始化,均是错误的。

    (2)外部内中的内部类

     1  public class Outer {   
     2            int outer_x = 100;  
     3     class Inner{  
     4       public int y = 10;  
     5       private int z = 9;  
     6       int m = 5;  
     7       public void display(){  
     8         System.out.println("display outer_x:"+ outer_x);  
     9       }  
    10       private void display2(){  
    11         System.out.println("display outer_x:"+ outer_x);  
    12       }  
    13     }  
    14     void test(){  
    15       Inner inner = new Inner();  
    16       inner.display();  
    17       inner.display2();  
    18       //System.out.println("Inner y:" + y);//不能访问内部内变量  
    19       System.out.println("Inner y:" + inner.y);//可以访问  
    20       System.out.println("Inner z:" + inner.z);//可以访问  
    21       System.out.println("Inner m:" + inner.m);//可以访问  
    22       InnerTwo innerTwo = new InnerTwo();  
    23       innerTwo.show();  
    24     }  
    25     class InnerTwo{  
    26       Inner innerx = new Inner();  
    27       public void show(){  
    28         //System.out.println(y);//不可访问Innter的y成员  
    29         //System.out.println(Inner.y);//不可直接访问Inner的任何成员和方法  
    30         innerx.display();//可以访问  
    31         innerx.display2();//可以访问  
    32         System.out.println(innerx.y);//可以访问  
    33         System.out.println(innerx.z);//可以访问  
    34         System.out.println(innerx.m);//可以访问  
    35       }  
    36     }  
    37     public static void main(String args[]){  
    38       Outer outer = new Outer();  
    39       outer.test();  
    40     }  
    41   }  

    以上代码需要说明有,对于内部类,通常在定义类的class关键字前不加public 或 private等限制符,若加了没有任何影响,同时好像这些限定符对内部类的变量和方法也没有影响(?)。另外,就是要注意,内部类Inner及InnterTwo只在类Outer的作用域内是可知的,如果类Outer外的任何代码尝试初始化类Inner或使用它,编译就不会通过。同时,内部类的变量成员只在内部内内部可见,若外部类或同层次的内部类需要访问,需采用示例程序中的方法,不可直接访问内部类的变量。

    3.在代码块的作用域内定义内部类。

     1 public class Outer {
     2 
     3     private String outerName = "This is Outer Name";
     4 
     5     public void test() {
     6 
     7         for(int i=0;i<3;i++) {
     8              class Inner {
     9                 public void display() {
    10                     System.out.println(outerName);
    11                 }
    12             }
    13              Inner inner = new Inner();
    14              inner.display();
    15         }
    16     } 
    17 }

    在上面的代码中,只能定义成class inner,不能定义成public class inner,因为此时是作为方法中的变量定义的,不是作为类的成员变量。

    参考链接:

    https://blog.csdn.net/qq_40665031/article/details/78440084

    https://blog.csdn.net/hust_yfang/article/details/79585696

    https://www.cnblogs.com/EasonJim/p/7841990.html

    https://blog.csdn.net/leixiongbo/article/details/52161936

    https://blog.csdn.net/WelcomeSpring/article/details/79430546

     
  • 相关阅读:
    Sublime安装package control的操作
    Sublime的简单操作
    C# 泛型方法
    C# 数组的讲解(ArrayList 与List的区别)
    免费的天气API
    bootstrapValidator的验证
    sqlServer 多行合并为一行
    bootstrap的安装注意
    SQL数据库中把一个表中的数据复制到另一个表中
    JavaScript的误区
  • 原文地址:https://www.cnblogs.com/alice-cj/p/11182267.html
Copyright © 2020-2023  润新知