Java面向对象_06_关键字补充


Java基本的语法结构已经介绍完毕,本文介绍一些常用的关键字,用于修饰权限以及调用。

1. final关键字

  1. final是一个关键字,表示最终的,不可变的。

  2. final修饰的类无法被继承。

  3. final修饰的方法无法被重写/覆盖。【可以重载】

  4. final修饰的变量,一旦赋值之后,不可重新赋值。

  5. final修饰的实例变量

    如果是实例变量,那么必须手动赋值。因为如果不赋值的话,系统会自动赋值,而final修饰的不可二次赋值,所以不手动赋值的话,以后就没机会修改了,这样做无意义,所以会编译报错,即Java规定对于final修饰的实例变量,必须手动初始化,不会自动初始化。

    final修饰的实例变量是不可变的,这种变量一般和static联合使用,被称为“常量”。之前的例子中,因为一个类中的所有对象的某个属性都是一样的,所以设置为静态变量。即将变量上升为类级别的。但是为了防止被修改,可以在此基础上,用final修饰。

    常量一般是公开的,所以前面加一个public。常量名满足Java语法规范:名字全部大写,单词之间用下划线分开。

    常量的定义语法格式:

    1
    2
    3
    4
    public static final 类型 常量名 = 值;

    // 例如
    public static final double PI = 3.1415926;
  6. final修饰的引用

    final修饰的引用,一旦指向某个对象之后,不能再指向其他对象,那么被指向的对象无法被垃圾回收器回收。直到当前方法结束,才会释放空间。(和普通的变量一样,不能重新赋值)。但是可以通过引用,修改对象里面的属性值,即内存的内容是可以修改的。

  7. final控制不了能不能调用的问题,final修饰的表示最后的,不能改变的。

  8. 常量:前面提到过,如果一个类中的所有对象实例的某个属性值都是一样的,那么可以将其声明为静态static,此时,如果这个静态变量如果是永远不变的,那么就可以将其声明为final,所以final和static一起修饰,这个变量就是常量了。

    其实,常量和静态变量是一样的,都是存储的方法区,都是在类加载时初始化。区别就是常量的值不能变,而静态变量则可以改变。

    常量一般都是公开的,因为公开了你也改不了它。

2. super关键字

super关键字主要用来调用父类的一些属性和方法,this关键字指的是当前类/对象,而super则指的是父类。

super主要用在实例方法和构造方法中,不能用在静态方法中,其语法有super.super()两种,其中super.大部分情况下是可以省略的。

super()只能出现在构造方法第一行,即在当前的构造方法中去调用“父类”中的构造方法,目的是代码复用(创建子类对象的时候,先初始化父类型特征):

  1. super(实参)的作用是:初始化当前对象的父类型特征,并不是创建新对象。
  2. super关键字代表的就是“当前对象”的那部分父类型特征。就是说,虽然是继承了父类的,但是实际上自身已经拥有了,可以用super来初始化。
  3. 可以认为super指的是当前对象空间中的父类中的那部分空间。通过super.属性/方法来调用继承的父类的特征。见第三段代码。
  4. 当继承的父类属性和自身的属性重名时,也可以用this和super来区分父类的和子类的属性。

当子类继承父类时,那么创建子类对象时,会自动调用父类的无参构造方法(即初始化父类型特征),实际上就是在子类的构造方法中,默认调用了super()方法,那么如果父类的构造方法都是有参的话,就会报错

注意,在调用构造方法的时候,和调用普通的方法一样,都是在栈内存进行压栈弹栈等操作,然后在堆内存中生成对象。所以,在创建对象的时候,因为默认有super()关键字,所以一定会初始化父类型的特征。也就是说,对于子类来说,它内部是包含了父类的一些允许被继承的特征的。注意,尽管是调用了父类的构造方法,但是依然是创建了一个对象,只不过这个对象包含父类的一些特征。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SuperTest01{

public static void main(String[] args){

B b = new B();
}
}

class A{
public A(){
System.out.println("A类的无参数构造方法");
}
}

class B extends A{
public B(){
// 因为第一行既没有this,也没有super,所以默认调用父类构造方法,相当于自动调用super();
// super(); 该句写不写都行。
System.out.println("B类的无参数构造方法");
}
}

当一个构造方法第一行,既没有this(),也没有super()的话,默认会有一个super(); 表示通过当前子类的构造方法调用父类的无参数构造方法。所以必须保证父类的无参数构造方法是存在的。

注意,this()和super()不能共存,它们都是只能出现在构造方法的第一行。

无论怎样,父类的构造方法是一定会执行的,所以无论如何,一个类的无参数构造方法还是要手动写出来,避免写了有参数构造方法,导致无参数构造方法没有了。

另外,子类继承父类,并且父类中的属性是private修饰的,那么初始化父类参数的话,就只能采用super关键字来调用父类的有参构造方法了。因为private修饰的属性只能在本类中直接访问,子类访问不到。

简单案例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class SuperTest04{

public static void main(String[] args){
CreditAccount01 ca01 = new CreditAccount01();
}
}

class Account01{

private String actno;
private double balance;

public Account01(){

}

public Account01(String actno, double balance){
this.actno = actno;
this.balance = balance;
}

public void setActno(String actno){
this.actno = actno;
}

public String getActno(){
return this.actno;
}

public void setBalance(double balance){
this.balance = balance;
}

public double getBalance(){
return this.balance;
}
}

class CreditAccount01 extends Account01{
private double credit;

public CreditAccount01(){

}

public CreditAccount01(String actno, double balance, double credit){
/*
// 父类中的属性是private修饰的,不能直接访问
this.actno = actno;
this.balance = balance;
*/

super(actno, balance);
this.credit = credit;

}

public void setCredit(double credit){
this.credit = credit;
}

public double getCredit(){
return this.credit;
}
}

代码的内存图如下图所示:(其实方法的调用没有在栈内存中显示出来,其实无论是调用哪个方法,包括构造方法,都是在栈内存中执行的),注意:在构造方法执行过程中一连串调用了父类的构造方法,父类的构造方法又继续向下调用它的父类的构造方法,但是实际上对象只创建了一个,即子类对象。

oop_02.png (1397×685) (gitee.io)

3. 简单案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class Person{
private double height;
private double weight;

Person(){
}

Person(double height, double weight){
this.height = height;
this.weight = weight;
}

public void setHeight(double height){
this.height = height;
}

public double getHeight(){
return this.height;
}

public void setWeight(double weight){
this.weight = weight;
}

public double getWeight(){
return this.weight;
}

public String toString(){
return "height:" + this.height + ", weight:" + this.weight;
}

public void eating(){
System.out.println("正在吃饭...");
}
}

class Chineses extends Person{
public static final String NATION = "China";
private String name;

Chineses(){
}

Chineses(String name, double height, double weight){
super(height, weight);
this.name = name;
}

public void setName(String name){
this.name = name;
}

public String getName(){
return this.name;
}

public String toString(){
return "name:" + this.name + ", height:" + this.getHeight() + ", weight:" + this.getWeight();
}

public void sayChinese(){
System.out.println(this.name + "正在说汉语...");
}
}

public class TestOOP_06 {
public static void main(String[] args){
Chineses c1 = new Chineses("张三", 1.78, 67);
c1.eating();

c1.sayChinese();

System.out.println(c1);
}
}

4. 备注

参考B站《动力节点》。


文章作者: 浮云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 浮云 !
  目录