三大修饰符

三个修饰符

一、abstract

abstract,抽象的。

1.1 修饰类

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

public abstract class Animal {
    private String name;
    
    public void eat() {
        System.out.println("动物在吃...");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        // Animal a = new Animal(); // 报错,不能直接创建对象
        Animal a = new Dog(); // 使用子类创建对象
    }
}

1.2 修饰方法

在父类中,可能存在一些方法,必须要在子类中重写,那么可以在该方法前面加上abstract关键字,指定该方法在子类中应该重写。

public abstract class Animal {
    private String name;
    
    // 只需要方法的声明,不需要实现,所以没有大括号,直接使用分号结束
    public abstract void eat();
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗在吃...");
    }
}

注意:

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

  • 有抽象方法的类必然是抽象类

  • 抽象方法不能使用private,没有意义

  • 当子类继承一个有抽象方法的抽象类时,会报错。此时有两种解决方案:

    • 将子类也设置为抽象类

    • 实现(重写)父类中所有的抽象方法

二、final

final,最终的,最后的,终结的,不可更改的。

2.1 修饰类

表示该类不能被继承。

注意:final不能和abstract一起使用。

2.2 修饰方法

表示该方法不能被重写。

2.3 修饰变量

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

2.3.1 修饰属性

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

  • 直接在属性定义时赋值

public class Dog{
    private final String name = "";
}
  • 在代码块中赋值

public class Dog{
    private final String name;
   
   {
       name = "";
   }
}
  • 在构造方法中赋值

public class Dog{
    private final String name;
    
    public Dog() {
        this.name = "";
    }
    
    public Dog(String name) {
        this.name = name;
    }
}

注意:不能再次赋值,所以当在代码块中赋值后,不能在构造方法中赋值,因为代码块在构造方法前执行。

2.3.2 修饰局部变量

public class Dog extends Animal{
    public void m1() {
        // 先声明,后赋值
        final int n; 
        n = 6;
        // n = 5; 会报错,不能重复赋值
        // 声明的同时赋值
        final int m = 3;
    }
}

2.3.3 修饰方法的参数

public class Dog extends Animal{
    public void m2(final int n) {
//      n = 5; 会报错, 表示该值不能修改
    }
}

2.3.4 常量

在类中一般会定义一些变量,声明为final修饰,视作常量。

在项目中,固定使用的一些常数,不希望在使用过程中被改变,会定义成常量。

常量定义的规范:单词全大写,多个单词使用下划线隔开

// Integer类中的整数最大值:
public static final int   MAX_VALUE = 0x7fffffff;
// Math类中的PI的值:
public static final double PI = 3.14159265358979323846;

三、static关键字

3.1 修饰属性

表示该属性为静态属性,也叫类属性。

同一个类共享同一个类型属性空间,也可以使用对象操作。但是不推荐。应该使用类名访问。

创建的对象在堆中,而类属性在方法区。

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

public class Student {
    public String name;
    public int age;
    public static String className;
    
    
    public void introduce() {
//      static int n = 5; // 报错,不能修饰局部变量
        System.out.println(className);
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.name = "张三";
        s1.age = 20;
        s1.className = "0班"; // 可以操作,但是不推荐
        Student.className = "1班"; // 静态属性,类属性
        
        Student s2 = new Student();
        s2.name = "李四";
        s2.age = 18;
        Student.className = "2班";
        System.out.println(s1.name + "," + s1.age + "," + Student.className 
                + "---" + s2.name + "," + s2.age + "," + Student.className);
    }
}

在实例方法中是否可以调用静态属性?

  • 可以,因为静态属性不需要创建对象就可以访问。创建了对象也可以访问。

3.2 修饰方法

表示该方法为静态方法(类方法)。

即直接使用类名调用的方法,不需要创建对象即可调用。

public class Student {
    public String name;
    public int age;
    public static String className;
    public static int count = 0;
    
    public Student() {
        count++;
        System.out.println("对象被创建了"+count+"次");
    }
    
    public void introduce() {
//      static int n = 5; // 报错,不能修饰局部变量
        System.out.println(className);
    }
    
    // 静态方法,类方法
    public static void m1() {
        System.out.println("m1===被调用");
    }
}

注意:

  • 静态方法不需要创建对象即可使用,直接用类名访问。

  • 在静态方法中可以调用其他静态方法,但是不能调用非静态方法(实例方法)。

  • 静态方法中可以调用静态属性,但是不能调用非静态属性(实例属性)。

  • 静态方法中不能使用this和super。

  • 静态方法可以继承,不能重写,没有多态。

3.3 修饰代码块

动态代码块:在类中直接使用一对大括号中的代码。创建对象时执行。

执行顺序:

  • 初始化属性

  • 执行动态代码块

  • 执行构造方法

public class A {
    public String name = "aaa";
    
    {
        System.out.println(name);
        System.out.println("动态代码块");
    }
    
    public A() {
        System.out.println("构造方法");
    }
}
​
public class Demo2 {
    public static void main(String[] args) {
        new A();
    }
}

静态代码块:使用static修饰的代码块叫静态代码块。类加载时执行。而且只执行一次。

创建对象时会先加载类。

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

执行顺序:

  • 静态属性初始化(仅一次)

  • 静态代码块(仅一次)

  • 实例属性

  • 动态代码块

  • 构造方法

public class A {
    public static String sname = "静态属性";
    public String name = "实例属性";
    
    {
        System.out.println(name);
        System.out.println("动态代码块");
    }
    
    public A() {
        System.out.println("构造方法");
    }
    
    static {
        System.out.println(sname);
//      System.out.println(name); // 不能访问实例属性
        System.out.println("静态代码块");
    }
}
​
public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException {
//      new A();
        // 加载类
//      Class.forName("com.qf.day13.A");
        new A(); // 会先加载类
//      new A();
    }
}

3.4 继承时的执行顺序

经典面试题:执行顺序:

父类静态属性(仅一次) 父类静态代码块(仅一次) 子类静态属性(仅一次) 子类静态代码块(仅一次)

父类实例属性 父类动态代码块 父类构造方法 子类实例属性 子类动态代码块 子类构造方法

public class A {
    public static String sname = "父类静态属性";
    public String name = "父类实例属性";
    
    {
        System.out.println(name);
        System.out.println("父类动态代码块");
    }
    
    public A() {
        System.out.println("父类构造方法");
    }
    
    static {
        System.out.println(sname);
        System.out.println("父类静态代码块");
    }
}
​
public class B extends A{
    public static String sname1 = "子类静态属性";
    public String name1 = "子类实例属性";
    
    {
        System.out.println(name1);
        System.out.println("子类动态代码块");
    }
    
    public B() {
        System.out.println("子类构造方法");
    }
    
    static {
        System.out.println(sname1);
        System.out.println("子类静态代码块");
    }
}
​
public class Demo2 {
    public static void main(String[] args){
        new B();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值