Java面向对象基础(8-static和final)
static关键字
作用:在没有创建对象的情况下进行调用(方法/字段)。
- static字段
静态字段和非静态字段的区别:
静态字段被所有的对象所共享,在内存中只有一个副本,当且仅当类初次加载时会被初始化。
非静态字段是对象所拥有的,在创建对象时会被初始化,存在多个副本,各个对象拥有的副本互不影响。
public class Main {
public static void main(String[] args) {
System.out.println(Person.name);
}
}
class Person{
static String name="name";
}
可以在未创建Person对象的时候,对Person中的name静态字段进行访问。
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
}
}
class Person {
static String name="name";
}
也可以新建一个类对象进行调用,但是不推荐这样使用静态字段,因为编译器会根据实例类型自动将
实例变量.静态字段
转换类名.静态字段
,所以更推荐使用第一种方法进行访问。
在Java中,static 是不能用来修饰局部变量的
-
static方法
static方法
,由于静态方法不依赖于任何对象就可以访问,因此对于静态方法来说是没有this的,因为它不依赖于任何对象。并且因为这个特性,在静态方法中不能访问类的非静态方法和非静态字段,因为非静态方法和非静态字段都是必须依赖于具体的对象才能被调用。
静态方法不能访问非静态成员方法和非静态成员字段,但是,非静态方法可以访问静态成员方法和静态成员字段。 -
static代码块
static代码块可以用来优化程序性能,它可以置于类中任何地方,类中可以同时有多个代码块。
static代码块的特点是:在类初次被加载的时候,会按照static代码块的顺序来执行每个static块,并且只会执行一次。即只会在类加载的时候执行一次。
例如:
public class Main extends Base{
static{
System.out.println("Main Static Block");
}
public Main(){
System.out.println("Main Constructor");
}
public static void main(String[] args) {
new Main();
}
}
class Base {
static{
System.out.println("Base Static Block");
}
public Base(){
System.out.println("Base Constructor");
}
}
输出:
Base Static Block
Main Static Block
Base Constructor
Main Constructor
解析:
在程序执行开始的时候,需要先找到main方法,因为main方法是程序的入口,但是在执行main方法时,必须先加载Main类。而在加载Main类时,又发现Main类继承自Base类,故转去加载Base类,在加载Base类时,发现有static块,便执行了该块,输出Base Static Block
。在Base类加载完成后,便继续加载Main类,发现Main类中也有static块,便执行了该块,输出Main Static Block
。在加载完所需的类之后,便开始执行main方法。在main方法执行new Main()
的时候会先调用父类(Base类)的构造方法(输出Base Constructor
),然后再调用自身(Main类)的构造方法(输出Main Constructor
)。于是便有了上面的输出结果。
final关键字
final
关键字有“无法改变”或者“终态”的含义,可以修饰非抽象类、非抽象类成员方法和非抽象类成员字段。
final
修饰class
可以防止class
被继承
//Base类无法被继承
final class Base {
}
final
修饰method
可以防止method
被子类覆写
class Base {
public final void run(){
System.out.println("Running");
}
}
class Person extends Base{
//run无法被覆写,会编译错误
public void run(){
System.out.println("Stopping");
}
}
final
修饰field
可以阻止field
被重新赋值
public class Main{
public static void main(String[] args) {
Base base = new Base();
//会报错,无法为最终变量name赋值
base.name="None";
}
}
class Base {
public final String name="Name";
}
final
修饰参数
public class Main{
public static void main(String[] args) {
new Main().printName("Ming");
}
public void printName(final String name){
//name="Hong"; 加上这句会报错
System.out.println("姓名:"+name);
}
}
当函数参数为
final
类型时,可以使用该参数,但是不能更改该参数的值。