一、** final关键字

1、final修饰变量

final修饰的基本数据类型的变量可以初始化,不能再更改。

/**
 * @document: final修饰变量
 * @Author:SmallG
 * @CreateTime:2023/7/27+9:17
 */

public class Demo01 {
    public static void main(String[] args) {
        //在方法中声明的变量就是局部变量
        final int a; //声明一个final的变量
        a = 5; //只能赋值一次 第一次赋值成为初始化
        System.out.println(a); //5
        // a = 10; //编译错误 final修饰的局部变量 不能修改值

        final int b =10; //在声明变量的时候同时初始化  不能再次赋值
    }
}

(1)final修饰局部变量

方法中的变量和方法的参数都属于局部变量。当final修饰引用类型变量时对象的首地址不能修改,但是对象的内容可以修改。

final修饰局部变量

/**
 * @document: final修饰局部变量
 * @Author:SmallG
 * @CreateTime:2023/7/27+9:17
 */

public class Demo01 {
    public static void main(String[] args) {
        //在方法中声明的变量就是局部变量
        //final修饰引用类型变量
        //变量中存的是变量的首地址
        //初始化后不能再修改
        //但是变量中的值可以修改
        final int[] arr = {5, 10};
        System.out.println(Arrays.toString(arr)); //[5, 10]
        arr[0] = 1;
        System.out.println(Arrays.toString(arr)); //[1, 10]
        //arr = new int [10];//报错: arr的引用不能改变
        
        final Aoo aoo = new Aoo(); //aoo 为引用类型变量
        //aoo = new Aoo(); //报错引用类型不能改变
        aoo.c =10; //变量的内容可以改变
        
        //aoo = null;  //aoo引用中保存的是地址不能修改
    }
}
class Aoo {
    int c = 5;
}

final修饰方法的参数:

/**
 * @document: final修饰方法的参数
 * @Author:SmallG
 * @CreateTime:2023/7/27+9:36
 */

public class Demo02 {
    public static void main(String[] args) {
        Boo boo = new Boo();
        boo.sum(5, 10); //在调用时进行初始化赋值
    }
}

class Boo {
    public void sum(int a, final int b) {
        a = 10;
        //b = 20; //报错:方法的参数使用final修饰 不能再次赋值
        System.out.println(a + b);
    }
}

(2)final修饰类的成员变量

/**
 * @document:final修饰类的成员属性(成员变量/实例变量)
 * @Author:SmallG
 * @CreateTime:2023/7/27+9:43
 */

public class Demo03 {
    public static void main(String[] args) {
        Coo coo1 = new Coo();
        System.out.println(coo1.a + " " + coo1.b); //5 3

        Coo coo2 = new Coo(10);
        System.out.println(coo2.a + " " + coo2.b); //5 10
        //coo2.a = 15;  报错:不能修改final修饰的成员属性值
    }
}

class Coo {
    final int a = 5; //在声明的时候直接初始化
    final int b;

    //不能有默认构造器 (如果非要有需要将b的值进行初始化
    public Coo() {
        this.b = 3;
    }

    public Coo(int b) {//在构造器中完成初始化
        this.b = b;
    }
}

2、final修饰方法

final修饰的方法不能在子类中重写。

/**
 * @document: final修饰方法
 * @Author:SmallG
 * @CreateTime:2023/7/27+10:09
 */

public class Demo04 {
    public static void main(String[] args) {
        Doo doo = new Doo();
        doo.hello(); //Hello World
        SubDoo subDoo = new SubDoo();
        subDoo.hello(); //Hello World
    }
}

class Doo {
    public final void hello() {
        System.out.println("Hello World"); 
    }
}

class SubDoo extends Doo {
    //final修饰的方法可以被继承 但是不能被重写
    /*public final void hello(){
        报错:不能被重写
    }*/
}

3、final修饰类

final修饰的类不能再被继承派生出子类,在实际开发中一般禁止使用final声明类。

/**
 * @document: final修饰类
 * @Author:SmallG
 * @CreateTime:2023/7/27+10:21
 */

public class Demo05 {
    public static void main(String[] args) {
        Eoo eoo = new Eoo(); //可以创建相应的对象并且运行方法
        eoo.hello(); //Hello World
    }
}

final class Eoo {
    public void hello() {
        System.out.println("Hello World");
    }
}

/*class Foo extends Eoo{
    编译错误:被final修饰的类不能被继承
}*/

二、** static关键字

1、修饰变量

成员变量有三种:实例变量、静态变量、常量

实例变量:是属于每个对象的属性,每个对象中都有一份

静态变量:是属于类的变量,只有一份,全体对象共享的同一份变量

常量:是不变的常数

静态变量:

使用static修饰的变量时静态变量,全体对象共享的一份变量,用静态变量存储程序中只有一个就足够的数据,静态变量和类的信息一起存储在方法区,static不能直接修饰局部变量。

静态变量工作原理:

第一次运行时,字节码文件会被分配到方法区,类中的静态变量此时在方法区中分配出来,字节码文件只加载一次。

/**
 * @document: static修饰成员属性  被修饰的属性称为静态成员 属于整个类
 * 类的所有对象共享这一个数据
 * @Author:SmallG
 * @CreateTime:2023/7/27+10:34
 */

public class Demo06 {
    public static void main(String[] args) {
        Foo foo1 = new Foo();
        Foo foo2 = new Foo();

        foo1.a = 5;
        foo2.a = 10; //修改的不是一个存储位置的变量
        foo1.b = 20;
        foo2.b = 30; //修改的是同一个位置的变量

        System.out.println(foo1.a); //5
        System.out.println(foo2.a); //10
        System.out.println(foo1.b); //30
        System.out.println(foo2.b); //30

        //static修饰的成员属性不推荐使用对象访问,推荐使用类直接访问
        Foo.b = 50;
    }
}

class Foo {
    int a; //普通的成员属性
    static int b; //static修饰的属性称为类属性/类变量 只有一份 被全体对象共享
    
    public void hello(){
        //static int age =10; static不能直接修饰局部变量
    }
}

static修饰变量

static final一起使用

同时使用时声明称为静态常量,不能被改变。

/**
 * @document: 常量 static final 常量在声明的时候就赋值 以后不可修改
 * @Author:SmallG
 * @CreateTime:2023/7/27+11:15
 */

public class Demo07 {
    public static void main(String[] args) {
        System.out.println(Message.MSG_LOGIN_FAILED);
        System.out.println(Message.MSG_LOGIN_SUCCESS);

    }
}

class Message {
    //用static final修饰的变量 名字采用全大写 单词组合用下划线分开
    public static final String MSG_LOGIN_FAILED = "用户名或密码错误";
    public static final String MSG_LOGIN_SUCCESS = "登录成功";
}

常量的细节:

  • 软件中不能改变的数据,应该都定义常量
  • 同时使用static final修饰,两个关键字可以调换
  • 常量必须初始化
  • 一般常量名都是大写字母,多个单词使用下划线分割开

2、修饰方法

静态方法是属于类的方法。属于类的方法就可以直接使用类名直接引用方法。比如:Math.random()就是一个静态方法。

静态方法不能访问非静态成员,普通方法可以访问非静态成员。这里静态成员指成员属性和方法。

/**
 * @document: 静态方法 使用static关键字修饰的方法 可以直接用类名访问
 * @Author:SmallG
 * @CreateTime:2023/7/27+14:02
 */

public class Demo08 {
    public static void main(String[] args) {
        Person.add(3, 5); //8

        //成员方法只能通过对象访问
        Person person = new Person("tom");
        person.WhoRY();

        person.add(6,9);//15 对象也可以访问静态方法 不推荐
        //我是tom
        //10
        WaWo(); //可以直接访问本类中的静态方法
        // HH();  报错:不可以直接访问本类中的普通方法
    }
    public static void WaWo(){
        System.out.println("这里是静态方法");
    }
    public void HH(){
        System.out.println("这里是普通方法");
    }
}

class Person {
    String name;
    static int num = 10;

    public Person(String name) {
        this.name = name;
    }

    //静态方法不能用this 静态方法属于整个类 this是属于对象的
    //静态方法不能访问非静态成员
    public static void add(int a, int b) {
        System.out.println(a + b);
        // System.out.println(name); 报错:静态方法不能访问非静态成员(成员属性和方法)
        System.out.println(num); //10
    }

    public void WhoRY() {
        System.out.println("我是" + this.name);
        System.out.println(num); //普通方法可以访问静态成员
    }
}

3、static的其他用法

代码块

/**
 * @document: 代码块 在类中直接使用一对{}编写的代码
 * @Author:SmallG
 * @CreateTime:2023/7/27+14:27
 */

public class Demo09 {
    public static void main(String[] args) {
        Goo goo1 = new Goo(); //属性成功初始化
        Goo goo2 = new Goo(); //属性成功初始化
        System.out.println(goo1.name); //Tom
        System.out.println(goo2.name); //Tom
    }
}

class Goo {
    String name;

    //每次创建对象,都会调用代码块中的内容
    {
        name = "Tom";
        System.out.println("属性成功初始化");
    }
}

静态代码块

在类加载期间执行,只加载一次。

/**
 * @document: 静态代码块 在加载类的时候(创建类的对象或访问类的静态成员)执行 以后不再执行
 * @Author:SmallG
 * @CreateTime:2023/7/27+14:33
 */

public class Demo10 {
    public static void main(String[] args) {
        //创建对象
        /*Hoo hoo1 = new Hoo(); //静态成员初始化成功
        Hoo hoo2 = new Hoo(); //静态代码块只能执行一次*/
        System.out.println(Hoo.name); //静态成员初始化成功  Tom 先加载类 静态代码块立即执行
    }
}

class Hoo {
    static String name;

    //静态代码块只能访问静态成员
    static {
        System.out.println("静态成员初始化成功");
        name = "Tom";
    }
}

静态导入

import static static1.Person.*; //加载Person里面的所有组件

/**
 * @document: 静态导入 在导包的时候前面加static
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:05
 */

public class Demo11 {
    public static void main(String[] args) {
        eat();
        sleep();
        talk();
    }
}

三、**abstract抽象

1、抽象类

抽象类不能直接实例化创建对象,是个半成品创建对象没有意义,只包含部分的属性和方法。

abstract和final不可以同时修饰一个类,final关键字不能被继承,而抽象类如果不能被继承就没有了意义。

抽象类中可以创建构造器,用于子类的继承。

/**
 * @document: 父类
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:30
 */
//抽象类不能被实例化  但是可以被继承
public abstract class Person {
    String name;
    int age;

    public void whoru() {
        System.out.println("我是" + name);
    }
}

/**
 * @document:
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:33
 */

public class Student extends Person {
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void study() {
        System.out.println("我在学习");
    }
}

/**
 * @document:
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:37
 */

public class Teacher extends Person {
    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void teach() {
        System.out.println("我在讲课");
    }
}

/**
 * @document:
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:40
 */

public class Worker extends Person {
    public Worker(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void work() {
        System.out.println("我在工作");
    }
}


/**
 * @document: 测试类
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:42
 */

public class Demo13 {
    public static void main(String[] args) {
        Student student = new Student("Tom", 12);
        //创建老师对象
        Teacher teacher = new Teacher("Jerry", 30);
        //创建工人对象
        Worker worker = new Worker("Spike", 25);
        student.whoru(); //我是Tom
        student.study(); //我在学习

        teacher.whoru(); //我是Jerry
        teacher.teach(); //我在讲课

        worker.whoru();  //我是Spike
        worker.work();   //我在工作

        //问题:如果创建person对象 父类没有初始化 不应该让他们创建对象
        //java编译器检查  不允许创建抽象类的对象
        //Person person = new Person();
        //person.whoru();
    }
}

2、抽象方法

使用abstract关键字声明,不包含方法体

(思想是重点)抽象方法的语法:

抽象类可以没有抽象方法,但是一个类如果有抽象方法就一定要是抽象类。子类继承抽象类要重写所有的抽象方法,否则报错。

抽象方法的意义在于便于程序的统一管理

/**
 * @document: 父类
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:30
 */
//抽象类不能被实例化  但是可以被继承
public abstract class Person {
    //抽象方法 不能有方法体
    public abstract void schedule();
}

/**
 * @document:
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:33
 */

public class Student extends Person {
    @Override
    public void schedule() {
        System.out.println("吃饭 听课");
    }
}

/**
 * @document: 测试类
 * @Author:SmallG
 * @CreateTime:2023/7/27+15:42
 */

public class Demo13 {
    public static void main(String[] args) {
        Student student1 = new Student("SmallG",23);
        student.schedule();
    }
}

四、练习

计算汽车租赁价格

汽车租赁公司出租多种车辆,车型和租金情况如下图所示:

练习1

编写程序实现租赁价格的计算。

具体需求:

1、车辆分为轿车和客车两大类,它们都继承自抽象类MotoVehicle,如下图所示:

练习2

2、抽象类MotoVehicle

  • 有参构造器:带有两个参数(String类型的汽车牌照和品牌)
  • 方法getNo():返回String 类型的汽车牌照
  • 方法getBrand():返回String 类型的品牌(宝马或者别克)
  • 抽象方法calRent():需要一个int类型的参数表示被租赁的天数,用于计算租金
/**
 * @document: 父类抽象类
 * @Author:SmallG
 * @CreateTime:2023/7/27+8:04
 */

public abstract class MotoVehicle {
    String no; //汽车牌照
    String brand; //汽车品牌

    //无参构造器
    public MotoVehicle() {
    }

    //有参构造器
    public MotoVehicle(String no, String brand) {
        this.no = no;
        this.brand = brand;
    }

    //get方法
    public String getNo() {
        return no;
    }

    public String getBrand() {
        return brand;
    }

    //抽象方法
    public abstract int calRent(int days);
}

3、子类 Car:表示轿车

  • 有参构造器:带有三个参数(String类型的汽车牌照、品牌、车型)
  • 方法getType():返回String 类型的车型(如果是宝马,则为 550i)
  • 方法setType():带有Stirng类型的参数,设置车型
  • 重写方法calRent():根据品牌及车型,找到对应的日租金,乘以租用天数,计算租金
/**
 * @document: 汽车类,表示轿车
 * @Author:SmallG
 * @CreateTime:2023/7/27+8:10
 */

public class Car extends MotoVehicle {
    String type;

    //无参构造器
    public Car() {
    }

    //有参构造
    public Car(String no, String brand, String type) {
        super(no, brand);
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public int calRent(int days) {
        if (brand.equals("宝马") && type.equals("550i")) {
            return days * 500;
        } else if (brand.equals("别克商务舱") && type.equals("GL8")) {
            return days * 600;
        } else {
            return days * 300;
        }
    }
}

4、子类 Bus:表示客车

  • 有参构造器:带有三个参数(String类型的汽车牌照和品牌、int类型的车座位数)
  • 方法getSeatCount ():返回int 类型的车座位数
  • 方法setSeatCount ():带有int 类型的参数,设置车座位数
  • 重写方法calRent():根据座位数,找到对应的日租金,乘以租用天数,计算租金
/**
 * @document: 表示客车
 * @Author:SmallG
 * @CreateTime:2023/7/27+8:17
 */

public class Bus extends MotoVehicle {
    int seatCount;

    public Bus() {
    }

    public Bus(String no, String brand, int seatCount) {
        super(no, brand);
        this.seatCount = seatCount;
    }

    public int getSeatCount() {
        return seatCount;
    }

    public void setSeatCount(int seatCount) {
        this.seatCount = seatCount;
    }

    @Override
    public int calRent(int days) {
        if (seatCount <= 16) {
            return days * 800;
        } else {
            return days * 1500;
        }
    }
}

5、定义测试类TestRent,并实现车辆的租赁计算。

运行效果如下所示:

练习3

/**
* @document: 测试类
* @Author:SmallG
* @CreateTime:2023/7/27+8:20
*/

public class TestRent {
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int sum = 0;

    System.out.println("欢迎您来到汽车租赁公司!");
    System.out.print("请输入要租赁的天数:");
    int days = scanner.nextInt();
    boolean s1 = true;
    int num1 = 0;
    while (s1) {
        System.out.print("请输入要租赁的汽车类型(1:轿车\t 2、客车):");

        num1 = scanner.nextInt();
        if (num1 != 1 && num1 != 2) {
            System.out.println("请输入正确的汽车类型!");
        } else {
            s1 = false;
        }
    }
    //选择轿车
    int num2 = 0;
    if (num1 == 1) {
        boolean s2 = true;
        while (s2) {
            System.out.print("请输入要租赁的汽车品牌(1、宝马\t 2、别克):");
            num2 = scanner.nextInt();
            if (num2 != 1 && num2 != 2) {
                System.out.println("请输入正确的汽车品牌!");
            } else {
                s2 = false;
            }
        }
    } else {//选择客车
        boolean s4 = true;
        int num5 = 0;
        while (s4) {
            System.out.print("请输入要租赁的客车品牌(1、金杯\t 2、金龙):");
            num5 = scanner.nextInt();
            if (num5 != 1 && num5 != 2) {
                System.out.println("请输入正确的汽车品牌!");
            } else {
                s4 = false;
            }
        }
        boolean s5 = true;
        int num6 = 0;
        while (s5) {
            System.out.print("请输入客车的座位数:");
            num6 = scanner.nextInt();
            if (num6 <= 0) {
                System.out.println("请输入正确的座位数!");
            } else {
                s5 = false;
            }
        }
        if (num5 == 1) {
            Bus bus = new Bus("京AU8769", "金杯", num6);
            sum = bus.calRent(days);
            System.out.println("分配给您的汽车牌号是:" + bus.no);
        }else{
            Bus bus = new Bus("京AU8769", "金龙", num6);
            sum = bus.calRent(days);
            System.out.println("分配给您的汽车牌号是:" + bus.no);
        }
    }
    //轿车型号
    boolean s3 = true;
    int num3 = 0;
    int num4 = 0;
    if (num2 == 1) { //轿车宝马
        while (s3) {
            System.out.print("请输入轿车型号(1、550i):");
            num3 = scanner.nextInt();
            if (num3 == 1) {
                s3 = false;
            } else {
                System.out.println("请输入正确的轿车型号!");
            }
        }
        Car car = new Car("京BK5543", "宝马", "550i");
        sum = car.calRent(days);
        System.out.println("分配给您的汽车牌号是:" + car.no);

    } else if (num2 ==2){//轿车别克
        while (s3) {
            System.out.print("请输入轿车型号(1、GL8):");
            num4 = scanner.nextInt();
            if (num4 == 1) {
                s3 = false;
            } else {
                System.out.println("请输入正确的轿车型号!");
            }
        }
        Car car = new Car("京BK5543", "别克商务舱", "GL8");
        sum = car.calRent(days);
        System.out.println("分配给您的汽车牌号是:" + car.no);
    }
    System.out.println();
    System.out.println("顾客您好!您需要支付的租赁费用是" + sum + "。");
} }


最后修改:2023 年 07 月 28 日
如果觉得我的文章对你有用,请随意赞赏