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

 
原文地址:https://www.cnblogs.com/alice-cj/p/11182267.html