【25节JavaSE知识点·11】面向对象三大修饰符 abstract static final

面向对象三大修饰符

【注1】:回答修饰符关键字的用法时:

  1. 修饰哪些元素?2.分别有什么含义?

【注2】:和访问修饰符 (private 缺省 protected public) 在使用时,无先后顺序

abstract 抽象

1)修饰类(抽象类)

  1. 被abstract修饰的类为抽象类
  2. 抽象类不允许创建对象!绝育了!但可以声明引用!所以可以强制用多态!
public class TestMyClass {
    public static void main(String[] args) {
        //声明引用
        MyClass m = null;
        MyClass s = new MySub();    //多态的使用
        s.eat();
        System.out.println(s.m);
    }
}
abstract class MyClass{
    int m = 5;  //抽象类中可以有属性
    public void eat(){  //抽象类中可以有成员方法
        System.out.println("吃");
    }
}
class MySub extends MyClass{
}
  1. 语法: 访问修饰符 abstract class 类名{ }
  2. 好处:强制使用多态
  3. 抽象类的使用场景:

通常将一些抽象出的父类定义为抽象类:具有某一类事物的特性和行为,(行为定义成抽象方法一定需要重写),但不具有具体的执行功能的类。

【注意事项】

  • 在抽象类中,可以定义属性和成员方法。
  • 在抽象类中,可以定义构造方法,但是构造方法不是给自己的对象使用的,而是子类对象创建对象时使用。
  • 抽象类中也既可以有抽象方法,也可以没有抽象方法。
  • 如果一个类,继承抽象类,则该类必须覆盖父类中全部抽象方法,除非该子类还是抽象类。

2)修饰方法(抽象方法)

  1. 被abstract修饰的方法为抽象方法,只有声明,没有方法的实现。
  2. 语法:访问修饰符 abstract 返回值类型 方法名(实参列表);
  3. 【注意事项】
  • 抽象方法必须定义在抽象类中。
  • 抽象类中不一定要有抽象方法,抽象类中,既可以有抽象方法,可以只有普通方法。

static 静态

可以修饰 成员变量、成员方法、初始代码块

成员变量可以分为两类:

  • 静态成员变量——有static修饰,属于类,内存中仅加载一次
  • 普通成员变量——无static修饰,属于对象

成员方法可以分成两类:

  • 静态成员方法(有static修饰,归属于类),建议用类名访问,也可以用对象访问。
  • 实例成员方法(无static修饰,归属于对象),只能用对象触发访问。

修饰成员变量

static修饰的成员变量为静态成员变量,属于类,被该类的所有对象共享。

语法:访问修饰符 static 数据类型 变量名;

访问修饰符 static 数据类型 变量名 = 值;

使用:类名.属性名 //推荐使用

​ 对象名.属性名

修饰方法

被static修饰的方法称为静态方法,属于类,被该类的所有对象共享。

语法:访问修饰符 static 返回值类型 方法名(形参列表){ 方法体 }

使用:类名.方法名(实参)

​ 对象名.方法名(实参)

注意:

  1. 静态方法中可以直接使用静态属性静态方法
  2. 静态方法中不允许直接使用非静态属性非静态方法
  3. 非静态方法中 可以使用 静态属性和静态方法;
  4. 静态方法中 不允许使用this和super关键字;
  5. 静态方法可以被继承,但没有多态(子类中定义和父类相同的方法,当通过父类的引用 调用时,执行的是 父类中的静态方法)
静态成员方法的适用场景
  • 表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法。
  • 如果该方法是以执行一个共用功能为目的,则可以声明成静态方法。

static应用知识——工具类

1、工具类是什么?

类中都是一些静态方法,每个方法都是以完成一个公用的功能为目的,这个类是用来给系统开发人员共同使用的。

2、使用工具类的好处
  1. 调用方便
  2. 提高了代码的复用性,一次编写处处可用。
/**
 * 工具类
 */
public class Util {
    /**
     * 静态方法
     */
    public static String creatVerifyCode(int n){
        //1.定义一个变量定义验证码
        String code = "";
        //2.定义一个变量记住全部验证码字符
        String data = "zbcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ";
        //3.定义一个循环生成几个随机索引,去得到几个字符
        Random r = new Random();
        for (int i = 0; i < 5; i++) {
            //获取随即索引对应的字符,链接给code
            int index = r.nextInt(data.length());
            code += data.charAt(index);
        }
        return code;
    }
    /**
     * 由于工具类无需创建对象,所以将构造器私有化会显得很专业。
     */
    private Util(){
    }
}

public class Check {
    //审核
    public static void main(String[] args) {
        System.out.println(Util.creatVerifyCode(5));
    }
}

3、为什么工具类中的方法不用实例方法做?
  1. 实例方法需要创建对象调用。
  2. 此时用对象只是为了调用方法,这样会浪费内存
4、工具类定义时的其他要求:
  • 由于工具类里面都是静态方法,直接用类名即可访问,因此,工具类无需创建对象。建议将工具类的构造器私有化。

代码块

代码块概述

  • 代码块是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)
  • 在Java类中,使用{}括起来的代码成为代码块。

静态代码块

  • 被static修饰的初始代码块。
  • 格式static{ }
  • 特点:需要通过static关键字修饰,随着类加载而加载,并且自动触发,只执行一次。
  • 适用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
public class StaticDemo1 {
    public static String schoolName;
    /**
     * 静态代码块
     * 作用:可以用于初始化静态资源
     */
    static{
        System.out.println("静态代码块被触发啦");
        schoolName = "小禾苗幼儿园";
    }
    public static void main(String[] args) {
        //目标:理解静态代码块
        System.out.println("main方法执行");
        System.out.println(schoolName);
    }
}
-------------------------------------------------------------------
静态代码块被触发啦
main方法执行
小禾苗幼儿园

构造代码块

  • 定义在类以内,方法以外的代码块(用{ }括起来的一段代码)
  • 格式{}
  • 特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行之前执行。
  • 适用场景:初始化实例资源。
public class StaticDemo2 {
    public StaticDemo2(){
        System.out.println("无参构造器被执行");
    }
    /**
     * 实例代码块
     */
    {
        System.out.println("实例代码块被调用");
    }
    public static void main(String[] args) {
        //目标:理解实例代码块
        StaticDemo2 s1 = new StaticDemo2();
    }
}
--------------------------------------------------------------------
实例代码块被调用
无参构造器被执行

静态代码块案例

public class StaticTest3 {
    /**
     * 1.定义一个静态集合,这样这个集合只加载一次,因为当前只需要一副牌
     */
    public static ArrayList<String> cards = new ArrayList<>();

    /**
     * 2.在程序真正运行main方法前。把54张牌放进去,后续游戏直接使用
     */
    static{
        //3.正式做牌,放到集合中去即可
        //a.定义一个数组存储全部点数,类型确定、个数确定,用数组比较好
        String[] sizes = {"3", "4", "5", "6", "7", "8", "9","J","Q","K","A"};
        //b.定义一个数组存储花色
        String[] colors = {"♥" , "♠", "♦", "♣"};
        //c.遍历点数
        for (int i = 0; i < sizes.length; i++) {
            //d.遍历花色
            for (int i1 = 0; i1 < colors.length; i1++) {
                String card = sizes[i] + colors[i1];
                cards.add(card);
            }
        }
        //e.单独加入大小王
        cards.add("小🃏");
        cards.add("大🃏");
    }
    public static void main(String[] args) {
        //目标:模拟游戏启动前初始化54张牌
        System.out.println("新牌" + cards);
    }
}
---------------------------------------------------------------------
新牌[3♥, 3♠, 3♦, 3♣, 4♥, 4♠, 4♦, 4♣, 5♥, 5♠, 5♦, 5♣, 6♥, 6♠, 6♦, 6♣, 7♥, 7♠, 7♦, 7♣, 8♥, 8♠, 8♦, 8♣, 9♥, 9♠, 9♦, 9♣, J♥, J♠, J♦, J♣, Q♥, Q♠, Q♦, Q♣, K♥, K♠, K♦, K♣, A♥, A♠, A♦, A♣, 小🃏, 大🃏]

类加载

类加载:【面试重点】

当JVM第一次使用某个类时进行类加载**,通过classpath环境变量找到对应的.class文件,从.class文件中读取该类的相关信息(包名/类名/父类/构造方法/属性/成员方法等等)并保存到JVM内存中,这个过程称类加载(类加载只进行1次)。(将静态常量池内数据存放入方法区的运行时常量池

类加载的时机:【面试重点】

1> 第1次创建一个类的对象,先类加载,后创建对象

2> 第1次使用一个类的静态属性或静态方法时,会先类加载

3> 子类类加载时,会先进行父类的类加载

  1. 第1次创建子类的对象时
  2. 第1次使用子类的静态属性或静态方法时

对象创建的过程

**1> 类加载:**给静态属性分配空间,赋初值,执行静态代码块

  1. 先父类 类加载(如果有)

父类静态属性->父类的静态代码块

  1. 后子类 类加载

子类静态属性->子类的静态代码块

2> 创建对象

  1. 分配内存空间(根据成员变量分配),属性赋默认值
  2. 递归的创建父类对象:给父类属性赋初值->调父类构造方法
  3. 给本类属性赋初值
  4. 调本类构造方法

【小知识】

Scanner sc = new Scanner(System.in);
//System.in 此处in为System类的静态属性

final( 最终的、最后的)

1、final可以修饰变量(局部变量、实例变量、静态变量)

(1)final修饰的局部变量,只允许一次赋值,一旦赋值不允许修改,可以多次使用。

public static void main(String[] args) {
        final int a = 7;  //局部变量
        //a = 9;    java: 无法为最终变量a分配值
        System.out.println("a + 9" + "=" + (a + 9));    //a + 9=16
    }

(2)final修饰的实例变量,jvm不再分配默认值,初始化时机:

a.在声明的同时完成初始化。

b.利用构造方法完成初始化

【报错:java: 变量 m 未在默认构造器中初始化】

final修饰的变量,只能赋值一次,如果Java给赋值默认值,开发者无法赋值

public class TestFinal {
    public static void main(String[] args) {
        MyClas mc = new MyClas();
        System.out.println(mc.m);  //报错!!!!!
    }
}
class MyClas{
    final int m;    
}

可以在构造方法中为final修饰的成员变量赋值

public class TestFinal {
    public static void main(String[] args) {
        MyClas mc = new MyClas(9);
        System.out.println(mc.m);
    }
}
class MyClas{
    final int m;    //实例变量

    public MyClas(int m) {
        this.m = m;
    }
}

(3)final修饰的静态变量,不再分配默认值,初始化时机:

a.在声明的同时,完成初始化

b.在静态代码块中,完成初始化

final static int m = 9;
class MyClas{
    final static int n;
    //静态代码块:类加载时执行。
    static{
        n = 10;
    }
}

(4)被final修饰的引用,代表引用中存储的地址不可以改变,但对象本人可以改变。

public class TestFinal {
    public static void main(String[] args) {
        final MyClas mc;  //局部变量
        mc = new MyClas();  //引用存储的是对象的首地址
        mc.m = 10;
        System.out.println(mc.m);   //10
        // mc.n = 100 报错 不允许被修改
    }
}
class MyClas{
    int m = 3;  //实例变量,数据可以被改变
    final int n = 8;    //实例变量,数据不允许改变
}

2、final修饰方法:被final修饰的方法能被子类继承,但是不允许覆盖

class MyClas{
    int m = 3;  //实例变量,数据可以被改变
    final int n = 8;    //实例变量,数据不允许改变
    public final void m1(){
        System.out.println("m1时final修饰的,可以继承到,不能被覆盖");
    }
}
class Sub extends MyClas{
//    public void m1(){ 报错
//    java: Sub中的m1()无法覆盖MyClas中的m1()
//    }
}

3、final修饰类,被final修饰的类不能被继承,没有子类。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值