【Java基础】详解三大修饰符:abstract、static、final

思维导图

在这里插入图片描述

一、abstract

1.1 抽象类

举例

package com.robot.month1.week2.day20200728;

/**
 * 动物抽象类。
 *
 * @author 张宝旭
 */
public abstract class Animal {
    private String name;
    private int age;

    public Animal() {
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 吃
     */
    public abstract void eat();

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

特点

  • 抽象类不能被实例化
  • 抽象类中可以包含抽象方法,也可包含方法体
  • 包含抽象方法的类,一定是抽象类
  • 子类必须实现抽象类中的所有抽象方法,除非子类也是抽象类

1.2 抽象方法

特点

  • 没有方法体
  • 包含抽象方法的类,一定是抽象类
  • 抽象方法必须被子类重写,除非子类也是抽象类

1.3 小练习

有一个交通工具类TracficTool,属性: brand, 方法: run()
有三个子类Bicycle、 Car、SubWay
主人类:属性:name,方法:goHome(交通工具)
使用抽象类抽象方法优化

/**
 * 交通工具抽象类。
 * 
 * @author 张宝旭
 */
public abstract class TracficTool {
    private String brand;

    public TracficTool() {
    }

    public TracficTool(String brand) {
        this.brand = brand;
    }

    public abstract void run();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}
/**
 * 自行车。
 * 
 * @author 张宝旭
 */
public class Bicycle extends TracficTool{
    public Bicycle() {
    }

    public Bicycle(String brand) {
        super(brand);
    }

    @Override
    public void run() {
        System.out.println(super.getBrand() + " run");
    }
}
/**
 * 小汽车。
 * 
 * @author 张宝旭
 */
public class Car extends TracficTool{
    public Car() {
    }

    public Car(String brand) {
        super(brand);
    }

    @Override
    public void run() {
        System.out.println(super.getBrand() + " run");
    }
}
/**
 * 地铁。
 * 
 * @author 张宝旭
 */
public class SubWay extends TracficTool{
    public SubWay() {
    }

    public SubWay(String brand) {
        super(brand);
    }

    @Override
    public void run() {
        System.out.println(super.getBrand() + " run");
    }
}
/**
 * 主人。
 * 
 * @author 张宝旭
 */
public class Master {
    private String name;

    public Master() {
    }

    public Master(String name) {
        this.name = name;
    }
    public void goHome(TracficTool tracficTool) {
        System.out.println(this.name + " 坐着 " + tracficTool.getBrand() + " 回家了");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * 测试。
 * 
 * @author 张宝旭
 */
public class Test {
    public static void main(String[] args) {
        Master master = new Master("小张");
        TracficTool bicycle = new Bicycle("自行车");
        TracficTool car = new Car("小汽车");
        TracficTool subway = new SubWay("地铁");
        master.goHome(car);
    }
}
// 结果示例
小张 坐着 小汽车 回家了

二、static

static用法

  • 静态属性
  • 静态方法
  • 静态代码块
  • 静态内部类
  • 静态导入

2.1 实例属性

每个对象各自持有的独立空间,不影响

Student s1 = new Student();
s1.count;

Student s2 = new Student();
s2.count;

2.2 静态属性

整个类共同持有的共享空间

static int count;

静态属性应该使用 类名.属性 来访问

Student.count;

静态成员存在方法区中

JDK7之前在永久代

JDK8之后在元空间


2.3 静态方法

特点

  • 静态方法中可以访问静态方法或静态属性
public static void countStudents() {
    Student.count = 125;
}
  • 静态方法中不可以访问静态方法或静态属性
public static void run() {
    name = "zbx"; // 错误,不可以方法静态属性
}
  • 非静态方法可以访问静态方法或静态属性
public void sort() {
    Student.count = 125;
}
  • 静态方法中不允许使用this或super关键字
  • 静态方法可以继承,不能重写、没有多态。
  • 静态成员可以直接通过类名访问
  • 在类加载时执行,只执行一次

测试

/**
 * 学生类。
 * 测试static
 *
 * @author 张宝旭
 */
public class Student {
    static int studentCount;
    String name;

    public static void count() {
        System.out.println("Student " + Student.studentCount);
    }
    public void run() {
        System.out.println(this.name + " run");
    }
}
/**
 * 测试学生类。
 *
 * @author 张宝旭
 */
public class StudentTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.name = "小张"; // 调用非静态属性
        student.run(); // 调用非静态方法
        Student.studentCount += 125; // 调用静态属性
        Student.count(); // 调用静态方法
    }
}

2.4 代码块

2.4.1 局部代码块

放在局部代码块中的内容,可以缩小使用范围,提前释放内存空间

public static void main(String[] args) {
    int num = 12;
    {
        int age = 25;
    }
}

测试

不使用局部代码块

public class Temp {
    public static void main(String[] args) {
        int num1 = 12;
        int num2 = 25;
        int num3 = 99;
    }
}

使用javap -v Temp 查看
在这里插入图片描述

使用局部代码块

/**
 * @author 张宝旭
 */
public class Temp {
    public static void main(String[] args) {
        int num1 = 12;
        {
            int num2 = 25;
            System.out.println(num2);
        }
        int num3 = 99;
    }
}

使用javap -v Temp 查看
在这里插入图片描述

可以看到,num2和num3使用的是同一个内存空间

因为num2在局部代码块中,使用完之后就会提前释放空间,所以为sum3分配空间的时候又分配了同样的内存空间


2.4.2 动态代码块

创建对象时执行,静态属性初始化之后执行

作用:可以为静态属性赋值,初始化作用

/**
 * @author 张宝旭
 */
public class DyTest {
    static int count;
    {
        count = 125;
    }

    public static void main(String[] args) {
        
    }
}

反编译查看代码

public class DyTest
{

	static int count;

	public DyTest()
	{
		count = 125;
	}

	public static void main(String args1[])
	{
	}
}

可以看到并没有动态代码块,而是将动态代码块中的内容放到了构造方法中(先执行动态代码块,后执行构造方法)


2.4.3 静态代码块

/**
 * @author 张宝旭
 */
public class StaticTest {
    static int count;
    // 静态代码块在类加载时只执行一次
    static {
        count = 125;
    }

    public static void main(String[] args) {
        System.out.println(StaticTest.count);
    }
}

面试题

在这里插入图片描述

  1. 先在内存中初始化开辟空间,demo=null count1=0 count2=0
  2. 然后执行 private static Demo demo = new Demo(); 创建对象的过程中调用了构造方法,所以count1=1,count2=1
  3. 然后执行 public static int count1; 没有赋值,所以count1还是1
  4. 然后执行 public static int count2=0; 赋值为0,所以count2变为0
  5. 最后执行 Demo.show(); 方法打印出结果,执行结果为count1:1 count2:0

2.5 对象创建过程

父类静态属性

父类静态代码块

子类静态属性

子类静态代码块

父类实例属性

父类动态代码块

父类构造方法

子类实例属性

子类动态代码块

子类构造方法


三、final

概念:最终的,不可更改的

final可修饰的内容:类、方法、变量

final修饰的类,不能被继承

final修饰的方法,不能被覆盖(但是可以被继承)

final修饰的变量,不能被更改(常量)


  • 实例常量 final String name; :显示初始化,可在动态代码块、构造方法中赋值
  • 静态常量 static final String name; :显示初始化,可在静态代码块中赋值
static final int sum;

static {
    sum = 12;
}
  • 对象常量 final int[] array = new int[12]; :引用类型, 地址不可变

abstract 不能和 final 同时使用:因为 abstract 必须重写,而 final 不能重写

abstract 不能和 static 同时使用:因为 static 修饰的是静态方法,可以直接被类调用,而 abstract 修饰的是抽象方法,没有方法体

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值