zl程序教程

您现在的位置是:首页 >  后端

当前栏目

第十一篇:一文解析Java常用关键字

JAVA 解析 常用 一文 关键字
2023-09-14 09:15:23 时间

一、前言

本文介绍六个关键字:static、final、extends、implements、this、super,下面具体介绍各个关键字及需要注意的点。

二、Java 51个关键字

记住1:两个保留字:const和goto (保留字:现在没用,以后用得上)

记住2:所有的关键字都是小写,一旦有大写的,一定不是关键字

三、关键字static

static是java中的一个关键字(key words),其表示的含义在于被static修饰的域、方法、代码块为类所有,而不是为代码所有,使用类名调用(亦可使用对象名调用),static域加载时仅加载一次。

第一点,非static方法、代码块内可以有非static域、方法、代码块,也可以有static域、方法、代码块;但是static方法、代码块内可以只能出现static域、方法、代码块,即static域、方法、代码块仅出现在static环境(static方法、代码块)下,static域只能出现在static方法或代码块中,static方法只能在static方法或代码块中被调用。如图1所示。

在这里插入图片描述

图1 外层环境与内部变量之间的关系

第二点,static方法可以用类名调用,也可以用对象名调用,但是非static方法只能由对象名调用调用,因为非static方法只有在对象存在时才有意义,如图2所示。

在这里插入图片描述

图2 static方法和非static方法调用方式

四、关键字final

4.1 概要

Java语言中final是一个关键字(key words),其表示的三个含义:final修饰的变量是常量,final修饰的类不可继承,final修饰的方法不可重写。

final关键字三个特性:final修饰的变量为常量、final修饰的类不可继承、final修饰的方法不可重写。

4.2 final修饰的变量为常量

4.2.1 基本类型与引用类型

对于final修饰的变量,应该对基本类型和引用类型分开讨论:

4.2.1.1 基本类型(byte short int long float double boolean char)

基本类型为栈内存(-128~127情况下),一旦被final关键字修饰,其变量属性变为只读,不再进行写操作,否则编译报错。

4.2.1.2 引用类型 (类、接口、数组)

引用类型为堆内存,一旦被final关键字修饰,则引用不再改变,但是引用所指向的对象是可以被修改的,Java语言并未提供任何方式使用对象恒定不变。示意代码如下:

public class FinalData {
    private final Value value = new Value(22);

    public static void main(String[] args) {
        FinalData finalData = new FinalData();

        //finalData.value=new Value(33);   // 编译报错,value为final类型
        finalData.value.i++; // 编译通过,value所指向的对象可以修改
    }
}

class Value {
    int i;

    public Value(int i) {
        this.i = i;
    }
}

4.2.2 初始化时机

4.2.2.1 final变量定义时初始化

final变量定义时初始化常见,定义时直接赋值即可,不再赘言。

4.2.2.2 final变量构造函数中初始化(空白final)

因为被final修饰的变量一定要在使用前被初始化,所以如果没在定义操作,一定在构造函数中初始化,这种情况称为空白final。示例代码如下:

public class FinalData {
    private final int i;//基本类型示意
    private final Value value;//引用类型示意

    public FinalData() { //  无参构造函数    空白final
        i = 1;
        value = new Value(1);
    }

    public FinalData(int x) {//有参构造函数  空白final
        i = x;
        value = new Value(x);
    }

    public static void main(String[] args) {
        new FinalData();
        new FinalData(22);

    }
}

class Value {
    int i;

    public Value(int i) {
        this.i = i;
    }
}

4.3 final修饰的类不可继承

类使用final关键字修饰之后,该类不可被继承,可以起到保护该类的作用。实例代码如下:

final class FinalFatherClass {

}

class SonClass extends FinalFatherClass {  //编译报错   final类不允许继承

}

4.4 final修饰的方法不可重写

class FinalFatherClass {
    final void f() {
        System.out.println("FinalFatherClass f()");
    }
}

class SonClass extends FinalFatherClass {
    final void f() {//编译报错    
    // 子类中某一方法的方法签名(方法名+形参列表)与父类相同,即可认为子类中该方法重写父类方法
    // 因final方法不可被重写,顾此处编译报错
        System.out.println("SonClass f()");
    }
}

值得注意的是,子类虽不能重写父类final函数,但是可以继承父类final函数,示意代码如下:

public class TestFinal {
    public static void main(String[] args) {
        FinalFatherClass son = new SonClass();
        son.f();    //打印  FinalFatherClass f()
        //因为子类未重写父类final函数,也不能重新父类final函数    
        //但子类可以继承父类final函数,所以调用父类 f()  打印  FinalFatherClass f()
    }
}

class FinalFatherClass {
    final void f() {
        System.out.println("FinalFatherClass f()");
    }
}

class SonClass extends FinalFatherClass {

}

从上面可以看到,final修饰的方法在特定的访问权限下可以被继承。

这是因为,方法是否被final修饰与方法的访问权限是两回事,没有任何关系,被final修饰的方法和未被final修饰的方法都可以自由的指定访问权限。

我们有兴趣去谈论final关键字和访问权限关键字在修饰方法的过程的起到的作用, 如下表(声明:final和访问权限是两个独立的概念,没有任何比较意义,所有本表仅方便读者理解,不可作为正统知识) :

protect关键字final关键字private关键字
是否可以继承
是否可以重写

小结 private<final<protect (仅适用于方法)

从表中可以看到,protect修饰的方法在子类中可见,所有可以被子类继承,亦可以被子类重写;

final修饰的方法可以被子类继承,但不可被子类重写(这里final方法的访问权限为默认的default、protected、public均可,只要保证子类可见即可);

private修饰的方法由于仅本类可见,故不能被子类继承,亦不能被子类重写。

4.5 private与final对比

实际上,Java语言中,所有被private关键字修饰的方法都隐式的被final关键字修饰,(正如上表所示,private实现了final方法不可重写的功能,并附加不可继承功能。)(再次声明:final和访问权限是两个独立的概念,没有任何比较意义,所有上表仅方便读者理解,不可作为正统知识)可以对private方法添加final关键字,但是这种做法没有任何意义。代码示例如下:

public class TestFinal {
    public static void main(String[] args) {
        FinalFatherClass fatherClass = new FinalFatherClass();

        SonClass sonClass = new SonClass();

        //f() 为final方法  被private修饰后 仅本类可见  所有不能到TestFinal类中调用
        //fatherClass.f();  
        //sonClass.f();

        //g() 虽然不是final方法  但被private修饰后 也是仅本类可见  所有不能到TestFinal类中调用
        //fatherClass.g();   
        //sonClass.g();

        //小结:java中,private方法已经隐式的包含final关键字  所以final关键字有无并不重要
    }
}

class FinalFatherClass {
    private final void f() {
        System.out.println("FinalFatherClass f()");
    }

    private void g() {
        System.out.println("FinalFatherClass g()");
    }
}

class SonClass extends FinalFatherClass {
    private final void f() {
        System.out.println("SonClass f()");
    }

    private void g() {
        System.out.println("SonClass g()");
    }
}

五、关键字extends和implements

Java中单继承多实现,先继承后实现(即当一个类既要继承又要实现的时候,顺序是先继承后实现 eg: extends A implements B)。

5.1 类继承类(单继承)

class SuperA {

}

class SuperB {

}

class Sub extends SuperA {//类继承类   只能继承一个类   单继承

}

5.2 类实现接口(多实现)

interface InterfaceA {
	
}
interface InterfaceB{
	
}
class Sub implements InterfaceA,InterfaceB{//类实现接口  可以实现多个接口  Java多实现
	
}

5.3 接口继承接口(多继承)

接口继承接口容易被人遗忘,一般我们只记得类继承类和类实现接口,但接口直接也可以相互继承,而且还是多继承。

interface InterfaceA {
	
}
interface InterfaceB{
	
}
interface InterfaceC extends InterfaceA,InterfaceB{//接口继承接口  可以多继承
	
}

六、关键字this与super

6.1 this与super

this表示当前类所指对象,super表示父类对象的引用

this关键字
this 当前类所指对象
this.字段名表示当前类字段,此处this可以省略
this.方法名() 调用当前类方法,此处this可以省略
super关键字
super() 调用父类无参构造函数,仅在子类构造函数中出现,可以省略,父类无参构造函数可以隐式调用
super(参数) 调用父类指定参数构造函数,仅在子类构造函数中出现,注意不可省略,父类带参构造函数无法隐式调用
super.字段名 子类中访问父类字段,用super.避免与子类同名字段混淆
super.方法名() 子类中调用父类函数,用super.避免与子类相同函数签名的函数混淆

6.2 父类构造函数和子类构造函数

代码示意:

public class Test_thisAndSuper {
 
	public static void main(String[] args) {
		System.out.println("=====无参构造函数=====");
		new BallGame();
		System.out.println("=====带参构造函数=====");
		new BallGame("basketBall");
	}
 
}
 
class Game {
	public Game() {
		System.out.println("Game non-parameter constructor");
	}
 
	public Game(String name) {
		System.out.println("Game parameter constructor: " + name);
	}
 
}
 
class BallGame extends Game {
	public BallGame() {
		super();// 此行代码 可有可无 Java中,子类构造函数可以隐式调用父类无参构造函数
		System.out.println("BallGame non-parameter constructor");
	}
 
	public BallGame(String name) {
		super(name);
		System.out.println("BallGame parameter constructor: " + name);
	}
}

输出结果:

=====无参构造函数=====
Game non-parameter constructor
BallGame non-parameter constructor
=====带参构造函数=====
Game parameter constructor: basketBall
BallGame parameter constructor: basketBall

附加:默认调用父类无参构造函数

public class Test1 {

    public static void main(String[] args) {
        System.out.println("=====无参构造函数=====");
        new BallGame();
        System.out.println("=====带参构造函数=====");
        new BallGame("basketBall");
    }

}

class Game {
    public Game() {
        System.out.println("Game non-parameter constructor");
    }

    public Game(String name) {
        System.out.println("Game parameter constructor: " + name);
    }

}

class BallGame extends Game {
    public BallGame() {
        super();// 此行代码 可有可无 Java中,子类构造函数可以隐式调用父类无参构造函数
        System.out.println("BallGame non-parameter constructor");
    }

    public BallGame(String name) {
        //super(name);
        System.out.println("BallGame parameter constructor: " + name);
    }
}

运行结果:

=====无参构造函数=====
Game non-parameter constructor
BallGame non-parameter constructor
=====带参构造函数=====
Game non-parameter constructor
BallGame parameter constructor: basketBall

6.3 父类字段和子类字段

代码示意:

public class Test_thisAndSuper {
 
	public static void main(String[] args) {
		System.out.println("=====无参构造函数=====");
		BallGame _ballGame_noParameter=new BallGame();
		System.out.println("=====带参构造函数=====");
		new BallGame("basketBall");
		System.out.println("=====打印字段=====");
		_ballGame_noParameter.displayField();
	}
 
}
 
class Game {
	protected String _description="This is an interesting game";
	public Game() {
		System.out.println("Game non-parameter constructor");
	}
 
	public Game(String name) {
		System.out.println("Game parameter constructor: " + name);
	}
 
}
 
class BallGame extends Game {
	protected String _description="This is an interesting ballgame";
	public BallGame() {
		super();// 此行代码 可有可无 Java中,子类构造函数可以隐式调用父类无参构造函数
		System.out.println("BallGame non-parameter constructor");
	}
 
	public BallGame(String name) {
		super(name);
		System.out.println("BallGame parameter constructor: " + name);
	}
	
	public void displayField(){
		System.out.println("父类字段: "+super._description);
		System.out.println("子类字段: "+this._description);
	}
}

输出结果:

=====无参构造函数=====
Game non-parameter constructor
BallGame non-parameter constructor
=====带参构造函数=====
Game parameter constructor: basketBall
BallGame parameter constructor: basketBall
=====打印字段=====
父类字段: This is an interesting game
子类字段: This is an interesting ballgame

6.4 父类方法和子类方法

代码示意:

public class Test_thisAndSuper {
 
	public static void main(String[] args) {
		System.out.println("=====无参构造函数=====");
		BallGame _ballGame_noParameter=new BallGame();
		System.out.println("=====带参构造函数=====");
		new BallGame("basketBall");
		System.out.println("=====打印字段=====");
		_ballGame_noParameter.displayField();
		System.out.println("=====打印方法调用=====");
		_ballGame_noParameter.displayFunction();
	}
 
}
 
class Game {
	protected String _description="This is an interesting game";
	public Game() {
		System.out.println("Game non-parameter constructor");
	}
 
	public Game(String name) {
		System.out.println("Game parameter constructor: " + name);
	}
	
    protected void  playing() {
	    System.out.println("This game is so interesting");
    }
}
 
class BallGame extends Game {
	protected String _description="This is an interesting ballgame";
	public BallGame() {
		super();// 此行代码 可有可无 Java中,子类构造函数可以隐式调用父类无参构造函数
		System.out.println("BallGame non-parameter constructor");
	}
 
	public BallGame(String name) {
		super(name);
		System.out.println("BallGame parameter constructor: " + name);
	}
	
	public void displayField(){
		System.out.println("父类字段: "+super._description);
		System.out.println("子类字段: "+this._description);//此处this可以省略
	}
	
	protected void  playing() {
		System.out.println("This ballgame is so interesting");
	}
	
	public void displayFunction(){
		System.out.print("父类方法: ");
		super.playing();
		System.out.print("子类方法: ");
		this.playing();//此处this可以省略
	}
}

输出结果:

=====无参构造函数=====
Game non-parameter constructor
BallGame non-parameter constructor
=====带参构造函数=====
Game parameter constructor: basketBall
BallGame parameter constructor: basketBall
=====打印字段=====
父类字段: This is an interesting game
子类字段: This is an interesting ballgame
=====打印方法调用=====
父类方法: This game is so interesting
子类方法: This ballgame is so interesting

6.5 this和super同时出现

子类构造函数中可以同时出现super和this关键字,但是super和this不能同时调用构造函数,代码示意:

public class Test_thisAndSuper {
 
	public static void main(String[] args) {
		System.out.println("=====无参构造函数=====");
		BallGame _ballGame_noParameter=new BallGame();
		System.out.println("=====带参构造函数=====");
		new BallGame("basketBall");
		System.out.println("=====打印字段=====");
		_ballGame_noParameter.displayField();
		System.out.println("=====打印方法调用=====");
		_ballGame_noParameter.displayFunction();
		
	}
 
}
 
class Game {
	protected String _description="This is an interesting game";
	public Game() {
		System.out.println("Game non-parameter constructor");
	}
 
	public Game(String name) {
		System.out.println("Game parameter constructor: " + name);
	}
	
 
protected void  playing() {
	System.out.println("This game is so interesting");
}
}
 
class BallGame extends Game {
	protected String _description="This is an interesting ballgame";
	public BallGame() {
		super();// 此行代码 可有可无 Java中,子类构造函数可以隐式调用父类无参构造函数
		System.out.println("BallGame non-parameter constructor");
	}
 
	public BallGame(String name) {
		super(name);
		System.out.println("BallGame parameter constructor: " + name);
	}
	public BallGame(String test1,String test2){
		//super(test1);
		//this(test1);  super()和this()都要放在第一行  自相矛盾  编译时报错
		//小结:super和this可以同时出现,即使是在子类构造方法中也可以同时出现,但是不同同时调用构造方法,
		
		//理论解释:因为在一个构造方法中,只能访问一次其它的构造方法(不管是父类的还是子类的)所以此时不能同时用super和this关键字来调用构造方法,只能根据需求选其一。
		//简单理解:调用构造函数时,两个都要放第一,自相矛盾
	}
	public void displayField(){
		System.out.println("父类字段: "+super._description);
		System.out.println("子类字段: "+this._description);//此处this可以省略
	}
	
	protected void  playing() {
		System.out.println("This ballgame is so interesting");
	}
	
	public void displayFunction(){
		System.out.print("父类方法: ");
		super.playing();
		System.out.print("子类方法: ");
		this.playing();//此处this可以省略
	}
}

输出结果:

因不可同时调用父类构造函数和子类构造函数,无输出结果

小结(面试金手指,this与super同时出现)

1、super和this可以同时出现,即使是在子类构造方法中也可以同时出现,但是不同同时调用构造方法;

2、理论解释:因为在一个构造方法中,只能访问一次其它的构造方法(不管是父类的还是子类的)所以此时不能同时用super和this关键字来调用构造方法,只能根据需求选其一;

3、简单理解:调用构造函数时,两个都要放第一,自相矛盾。

七、面试金手指

7.1 static关键字

定义:static修饰的域、方法、代码块为类所有,而不是为对象所有;

调用:可以使用类名调用(亦可使用对象名调用);

变量加载顺序:static域加载时仅加载一次(基础面试题第一篇,变量加载顺序)。

第一点,static方法、代码块内可以只能出现static域、方法、代码块,最常见的就是main方法,static方法只能出现static变量。

第二点,非static方法只能由对象名调用调用,因为非static方法只有在对象存在时才有意义。

7.2 final关键字

final关键字三个特性:final修饰的变量为常量、final修饰的类不可继承、final修饰的方法不可重写。

第一,final修饰的变量为常量

对于final修饰的变量,应该对基本类型和引用类型分开讨论:

基本类型为栈内存(-128~127情况下),一旦被final关键字修饰,其变量属性变为只读,不再进行写操作,否则编译报错。

引用类型为堆内存,一旦被final关键字修饰,则引用不再改变,但是引用所指向的对象是可以被修改的,Java语言并未提供任何方式使用对象恒定不变。示意代码如下:

FinalData finalData=new FinalData();	
//finalData.value=new Value(33);   //编译报错    value为final类型   
finalData.value.i++; // 编译通过  value所指向的对象可以修改 

final变量的两个初始化时机:final变量定义时初始化、final变量构造函数中初始化(空白final)

第二, final修饰的类不可继承

第三,final修饰的方法不可重写,但是可以被继承,子类可见

ps:方法是否被final修饰与方法的访问权限是两回事,没有任何关系,被final修饰的方法和未被final修饰的方法都可以自由的指定访问权限。

附加:对于final方法 private<final<protect (仅适用于方法)

protect修饰的方法在子类中可见,所有可以被子类继承,亦可以被子类重写;

final修饰的方法可以被子类继承,但不可被子类重写(这里final方法的访问权限为默认的default、protected、public均可,只要保证子类可见即可);

private修饰的方法由于仅本类可见,故不能被子类继承,亦不能被子类重写;

ps:对于方法,所有被private关键字修饰的方法都隐式的被final关键字修饰,可以对private方法添加final关键字,但是这种做法没有任何意义。

7.3 extends和implements关键字

类继承类(单继承)

类实现接口(多实现)

接口继承接口(多继承)

7.4 this和super关键字

this表示当前类所指对象,super表示父类对象的引用

this关键字
this 当前类所指对象
this.字段名表示当前类字段,此处this可以省略
this.方法名() 调用当前类方法,此处this可以省略
super关键字
super() 调用父类无参构造函数,仅在子类构造函数中出现,可以省略,父类无参构造函数可以隐式调用
super(参数) 调用父类指定参数构造函数,仅在子类构造函数中出现,注意不可省略,父类带参构造函数无法隐式调用
super.字段名 子类中访问父类字段,用super.避免与子类同名字段混淆
super.方法名() 子类中调用父类函数,用super.避免与子类相同函数签名的函数混淆

第一,对于构造函数,对于super() 和 super(xxx) 默认调用父类无参构造函数

第二,子类字段和父类字段

public void displayField(){
	System.out.println("父类字段: "+super._description);
	System.out.println("子类字段: "+this._description);
}

第三,子类方法和父类方法

public void displayFunction(){
	System.out.print("父类方法: ");
	super.playing();
	System.out.print("子类方法: ");
	this.playing();//此处this可以省略
}

第四,this与super同时出现

1、super和this可以同时出现,即使是在子类构造方法中也可以同时出现,但是不同同时调用构造方法;

2、理论解释:因为在一个构造方法中,只能访问一次其它的构造方法(不管是父类的还是子类的)所以此时不能同时用super和this关键字来调用构造方法,只能根据需求选其一;

3、简单理解:调用构造函数时,两个都要放第一,自相矛盾。

八、尾声

一文解析Java常用关键字,完成了。

天天打码,天天进步!!!