Java--三个修饰符(abstract、static、final)

1.第一个修饰符:abstract(抽象)

   拿动物类来说,现实生活中的动物都是具体的,比如说:猫、狗、狮子、老虎等 这些都是‘动物类’的子类,并没有“动物”这个对象,它在现实生活中不存在,所以不应该被new() 实例化成对象,这个时候呢,需要把这个动物类定义成抽象类,来限制这种对象的创建(public abstract class Animal{})。

  抽象类:被abstract 修饰的类,称为抽象类。抽象类意为不够完整的类、不够具体的类,抽象类对象无法独立存在,即不能new对象

  作用:1:可被子类继承,提供共性属性和方法  2:可声明为引用,更自然的使用多态。

  经验:抽象父类,可作为子类的组成部分,依附于子类对象存在,由父类共性+子类独有组成完整的子类对象。

  抽象方法:被abstract修饰的方法,称为抽象方法。只有方法声明,没有方法实现({}的部分)。意为不完整的方法,必须包含在抽象类中

  总结:抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类。

           子类继承抽象类后,必须重写父类中所有的抽象方法,否则子类还是抽象类。

  示例:

  

-------------------------------------------------------------------------
package com.monv.abs;
/**
 * 交通工具类
 * @author lenovo
 *
 */

public abstract class Vehicle {
    
    private String Brand;
    
    public Vehicle() {

    }
    public Vehicle(String brand) {
        super();
        this.Brand = brand;
    }
    
    public String getBrand() {
        return Brand;
    }

    public void setBrand(String brand) {
        this.Brand = brand;
    }
    //前进的方法  这个方法在子类中有被重写 所以这里的代码部分就没有用了 可以优化成抽象方法
    public abstract void run();
    
}
-----------------------------------------------
package com.monv.abs;

public class Car extends Vehicle{
    
    public Car() {
        // TODO Auto-generated constructor stub
    }
        
    public Car(String brand) {
        super(brand);
    }

    //重写父类中的构造方法
    @Override
    public void run() {
        System.out.println(super.getBrand()+"牌的汽车正在前进。。。");
    }
}
-----------------------------------
package com.monv.abs;

public class Bike extends Vehicle{
    
    public Bike() {
        
    }
    
    public Bike(String brand) {
        super(brand);
    }

    //重写父类中的方法
    @Override
    public void run() {
        System.out.println(super.getBrand()+"牌的自行车正在前进。。。");
    }
}
------------------------
package com.monv.abs;
/**
 * 主人类
 * @author lenovo
 *
 */
public class Master {
    private String name;
    
    public Master() {
        // TODO Auto-generated constructor stub
    }
    
    public Master(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    //回家的方法
    public void goHome(Vehicle vehicle) {
        System.out.println(this.name+"下班回家了");
        vehicle.run();
    }
}
-----------------测试------------------------
package com.monv.abs;

public class TestMaster {
    public static void main(String[] args) {
        Master xiaoming = new Master("小明");
        Vehicle car = new Car("宝马");
        Vehicle bike = new Bike("永久");
        
        xiaoming.goHome(car);
        xiaoming.goHome(bike);
    }
}
--------------------------------------------------------------------
结果:
小明下班回家了
宝马牌的汽车正在前进。。。
小明下班回家了
永久牌的自行车正在前进。。。
--------------------------------------------------------------------

 2.第二个修饰符:static(静态)

   用 static 修饰的属性和方法称为静态属性(类属性)、静态方法(类方法) ;

   他们是属于整个类的,是全类所有对象共享的成员,在全类中只有一份,不因创建多个对象而产生多份;不必创建对象,可以直接通过类名访问。

    实例属性是每个对象各自持有的独立空间(多份),对象单方面修改,不会影响其他对象

    静态属性是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象。

    静态属性

    调用:类名.静态属性

package com.monv.static_01;

public class Student {
    String  name;//实例属性
    int     age;
    
    //学生数量 单个学生不适合有学生数量这个属性 ,这个属性是属于整个类(学生类)的  所以要定义为静态的     
    static int count;
    
    public void showage() {
        System.out.println("姓名:"+this.name+"--年龄:"+this.age);
    }
}
----------------------------------------------
package com.monv.static_01;

public class TestStudent {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.name="小明";
        s1.age = 22;
        
        Student s2 = new Student();
        s2.name = "小红";
        s2.age  = 23;
        
        s1.showage();
        s2.showage();
        //------------静态属性的调用-类名.静态属性(Student.count)-----------
        Student.count = 50;//在整个内存中只有一份
        System.out.println("学生数量为:"+Student.count);
        
    }
}
------------------------------------------------------------------

案例:统计一个类的对象被创建了多少次?

package com.monv.static_01;

public class Teacher {
    String name;//姓名
    int age;    //年龄
    double salary;//工资
    //保存对象创建的次数
    static int count = 0;
    //创建对象的时候 会执行默认的构造方法 所以在默认构造方法中给count+1
    public Teacher() {
        Teacher.count++;
    }
    public void show() {
        System.out.println("姓名:"+name+" 年龄:"+age+" 工资:"+salary);
    }
}
----------------------------------------------
package com.monv.static_01;

public class TestTeacher {
    public static void main(String[] args) {
        
        System.out.println("对象创建之前的次数:"+Teacher.count);
        Teacher t1 = new Teacher();
        Teacher t2 = new Teacher();
        Teacher t3 = new Teacher();
        System.out.println("对象创建之后的次数:"+Teacher.count);
    }
}
-------------------------------------------------------
对象创建之前的次数:0
对象创建之后的次数:3
-------------------------------------------------------

 静态方法

  调用:类名.静态方法

  1. 静态方法可以直接访问静态成员的                 
  2. 静态方法不能直接访问非静态成员。(静态方法属于类,不需要创建对象就可以用,而非静态成员属于每个对象,在使用静态方法的时候没有对象,无法访问非静态成员)
  3. 静态方法中不允许使用this或super关键字。(this调用的是本类的属性或方法,调用的也是非静态。super是父类的属性和方法,也是非静态的)
  4. 静态方法可以继承,不能重写,没有多态。

静态代码块

  语法:static{}

   什么时候执行静态代码块? 在类加载时,触发静态代码块的执行(仅一次)。执行地位:静态属性初始化后。

   作用:可为静态属性赋值,或必要的初始行为。

package com.monv.static_01;

public class Person {
    String name;

    //静态成员 人的最大数量
    static int max = 0;
    
    //静态代码块:类加载的时候则执行静态代码块,而且仅执行一次,可以进行一些初始化操作
    static {
        max = 10000;
        System.out.println("人的最大数量:"+max);
    }
    //静态方法
    public static void method() {
        
    }
}
--------------------------------------------------------------------
package com.monv.static_01;

public class TestPerson {
    public static void main(String[] args) {
        Person p;//用Person 创建一个对象p 这种静态方法没有执行(只用类创建了变量,类是不会加载的)
        Person p1 = new Person();//在new实例化对象的时候执行静态代码块
        Person p2 = new Person();//在new实例化对象的时候执行静态代码块
        
        Person.method();//调用静态方法也触发静态代码块的执行
    }
}
-----------------------------------------------------------------------

 

类加载

  • JVM首次使用某个类时,需通过CLASSPATH查找该类的  .class 文件
  • 将.class文件中对类的描述信息加载到内存中,进行保存。(从硬盘上加载到内存中,在加载的时候会触发静态代码块的执行)

           如:包名,类名,父类,属性,方法,构造方法。。。。(把这些加载到内存中)

  • 加载时机(以下都可以触发类的加载,类加载的时候会触发静态代码块的执行):
  1. 创建对象 
  2. 创建子类对象
  3. 访问静态属性
  4. 调用静态方法
  5. 主动加载:Class.forName("全限定名")

 总结:

  • static修饰的成员为静态成员、无需创建对象,可以直接通过类名访问
  • 静态方法不能直接访问非静态成员
  • 静态方法中不能使用this或super。
  • 静态方法可以继承、不能重写、没有多态
  • 静态代码块在类加载时被执行,且只执行一次

3.第三个修饰符:final(最终)

  • 概念:最后的,不可更改的。
  • final可以修饰的内容:类(最终类) 不能被继承;方法(最终方法)不能被覆盖重写,可以使用;变量(最终变量) 常量不能被更改

 final修饰方法:

 

-------------------汽车类父类------------------------
package com.monv.final_1;
/**
 * final修饰类:表示最终类 不能被继承
 * @author lenovo
 *
 */
public  class Car {
    String brand;
    String color;
    //最终方法,子类不能被重写,但是可以被继承
    public final void run() {
        System.out.println("汽车在前进...");
    }
}
--------------------小汽车类子类-----------------
package com.monv.final_1;

public class SmallCar extends Car{
//父类中run方法被final修饰 是最终方法不能重写 但是可以使用
//    @Override
//    public void run() {
//        System.out.println("小汽车正在前进...");
//    }
}

-----------------------测试------------------------
package com.monv.final_1;

public class TestCar {
    public static void main(String[] args) {
        SmallCar c1 = new SmallCar();
        c1.run();//父类中的方法
    }
}
----------------------------------------------------

 

final修饰变量:此变量值不能被改变(常量)   所有final修饰的变量只能赋值一次,值不允许改变。

  • 修饰局部变量-----变为常量
public  class Car {
    String brand;
    String color;
    //最终方法,子类不能被重写,但是可以被继承
    public final void run() {
        System.out.println("汽车在前进...");
        final int num = 100;//被final修饰 变为常量  num的值就不能改变
//        num = 200; num变为了常量 就不能再改变了 这句话就会报错
    }
}
  • 修饰实例变量----变成实例常量

  实例常量不再提供默认值,必须手动赋予初始值。

  赋值时机:显示初始化(直接在定义的时候赋值)、构造方法(在构造方法中对其赋值)。

  注意:如果在构造方法中为实例常量赋值,必须保证所有的构造方法都能对其正确赋值。

public  class Car {
//    final String brand = "宝马";//brand被final修饰变成实例常量 编译器不再给默认值 必须赋值,并且只能赋值一次
    final String brand ;//也可以在构造方法中给实例常量赋值    
    String color;
    
    public Car() {
        this.brand = "宝马";
    }
    //多个构造方法 也必须要给实例常量赋值
    public Car(String brand) {
        this.brand = brand;
    }
    //最终方法,子类不能被重写,但是可以被继承
    public final void run() {
        System.out.println("汽车在前进...");
        final int num = 100;//被final修饰 变为常量  num的值就不能改变
//        num = 200; num变为了常量 就不能再改变了 这句话就会报错
//        brand = "大众";//再次赋值就会报错
    }
}
  • 修饰静态变量---静态常量

  静态常量不再提供默认值,必须手动赋予初始值。

  赋值时机:显示初始化(直接在定义的时候赋值)、静态代码块。

public  class Car {
       //静态变量被final修饰变成静态常量 编译器不再给默认值 必须赋值,并且只能赋值一次
    final static String ADDRESS="上海";//定义的时候直接赋值 
    final static String ADDRESS1;
    //静态代码块赋值
    static {    
        ADDRESS1 = "北京";
    }
}
  • 对象常量

    final 修饰基本类型:值不可以被改变

         final 修饰引用类型:地址不可以被改变

package com.monv.final_1;

import java.util.Arrays;

public class TestStudent {
    public static void main(String[] args) {
        //final 修饰基本类型
        final int num = 20;
//        num = 30;//报错 不能被修改
        
        //final 修饰引用类型
        final int[] nums = new int [] {10,20,30};
//        nums = new int[5];//不能对nums在进行初始化了 会报错 
        nums[2] = 40;//但是可以修改nums中元素的值
        System.out.println(Arrays.toString(nums));
        
        final Student s1 = new Student();
//        s1 = new Student(); s1变成常量了 就不能再对其赋值 地址不可以改变
        s1.name = "小明";//但是可以对s1的属性进行赋值
        System.out.println(s1.name);
    }
}

总结:

  • final修饰类:此类不能被继承
  • final修饰方法:此方法不能被覆盖
  • final修饰变量:此变量不能被改变(无初始值,只允许赋值一次)

    局部常量:显示初始化(定义的时候直接赋值)

    实例常量:显示初始化、构造方法赋值

    静态常量:显示初始化、静态代码块

    基本类型常量:值不可变。

    引用类型常量:地址不可变。引用类型的数量可以改变。

 

posted @ 2020-08-31 23:11  改Bug的小魔女  阅读(323)  评论(0编辑  收藏  举报