三大修饰符(abstract、final、static)

三个修饰符

一、abstract

abstract:抽象的

例如生活中有很多动物,狗、猫、猪等等,但是这些都统称为动物,动物并不是一个实实在在的实例,所以这里的动物这个词是我们抽象出来的一个名字,而狗、猫等这些动物属于这个拥有动物特征所建立出的一个具体实例。

1.1 修饰类

有的类是抽象出来的概念,只能作为父类存在,而不应该直接创建对象,此时我们可以在类上加入abstract关键词,设置为抽象类,不能直接创建对象,只能作为父类,让其子类继承。

//abstract修饰的类无法创建对象
public abstract class class_Abstract {
    
}

1.2 修饰方法

abstract修饰的方法为抽象方法,抽象方法没有方法体,由子类去定义抽象方法的内容,一般我们将子类重写父类的一个方法定义为抽象方法。

例如:之前我们创建的Animal、Dog、Cat类,我们可以将Animal定义为抽象类,将他的eat方法可以定义为抽象方法,因为子类都会去重写这个类。

public abstract class class_Abstract {
    abstract void method_Abstract();
}

注意:

  • 一个抽象类可以没有抽象方法;

  • 一个抽象方法必须在抽象类中;

  • 抽象方法不能用private,否则无意义,因为抽象方法就是为了继承给子类重写;

  • 当子类继承一个有抽象方法的抽象类时,会报错,解决方案如下:

    • 将子类也设置为抽象类

    • 重写父类中所有的抽象方法

二、final

final:最终的、最后的、终结的

2.1 修饰类

当修饰类时表示该类不可被继承,因此注意final和abstract无法一起使用,abstract就是为了给子类继承编写,但是final无法继承。

public final class class_Abstract {
    
}

2.2 修饰方法

当修饰方法时表示该方法不可被重写。

public final void method_Abstract(){
    
}

2.3 修饰变量

表示该变量一旦赋值就不可改变,称为常量。

2.3.1 修饰属性

当修饰属性后,该属性必须要在创建对象后,必须有值。赋值时机:

  • 可在属性定义上赋予初始值

    public final class class_Abstract {
        public final String s1 = "aaaa";
    }
  • 可在类的构造方法中赋值

    public final class class_Abstract {
        final String s1;
        public class_Abstract(){
            s1 = "aaaa";
        }
    }

  • 可在代码块中赋值

    public final class class_Abstract {
        final String s1;
        {
            s1 = "aaa";
        }
    }

    注意:一旦代码块中赋值后,就不能在构造方法中再次赋值,因为常量不能再次赋值,代码块比构造方法先运行。

2.3.2 修饰局部变量

当修饰局部变量时,局部变量需要先声明后赋值或者声明时赋值。

2.3.3 修饰方法参数

当修饰方法参数时,表示传入的参数无法更改

2.3.4 常量

在类中我们一般会定义变量,声明final修饰,视作常量;

项目中我们将经常出现的一个常数或者字符串,不希望在过程中改变的,我们可以定义为常量。

  • 常量定义时单词全大写,多个单词间用下划线隔开。

在java中有一些提供的常量,例如Math.PI

import static java.lang.Math;
​
public final class class_Abstract {
    public void aa(){
        System.out.println(Math.PI);
    }
}

三、static

static:静态的

3.1 修饰属性

表示该属性为静态属性,也称为类属性

同一个类中共享一个类属性空间(所有对象使用的同一个类属性),也可以用对象操作,但是不推荐。

注意:不能修饰局部变量,不需创建对象就可使用类属性,创建对象也可使用类属性。

public class Demo {
    public static void main(String[] args) {
        //类属性可以用对象调用也可以用类调用
        System.out.println(A.name);
        A a = new A();
        System.out.println(a.name);
        
        //因为类属性共享一个内存空间,所以使用对象修改类属性值,所有调用类属性都会改变
        a.name = "修改后的类属性";
        System.out.println(a.name);
        System.out.println(A.name);
    }
}

public class A {
    static String name = "我是类属性";
}

3.2 修饰方法

表示为静态方法,也称类方法。

可以直接使用类名调用,也可创建对象调用。

注意:

  • 静态方法不需创建对象就可使用;非静态方法需要创建对象调用

  • 静态方法可以调用静态的方法和属性,不能调用非静态的方法和属性

  • 非静态方法可以调用静态方法和属性,也可调用非静态的方法和属性;

  • 静态方法不能使用this和super修饰,因为静态方法不用创建对象,this和super需要创建对象使用

  • 静态方法可以被继承,但是不能重写,所以也无法多态。

public class A {
    static String name = "我是类属性";
    String name1 = "我不是类属性";

    static void S1(){
        System.out.println(name);
//        System.out.println(name1);//会报错,因为name1不是静态属性
    }

    //非静态方法可以使用所有属性
    public void S2(){
        System.out.println(name);
        System.out.println(name1);
    }
}

3.3 修饰代码块

3.3.1 动态代码块

类中由一对大括号组成的代码块称为动态代码块,创建对象时执行,可执行多次,每次创建对象都会执行。

执行流程:

  • 初始化属性

  • 执行动态代码块

  • 执行构造方法

public class Demo {
    public static void main(String[] args) {
        new A();
    }
}

public class A {
    String name = "我是属性";

    {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(name);
        System.out.println("我是动态代码块");
    }

    public A(){
        System.out.println("我是构造方法");
    }
    //我是属性
	//我是动态代码块
	//我是构造方法

}

3.3.2 静态代码块

static关键字修饰的代码块为静态代码块,类加载时执行,只执行一次。

在创建对象时会加载类

类加载:将类信息加载到方法区,以便得到对象创建时所需得空间大小,方便创建对象。

执行流程:

  • 静态属性

  • 静态代码块

  • 实例属性

  • 执行动态代码块

  • 执行构造方法

public class Demo {
    public static void main(String[] args) {
        new A();
        //我是静态属性
        //我是静态代码块
        //我是实例属性
        //我是动态代码块
        //我是构造方法
    }
}

public class A {
    String name = "我是实例属性";
    static String name1 = "我是静态属性";

    {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(name);
        System.out.println("我是动态代码块");
    }

    {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(name1);
        System.out.println("我是静态代码块");
    }

    public A(){
        System.out.println("我是构造方法");
    }

}

3.4 继承时的加载顺序

面试题:当A继承了B类,那么创建A对象,他们之中的加载顺序是什么样的??

加载流程:

  • 父类静态属性

  • 父类静态代码块

  • 子类静态属性

  • 子类静态代码块

  • 父类实例属性

  • 父类动态代码块

  • 父类构造方法

  • 子类实例属性

  • 子类动态代码块

  • 子类构造方法

由上执行流程可知,为什么类方法无法调用非静态属性。

public class Demo {
    public static void main(String[] args) {
        new A();
        //我是父类静态属性
        //我是父类静态代码块
        //我是子类静态属性
        //我是子类静态代码块
        //我是父类实例属性
        //我是父类动态代码块
        //我是父类构造方法
        //我是子类实例属性
        //我是子类动态代码块
        //我是子类构造方法
    }
}

public class A extends B{
    String name = "我是子类实例属性";
    static String name1 = "我是子类静态属性";

    {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(name);
        System.out.println("我是子类动态代码块");
    }

    static {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(name1);
        System.out.println("我是子类静态代码块");
    }

    public A(){
        System.out.println("我是子类构造方法");
    }

}

public class B {
    String n1 = "我是父类实例属性";
    static String n2 = "我是父类静态属性";

    {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(n1);
        System.out.println("我是父类动态代码块");
    }

    static {
        //将name放到此处,可以看出执行动态代码块前是否先初始化属性,否则会报错
        System.out.println(n2);
        System.out.println("我是父类静态代码块");
    }

    public B(){
        System.out.println("我是父类构造方法");
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值