本篇文章主要分为两个模块进行介绍: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和“this、super”势不两立,因为this、super正好跟具体对象有关。
也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,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