面向对象高级(static,final,abstract)

文章详细阐述了Java中静态变量和实例变量的区别,包括它们的内存位置、加载时机、调用方式以及生命周期。同时,介绍了两种单例模式——饿汉式和懒汉式,分析了它们的加载时机和优缺点。此外,还讨论了final和abstract关键字的用途,以及抽象类在继承中的角色和规则。

static

静态变量:类中的属性使用static进行修饰。
对比静态变量与实例变量:

  1. 个数

静态变量:在内存空间中只有一份,被类的多个对象共享。
实例变量:类的每个对象都保存着一份实例变量。

2.内存位置

静态变量:jdk6及之前:存放在方法区。jdk7 之后:存放在堆区
实例变量:存放在堆空间的对象实体中

3.加载时机

静态变量:随着类的加载而加载,由于类只会加载一次,所以静态变量也只有一份
实例变量:随着对象的创建而加载。每个对象拥有一份实例变量。

4调用者

静态变量:可以被类直接调用,也可以使用对象调用。
实例变量:只能被对象进行调用。

5.判断是否可以调用—>从生命周期角度解释】

类 可以调用类变量,不能调用实例变量,因为只有创建了对象后才可以对实例变量进行调用
对象:可以调用类变量,也可以调用实例变量

6.消亡时机

静态变量:随着类的消亡而消亡
实例变量:随着对象的消亡而消亡

单例模式

1.饿汉式

class Bank{

    // 1. 类的构造器私有化
    private Bank(){

    }

    // 2. 在类的内部创建当前类的实例

    private static Bank instance = new Bank();

    // 3. 使用getXXX()方法获取当前类的实例,必须声明为static的
    public static Bank getInstance(){
        return instance;
    }

}

2.懒汉式

class Bank2{

    // 1. 私有化构造器
    private Bank2(){

    }

    // 2. 声明当前类的实例
    private static Bank2 instance = null;

    // 3. 通过getXXX()方法获取当前类的实例,如果未创建对象,则在方法内部进行创建
    public static Bank2 getInstance(){

        if (instance == null){
            instance = new Bank2();
        }
        return instance;
    }

}

对比两种模式:

饿汉式:立即加载,随着类的加载,当前的唯一实例就创建了
懒汉式:延迟加载,在需要使用的时候,进行加载。

优缺点:

饿汉式:写法简单,由于内存中较早加载,使用更方便,更快,并且是线程安全的,缺点内存中占用时间较长。
懒汉式:缺点,线程不安全,优点,节省空间

代码块

1.静态代码块:

随着类的加载而执行
由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次>作用:用来初始化类的信息
内部可以声明变量、调用属性或方法、编写输出语句等操作。>静态代码块的执行要先于非静态代码块的执行
如果声明有多个静态代码块,则按照声明的先后顺序执行
静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静态的结构(即非静态的属性、方法)

2.非静态代码块:

随着对象的创建而执行
每创建当前类的一个实例,就会执行一次非静态代码块>作用:用来初始化对象的信息
内部可以声明变量、调用属性或方法、编写输出语句等操作。>如果声明有多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内部可以调用静态的结构〈即静态的属性、方法),也可以调用非静态的结构(即非静态的属性、方法)

可以给类的非静态的属性(实例变量)赋值的位置有:

  1. 默认初始化
  2. 显示初始化 或 代码块初始化
  3. 构造器初始化
  4. 有了对象以后,通过"对象.属性","对象.方法"的方法进行赋值
    执行的先后顺序:
    1 - 2 - 3 4

final

3.1 final修饰类:表示此类不能被继承。
比如:String、StringBuffer、StringBuilder类
3.2 final修饰方法:表示此方法不能被重写
比如: 0bject类中的getclass()
3.3 final修饰变量:既可以修饰成员变量,也可以修饰局部变量。
此时的"变量"其实就变成了"常量",意味着一旦赋值,就不可更改。
3.3.1 final修饰成员变量:有哪些位置可以给成员变量赋值?

显式赋值
代码块中赋值
构造器中赋值

abstract

为什么要使用抽象类呢?
当某一个父类需要一个方法,但此方法在父类中不能具体的实现,只能通过子类的继承对方法进行重写,此时就需要将父类转为抽象类

abstract class Geometric0bject{//几何图形
求面积  (只能考虑提供方法的声明,而没有办法提供方法体。
所以,此方法适合声明为抽象方法
求周长  (只能考虑提供方法的声明,而没有办法提供方法体。
所以,此方法适合声明为抽象方法)
}

class Circle extends Geometric0bject{
求面积(必须重写(或实现)父类中的抽象方法)
求周长(必须重写(或实现)父类中的抽象方法)
}
public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal {
    public void eat (){
      	System.out.println("小猫吃鱼和猫粮"); 
    }
}
public class CatTest {
 	 public static void main(String[] args) {
        // 创建子类对象
        Cat c = new Cat(); 
       
        // 调用eat方法
        c.eat();
  	}
}

•抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
•抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
•抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。
理解:子类的构造方法中,有默认的super()或手动的super(实参列表),需要访问父类构造方法。
•抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
•理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

接口与抽象类的对比

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值