7. Java面向对象基础

1. 面向对象
⟴ 面向过程(以方法为单位解决问题)
⟴ 面向对象(以对象为单位解决问题)

  ➤ 在Java中,一切皆对象,程序由对象之间的交互来实现功能
面向对象编程(OOP):一种编程思维方法,将问题抽象化为对象,并通过定义对象的属性(成员变量)和行为(方法)来描述问题
面向对象编程(OOP)的五个核心: 类,对象,封装,继承,多态
  ▶ 类(Class)类是定义对象的模板或蓝图(描述对象的属性和行为),类型/类别/模板/,表示一类个体
  ▶ 对象(Object)对象(具体的、有状态和行为的实体)是类的实例

  OOP的三大特征
  ▶ 封装(Encapsulation)封装是一种将数据和操作数据的方法捆绑在一起的机制,隐藏对象内部的实现细节,并通过公共接口提供访问数据的方式(封装提供了信息隐藏、保护数据完整性和实现代码复用的好处)
  ▶ 继承(Inheritance)继承是一种机制,允许一个类(子类)派生自另一个类(父类)的属性和方法。子类可以继承父类的特性,并可以添加自己的特定功能(继承实现了代码的重用性和层次结构的组织)
  ▶ 多态(Polymorphism)多态是指同一名字的操作可以在不同的对象上有不同的行为,允许使用统一的接口处理不同类型的对象(多态性增强了灵活性、可扩展性和可维护性)
2. 类和对象

类的定义
      成员变量:对象的属性(特征/数据)
      成员方法:对象的行为(动作/功能)

创建类:
   class 类名 {
     类体
   }

class 类名() {
	// 成员变量
	变量类型 变量名;
	......

	// 成员方法
	[修饰词] 返回类型 方法名([参数列表]) {
		方法体;
		......
	}
	......
}

创建对象
       将类创建完成后,使用new关键字创建对象(也称类的实例化)

为了能够对实例化对象进行访问控制,需要使用一个特殊的变量——引用
java数据类型:基本数据类型和引用数据类型(类,接口,数组)
访问成员变量及成员方法:
       通过引用去访问对象的成员变量和成员方法
一般引用: 引用.成员变量名
引用并赋值:引用.成员变量 = 新值

数据类型   应用类型变量(引用)  指向    对象
Random       rand            =   new Random;
  • 创建简单学生类
package oopbasic;

/** 创建学生类 */
public class Student {
    // 成员变量
    String name;
    int age;
    String classNum;
    String id;

   // 成员方法
    void study(){
        System.out.println("学习java");
    }

    // 查看学生信息
    void show() {
        System.out.println("姓名:" + name + " 年龄:" + age + " 班级:" + classNum +  " 学号:" + id);
    }

    // 包含参数的方法
    void play(String anotherName) {
        System.out.println(name + "和" + anotherName + "正在打球!");
    }
}
  • 创建测试类
package oopbasic;

public class Test {
    public static void main(String[] args) {
     	// 类的实例化
        Student student = new Student();
        // 访问成员变量
        student.name = "张三";
        student.age = 20;
        student.classNum = "202301";
        student.id = "001";

        // 方法调用
        student.study();
        student.show();
        student.play("李四");
    }
}
3. 构造方法
构造方法(Constructor):一种特殊的方法,用于创建对象并初始化其实例变量
  ▶ 作用:给成员变量赋初始值
  ▶ 语法:名称必须与类名完全相同,并且没有返回类型(包括void)
  ▶ 调用:创建类的新对象时,构造方法会被自动调用
  ▶ 特点:编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供(需要手动添加无参构造方法)

this关键字:

this关键字的三种形式
访问变量: this.成员变量名
调用方法: this.方法名
调用构造方法: this()

this关键字只能用在方法中,方法中访问成员变量之前默认都有this
在这里插入图片描述在这里插入图片描述
this指代当前对象,哪个对象调用方法,它指的就是哪个对象
在这里插入图片描述
成员变量和局部变量是可以同名的,使用时默认采取的是就近原则当成员变量与局部变量同名时,若想访问成员变量则this不能省略
  在无参构造方法(成员变量的默认值,调用时自动默认,int为0,double为0.0)中可以调用其他方法(此时默认存在this关键字)关键字调用同方法中的其他成员方法,也能通过this(不可省)关键字调用本类中的有参构造方法在这里插入图片描述在这里插入图片描述
在这里插入图片描述

简单完整Student类

package oopbasic;

/** 创建学生类 */
public class Student {
    // 成员变量
    String name;
    int age;
    // 为成员变量赋默认值
    String classNum;
    String id;

    // 无参沟造方法(默认系统给出,一旦有的有参构造,则不提供无参构造,需要用时手动给出,自动调用)
    Student () {
        // 设置默认值
        name = "Unknown";
        age = 0;
    }

    // 有参构造(用于在调用时给成员变量初始化)
    Student (String name, int age, String classNum, String id) {
        // 成员变量与局部变量同名(采取就近原则,当局部访问成员变量时,用this关键字)
        // 变量初始化
        this.name = name;
        this.age = age;
        this.classNum = classNum;
        this.id = id;
    }

    // 成员方法
    void study(){
        System.out.println("学习java");
    }

    // 查看学生信息
    void show() {
        System.out.println("姓名:" + name + " 年龄:" + age + " 班级:" + classNum +  " 学号:" + id);
    }

    // 包含参数的方法
    void play(String anotherName) {
        System.out.println(name + "和" + anotherName + "正在打球!");
    }
}

测试类

package oopbasic;

public class Test {
    public static void main(String[] args) {
        // 无参构造
        Student student = new Student();
        // 访问成员变量
        student.name = "张三";
        student.age = 20;
        student.classNum = "202301";
        student.id = "001";

        // 方法调用
        student.study();
        student.show();
        student.play("李四");

        // 有参构造
        Student student1 = new Student("王五", 24, "2023", "002");
        student1.study();
        student1.show();
        student1.play("李四");
    }
}
4. java内存管理基础
Java内存管理:java内存由JVM(Java虚拟机)来管理
  ▶ 方法区:java字节码文件(.class文件:包括方法信息,静态变量等)加载区
  ▶ 堆(Heap):所有线程共享,并由垃圾收集器自动管理(存放new出来的对象,实例变量,数组元素,方法地址)
  ▶ 栈(Stack):存放线程方法调用和局部变量的内存区域

Java堆和栈的区别(Java中的堆和栈是两个不同的内存区域)

项目
存储内容存放动态分配的对象存放线程的方法调用和局部变量
分配方式堆的空间是动态分配的(动态地创建和销毁对象)栈的空间是静态分配的(线程在启动时就会为其分配一定大小的空间)
生存周期堆中的对象生存周期比较长(没有引用了才会收回)栈中的数据只存在于方法调用的过程中(执行完后即销毁)
空间大小堆远大于栈(堆需要存储所有动态分配的对象)栈的很小(存储方法参数、局部变量和返回地址等小数据)
内存管理堆由Java虚拟机自动进行垃圾回收,以释放不再使用的对象占用的空间栈的内存管理是由Java编译器自动管理
5. 继承
继承:一个类(子类)继承另一个类(父类)的属性和方法,(继承机制是面向对象编程的基本特征之一)被继承的类称为父类或超类或基类(superclass),继承这个类的类称为子类或派生类(subclass)
  ▶ 关键字extends:使用关键字extends来建立继承关系(子类使用extends关键字后跟父类名称来声明继承关系)
  ▶ 特性:子类继承了父类的非私有属性和方法(公共(public)、受保护(protected)和默认(default)访问权限的成员),子类可以重写父类的方法
  ▶ 单继承:一个类只能直接继承一个父类(Java不支持多重继承 —— 降低复杂性和避免潜在的冲突),但一个父类可以有多个子类
  ▶ 传递性:类A继承自类B,而类B又继承自类C,则类A自动也继承了从类C继承来的属性和方法
  ▶ 作用:实现代码复用,便于扩展代码和业务功能

通常,子类是对父类的抽象和扩展(子类相对于父类来说是更具体、更专门化的)
继承要符合是的关系

简单继承实例(this关键字实现)

  • Person(父类)
package oop.extend;

public class Person {
    String name;
    int age;
    String address;

    void eat() {
        System.out.println(name + "正在吃饭!");
    }

    void sleep() {
        System.out.println(name + "正在睡觉!");
    }
    void sayHi(){
        System.out.println("大家好,我叫" + name + ", 今年" + age + "岁了, 家住" + address);
    }
}
  • Student(子类1)
package oop.extend;

// 学生类继承Person
public class Student extends Person{
    // 子类属性
    String className;
    String studentId;

    // 无参构造
    Student(){}
    // 有参构造
    Student(String name, int age, String address, String className, String studentId){
        this.name = name;
        this.age = age;
        this.address = address;
        this.className = className;
        this.studentId = studentId;
    }

    // 子类方法
    void study() {
        System.out.println(name + "正在学习!");
    }
}
  • Teacher(子类2)
package oop.extend;

// 老师类继承Person
public class Teacher extends Person{
    // 子类属性
    double salary;

    // 无参构造
    Teacher(){}
    // 有参构造
    Teacher(String name, int age, String address,double salary){
        this.name = name;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    // 子类方法
    void teach() {
        System.out.println(name + "正在上课!");
    }
}
  • TestExtend(测试类)
package oop.extend;

public class TestExtend {
    public static void main(String[] args) {
        System.out.println("学生************************************************************************************");
        // 实例化学生对象(无参)
        Student lm = new Student();
        lm.name = "李明";
        lm.age = 20;
        lm.address = "北京市海淀区中关村大街123号";
        lm.className = "2308";
        lm.studentId = "200001";
        // 方法调用
        lm.eat();
        lm.sayHi();
        lm.sleep();
        lm.study();

        // 实例化学生对象(有参)
        Student wq = new Student("王强", 22, "上海市浦东新区世纪大道789号", "2308", "200002");
        // 方法调用
        wq.eat();
        wq.sayHi();
        wq.sleep();
        wq.study();
        System.out.println("学生************************************************************************************");

        System.out.println("老师************************************************************************************");
        // 实例化老师对象(无参)
        Teacher zw = new Teacher();
        zw.name = "张伟";
        zw.age = 26;
        zw.address = "广州市天河区珠江西路456号";
        zw.salary = 5600;

        // 方法调用
        zw.eat();
        zw.sayHi();
        zw.sleep();
        zw.teach();

        // 实例化老师对象(有参)
        Teacher zm = new Teacher("赵敏", 25, "深圳市南山区科技园北区789号", 6000);
        // 方法调用
        zm.eat();
        zm.sayHi();
        zm.sleep();
        zm.teach();
        System.out.println("老师************************************************************************************");
    }
}

super关键字
   作用:指代当前对象的超类对象
   super的用法:
         1.super.成员变量名:访问超类的成员变量
         2.super.方法():调用超类的方法
         3.super():调用超类的构造方法


子类利用super调用父类的构造方法: 1. 在子类中无参构造器中,java默认自动调用父类的无参构造器(如果在子类中手动添加了有参构造,则子类不提供无参构造,同理也不会调用父类无参构造);
                 2. 如果父类创建了有参构造,则在父类中也要提供无参构造,不然子类中的有参和无参构造均会报错

简单继承实例(super关键字实现 – 继承父类构造器)

  • Person(父类)
package oop.extend;

public class Person {
    String name;
    int age;
    String address;

    // 父类(无参)构造器
    Person(){
        System.out.println("父类无参构造");
    }
    // 父类(有)构造器
    Person(String name, int age, String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }

    void eat() {
        System.out.println(name + "正在吃饭!");
    }

    void sleep() {
        System.out.println(name + "正在睡觉!");
    }
    void sayHi(){
        System.out.println("大家好,我叫" + name + ", 今年" + age + "岁了, 家住" + address);
    }
}
  • Doctor(子类1:子类有参构造使用super关键字)
package oop.extend;

// 医生类继承Person
public class Doctor extends Person{
    // 子类属性
    String title;

    // 无参构造
    Doctor(){
        // 默认调用父类的无参构造(super只能放在第一行),如果父类中写了有参构造(系统默认不提供无参构造),
        // 则子类中无法调用无参构造(因为此时父类中没有无参构造),此时如果需要调用父类中的无参构造,则需要在父类中手动添加无参构造
        super();
        System.out.println("子类无参构造");
    }
    // 有参构造
    Doctor(String name, int age, String address, String title){
        // 将this改为super
        // 指代当前对象的超类对象(super.成员变量名:访问超类的成员变量)代码标准格式(this指子类的,super指父类的)
        super.name = name;
        super.age = age;
        super.address = address;
        this.title = title;
    }

    // 子类方法
    void cut(){
        System.out.println(name + "正在做手术!");
    }

    // super.方法名():调用超类的方法

}

在这里插入图片描述

  • Student(子类2:子类无参构造调用父类有参构造)
package oop.extend;

// 学生类继承Person
public class Student extends Person{
    // 子类属性
    String className;
    String studentId;

    // 无参构造
    Student(){}
    // 有参构造
    Student(String name, int age, String address, String className, String studentId){
        // 调用父类的有参构造器
        super(name, age, address);
        this.className = className;
        this.studentId = studentId;
    }

    // 子类方法
    void study() {
        System.out.println(name + "正在学习!");
    }
}

在这里插入图片描述

6. 方法重写
重写:重写指的是在子类中重新定义(覆盖)父类中已存在的方法
  ▶ 特点:重写后的方法的名称、返回类型和参数列表都与父类的相同(改变方法体的功能)
  ▶ 方法权限修饰符:修饰符级别只能比父类低,不能超过父类

▶ 重载(Overloading)和重写(Overriding)
     重载指的是在同一个类中,可以有多个方法具有相同的名称,但是参数列表不同。重载可以通过改变方法的参数个数、参数类型或者参数顺序来实现。在调用重载方法时,根据传入的参数来确定调用哪个方法。
     重写指的是在子类中重新定义(覆盖)父类中已存在的方法。重写方法使用与父类方法相同的名称、返回类型和参数列表。重写方法不能拥有比父类更严格的访问修饰符,但可以拥有比父类更宽松的修饰符。
重载:提高程序的灵活性和可读性
重写:提高代码重用性和可维护性

  • 重载
public class MyClass {
    public void print(int num) {
        System.out.println("打印整数:" + num);
    }

    public void print(String str) {
        System.out.println("打印字符串:" + str);
    }

    public void print(double num1, double num2) {
        System.out.println("打印两个浮点数:" + num1 + "," + num2);
    }
}
  • 重写
public class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}

public class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗发出汪汪的声音");
    }
}

final关键字
   final 修饰类: final 修饰符应用于类时,表示最终类,不能被继承,无法扩展(继承)
   final 修饰方法:final 修饰符应用于方法时,表示最终方法,不能被子类重写,子类中无法覆盖(重写)
   final 修饰变量: final 修饰符应用于变量时,表示一个常量,只能被赋值一次,赋值后不可再修改

注:1. 不能被继承,但是可以继承其他类
  2. 通常用大写字母表示常量名称如 final int NUMBER

简单继承实例(标准继承写法)

package working;

public class Work09 {
    public static void main(String[] args) {
        Dog husky = new Dog("哈士奇", 2, "灰色的");
        husky.eat();
        husky.drink();
        husky.lookHome();
        Dog shiba = new Dog("柴犬", 1, "黄色的");
        shiba.eat();
        shiba.drink();
        shiba.lookHome();
        Dog mastiff = new Dog();
        mastiff.name = "藏獒";
        mastiff.age = 3;
        mastiff.color = "黑色的";
        mastiff.eat();
        mastiff.drink();
        mastiff.lookHome();

        Chick polish = new Chick("波尔鸡", 1, "黑色的");
        polish.eat();
        polish.drink();
        polish.layEggs();
        Chick phoenix = new Chick("龙凤鸡", 1, "金黄色的");
        phoenix.eat();
        phoenix.drink();
        phoenix.layEggs();
        Chick freeRange = new Chick();
        freeRange.name = "土鸡";
        freeRange.age = 1;
        freeRange.color = "灰色的";
        freeRange.eat();
        freeRange.drink();
        freeRange.layEggs();

        Fish goldfish = new Fish("金鱼", 1, "金色的");
        goldfish.eat();
        Fish koi = new Fish();
        koi.name = "锦鲤";
        koi.age = 1;
        koi.color = "红白相间的";
        koi.eat();
    }
}

// 父类
class Animal {
    String name;
    int age;
    String color;

    Animal() {
    }

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

    void drink() {
        System.out.println(name + "在喝水!");
    }

    void eat() {
        System.out.println(name + "在吃饭!");
    }
}

// 子类:Dog
class Dog extends Animal {
    Dog() {
    }

    Dog(String name, int age, String color) {
        super(name, age, color);
    }

    void lookHome() {
        System.out.println(age + "岁" + color + name + "正在看家!");
    }

    void eat() {
        System.out.println(color + name + "在吃饭!");
    }
}

// 子类:Chick
class Chick extends Animal {
    Chick() {
    }

    Chick(String name, int age, String color) {
        super(name, age, color);
    }

    void layEggs() {
        System.out.println(age + "岁" + color + name + "在下蛋!");
    }

    void eat() {
        System.out.println(color + name + "在啄米!");
    }
}

// 子类:Fish
class Fish extends Animal {
    Fish() {
    }

    Fish(String name, int age, String color) {
        super(name, age, color);
    }

    void eat() {
        System.out.println(color + name + "在吃鱼料!");
    }
}
7. 抽象方法和抽象类
抽象方法:一种没有具体实现的方法(只有方法的声明,没有方法体,以();结束)
  ▶ 关键字:由abstract修饰
  抽象方法代表着不完整的方法,包含抽象方法的类一定是抽象类,抽象类不能实例化(new对象)
  ▶ 抽象类继承:抽象类使需要继承的(不是强制的),设计初衷是为了被其他类继承和扩展
  ▶ 意义:定义一个接口或契约,要求子类必须实现该方法,使得代码更具可读性、可扩展性和可维护性
  ▶ 抽象类是实现类和接口之间的桥梁:抽象类既可以实现接口可也以继承其他类
  • 抽象方法意义

强制子类实现:抽象方法是一种约束,它要求继承抽象类或实现接口的子类必须提供具体的实现(确保子类中包含了抽象类或接口所定义的关键行为和功能)
提供统一的接口:抽象方法定义了一个统一的接口,使得不同的子类可以根据自身的特性来实现该接口(在多态的场景下,可以通过父类引用来调用不同子类的实现,提高代码的灵活性和扩展性)
实现代码重用:抽象方法可以在抽象类中定义,抽象类可以提供一些通用的属性和方法,而子类则只需实现特定的抽象方法(在子类中重复编写相同的代码,提高代码的复用性)
实现细节延迟到子类:抽象方法没有具体的实现,它将实现细节留给了具体的子类(父类提供了基本的框架和规范,而具体的实现可以适应各种不同的需求和场景)
抽象方法声明以分号结束,没有方法体;具体的实现需要在继承抽象类或实现接口的子类中完成

  • 简单抽象方法
package oop.abstracts;

public class AbstractTest {
    public static void main(String[] args) {
        // 创建dog实例
        Dog husky = new Dog("哈士奇");
        husky.eat();
    }
}

// 抽象类
abstract class Animal{
    String name;

    public Animal() {
    }

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

    // 抽象方法(包含抽象方法的类是抽象类)
    abstract void eat();
}

class Dog extends Animal{
    public Dog() {
    }

    public Dog(String name) {
        super(name);
    }

    // 抽象父类方法
    @Override
    void eat() {
        System.out.println(name + "在卖力地吃着口狗粮");
    }
}
8. 接口
接口(Interface):是一种抽象引用数据类型,用于定义类应该具有的方法和常量
  ▶ 关键字:由interface定义
  ▶ 作用:接口提供了一种契约机制,用于规定类应该如何实现特定的行为
  ▶ 特点:接口不能被实例化,需要被实现
  ▶ 实现类:实现接口的类,实现类中必须重写接口的所有抽象方法(接口中的方法默认都为抽象方法),且必须加上public关键字
  一个类可以实现多个接口(继承和实现,遵循java的先继承再实现)
接口是一种标准、规范,实现了该接口就具备该功能,若不实现该接口就不具备该功能,要使用该接口必就须遵循该接口的标准规范
接口是对java类继承的单根性扩展 —— 实现了多继承(java接口是支持多继承的)
  • 接口一般包含抽象方法,即java接口中的方法一般默认为(前面默认有abstract关键字)抽象方法(常量,默认方法,静态方法,私有方法等)
    • 将所有子类所共有的属性和行为,抽到父类中(抽共性)
    • 若子类的行为(类方法)/代码都一样,设计为普通方法
    • 若子类的行为(类方法)/代码不一样,设计为抽象方法
    • 将子类所共有的行为,抽到接口中

接口的实现,类的继承,方法的抽象

  • Swimming接口
package oop.interfaces;

// 创建Swimming接口
public interface Swimming {
    // 定义swim抽象方法(抽象方法没有{})
    void swim();
}
  • 父类Animal
package oop.interfaces;
// 创建动物类
public class Animal {
    // 父类属性
    String name;
    int age;
    String color;

    // 父类无参构造器
    Animal(){}
    // 父类有参构造器
    Animal(String name, int age, String color){
        this.name = name;
        this.age = age;
        this.color = color;
    }
    void eat(){
        System.out.println(name + "在吃饭");
    }
}

  • 子类1 Dog继承Animal实现接口Swimming
package oop.interfaces;

public class Dog extends Animal implements Swimming{
    // 子类无参构造器
    Dog(){}
    // 子类有参构造器
    Dog(String name, int age, String color){
        // 引用父类有参构造器
        super(name, age, color);
    }
    // 重写父类方法(功能拓展)
    void eat(){
        System.out.println(color + name + "在吃饭");
    }

    // 重写接口抽象方法
    @Override
    public void swim() {
        System.out.println(age + "岁的" + name + "在游泳");
    }
}
  • 子类1 Fish继承Animal实现接口Swimming
package oop.interfaces;

public class Fish extends Animal implements Swimming{
    // 子类无参构造器
    Fish(){}
    // 子类有参构造器
    Fish(String name, int age, String color){
        // 引用父类有参构造器
        super(name, age, color);
    }
    // 重写父类方法(功能拓展)
    void eat(){
        System.out.println(color + name + "在吃饭");
    }

    // 重写接口抽象方法
    @Override
    public void swim() {
        System.out.println(age + "岁的" + name + "在游泳");
    }

}
  • 员工管理简单设计图(类和接的继承以及接口的实现)
    在这里插入图片描述
  • 部分代码
package test;

public class CodeTiny06 {
    public static void main(String[] args) {
        Majordomo liming = new Majordomo();
        liming.name = "李明总监";
        liming.working();
        liming.offDuty();
        liming.completeTask();
        liming.edit_ooks();
        liming.solveProblem();
    }
}

// 员工类
abstract class Employee{
    String name;
    int age;
    double salary;

    public Employee() {
    }

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    void working(){
        System.out.println("上班打卡");
    }
    void offDuty(){
        System.out.println("下班打卡");
    }

    abstract void completeTask();
}

// 接口1
interface Books{
    void edit_ooks();
}
// 接口2
interface Solve extends Books{
    // 解决问题
    void  solveProblem();
    // 培训员工
    void train();
}

// 总监类的实现
class Majordomo extends Employee implements Solve{
    // 无参
    public Majordomo() {
    }

    // 有参
    public Majordomo(String name, int age, double salary) {
        super(name, age, salary);
    }

    // 父类方法重写
    @Override
    void completeTask() {
        System.out.println("完成总监的工作");
    }

    // 接口2继承接口1的方法重写
    @Override
    public void edit_ooks() {
        System.out.println(name + "在编辑书籍!");
    }
    // 接口2的方法重写
    @Override
    public void solveProblem() {
        System.out.println(name + "解决问题");
    }

    @Override
    public void train() {
        System.out.println(name + "在培训员工");
    }
}

// 其他教师类,项目经理类,班主任类的实现类似
9. 引用类型数组
引用类型数组:数据类型是引用数据类型的数组
  • 引用类型数组的类型
package oop.quote;

// 创建引用类
public class Word {
    // 单词
    String word;
    // 词性
    String speech;
    // 次数
    int counts;

    public Word() {
    }

    public Word(String word, String speech, int counts) {
        this.word = word;
        this.speech = speech;
        this.counts = counts;
    }
}
  • 引用类型数组的实现
package oop.quote;

public class ReferArray {
    public static void main(String[] args) {
        String[] strings = {"接口", "是", "一种", "标准", "规范"};
        String[] string = {"n", "v", "n", "n", "n"};
        // 创建引用类型数组
        Word[] words = new Word[5];
        for (int i = 0; i < words.length; i++) {
            words[i] = new Word(strings[i], string[i],1);
            System.out.println(words[i].word + "   " + words[i].speech + "   " + words[i].counts);
        }
    }
}
10. 多态
  ➤ 多态:使用父类的引用来引用子类对象,并在运行时动态地确定具体调用的方法,进而实现多种形态
多态的两个关键点:继承和方法重写
核心:父类引用指向子类对象
  ▶ 向上造型(Upcasting):一个子类对象赋值给一个父类引用变量的过程(多态性的特性)
  ▶ 向下转型(Downcasting):① 引用所指的对象是该类型;② 引用所指的对象实现了该接口或者继承了该类

  多态的实际应用
  ▶ 超类数组(实现代码复用):将不同子类对象统一封装到父类数组(引用类型(父类)数组,子类实例元素)
  ▶ 超类参数/返回值(参数多态,扩大应用范围)将父类作为参数或者返回值类型,进而出入/返回子类对象
package working;

import oop.polymorphism.Animal;

public class Work12 {
    public static void main(String[] args) {
        // 方法参数多态(向上造型)
        Master master = new Master();
        Dog1 dog1 = new Dog1("小黑",2,"黑");
        Pandas panda = new Pandas("花花",3,"花");
        Fishs fish = new Fishs("小金",1,"金");
        master.feed(dog1);
        master.feed(panda);
        master.feed(fish);


        // 数组元素多态(向上造型)
        Animal1[] animals = new Animal1[5];
        animals[0] = new Dog1("小黑", 2, "黑");
        animals[1] = new Dog1("小白", 1, "白");
        animals[2] = new Fishs("小金", 1, "金");
        animals[3] = new Fishs("金鱼", 2, "金");
        animals[4] = new Pandas("花花", 3, "黑白");
        for (int i = 0; i < animals.length; i++) {
            System.out.println(animals[i].name);
            // 所有动物均会吃东西和喝水
            animals[i].eat();
            animals[i].drink();
            // 狗的特有属性
            if (animals[i] instanceof Dog1) {
                Dog1 dog = (Dog1) animals[i];
                dog.lookHome();
            }
            // 熊猫的特有属性
            if (animals[i] instanceof Pandas) {
                Pandas pandas = (Pandas) animals[i];
                pandas.show();
            }
            // 拥有游泳特性的动物
            if (animals[i] instanceof Swim) {
                Swim s = (Swim) animals[i];
                s.swim();
            }
        }
    }
}

abstract class Animal1 {
    String name;
    int age;
    String color;

    Animal1() {
    }

    Animal1(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    void drink() {
        System.out.println(color + "色的" + age + "岁的" + name + "正在喝水...");
    }

    abstract void eat();
}

interface Swim {
    void swim(); //游泳
}

class Dog1 extends Animal1 implements Swim {
    Dog1() {
    }

    Dog1(String name, int age, String color) {
        super(name, age, color);
    }

    void lookHome() {
        System.out.println(color + "色的" + age + "岁的狗狗" + name + "正在看家...");
    }

    void eat() {
        System.out.println(color + "色的" + age + "岁的狗狗" + name + "正在吃骨头...");
    }

    public void swim() {
        System.out.println(color + "色的" + age + "岁的狗狗" + name + "正在游泳...");
    }
}

class Pandas extends Animal1 {
    public Pandas() {
    }

    public Pandas(String name, int age, String color) {
        super(name, age, color);
    }

    void show(){
        System.out.println("熊猫" + name + "在表演");
    }

    @Override
    void drink() {
        super.drink();
    }

    @Override
    void eat() {
        System.out.println(color + "色的" + age + "岁的熊猫" + name + "正在吃竹子...");
    }
}

class Fishs extends Animal1 implements Swim {
    Fishs() {
    }

    Fishs(String name, int age, String color) {
        super(name, age, color);
    }

    void eat() {
        System.out.println(color + "色的" + age + "岁的小鱼" + name + "正在吃小虾...");
    }

    public void swim() {
        System.out.println(color + "色的" + age + "岁的小鱼" + name + "正在游泳...");
    }
}

class Master {
    // (喂动物方法)传入父类类型(利用多态的特性,扩大了方法的应用范围 )-- 方法参数多态
    void feed(Animal1 animal) {
        // 子类继承父类的方法属性
        animal.eat();
    }
}

11. 内部类
➤ 内部类:内部类是定义在其他类内部的类
四种内部类:成员内部类、局部内部类、匿名内部类、静态内部类
特性:可以访问外部类的成员变量和方法,并且可以拥有自己的成员变量和方法(内部类通常只服务于外部类,对外不具备可见性)
▶ 内部类的意义:实现更好的封装性和组织代码结构(内部类可以访问外部类的私有成员,并且可以在需要时提供更好的代码逻辑组织方式)

成员内部类(Member Inner Class)
    成员内部类是定义在一个类的内部的普通类。它可以访问外部类的所有成员,包括私有成员
    内部类的对象通常在外部类中创建

内部类中可以直接访问外部类的成员原因:在内部类中有个隐式的引用指向创建它的外部类对象
隐式的引用:外部类名.this
▶ 成员内部类使用场景:若A类只让B类用,并且A类还想访问B类的成员
    ▶ this:指代当前对象
    ▶ super:指代当前对象的超类对象
    ▶ 外部类名.this:指代当前对象的外部类对象

   public class OuterClass {
       // 外部类的代码
		String name;
		void methed(){
		// 内部类对象通常在外部类中创建
		InnerClass inners = new InnerClass();
		}
       public class InnerClass {
           // 内部类的代码(可以直接使用外部类的属性方法)
           System.out.println(name);
           // 隐式的引用:外部类名.this
           // 完整写法(上面省略了OuterClass.this.)
           System.out.println(OuterClass.this.name);
       }
   }

局部内部类(Local Inner Class)
    局部内部类是定义在方法内部或代码块内部的类
    局部内部类的作用范围限定在所在的方法或代码块内部
    局部内部类可以访问所在方法或代码块的局部变量,但是该局部变量必须是final或 effectively final 的

   public class OuterClass {
       // 外部类的代码

       public void someMethod() {
           // 方法代码

           class LocalInnerClass {
               // 局部内部类的代码
           }
       }
   }

匿名内部类(Anonymous Inner Class)
    匿名内部类是没有显式名称的内部类
    匿名内部类通常用于实现接口或继承抽象类,并且只能创建该接口或抽象类的一个实例
    匿名内部类可以直接在代码中创建,不需要先定义再使用

使用场景:创建一个派生类的对象,并且对象只创建一次
作用:简化代码
在匿名内部类中不能修改外面局部变量的值(在内部)
内部类也有独立的.class字节码文件外部类名$匿名内部类编号.class
在这里插入图片描述
在这里插入图片描述

  • 匿名内部类
package oop.inners;

public class InnerClass {
    public static void main(String[] args) {
        // 匿名内部类(使用场景:创建一个派生类的对象,并且对象只创建一次)
        /*
         * new Inter(){}是一个(没有名字)的子类
         * Inter(父类)类型 inter(Inter类型的引用) = new Inter(){}子类(多态)
         * 只能创建一个对象,再次创建属于新的子类(与第一次建的子类不是同一个)
         * Inter(父类) inter(父类类型的引用) =(指向) new Inter(){}(子类类体)(创建的子类);
         */
        Inter inter = new Inter(){};

        // 创建匿名内部类对象
        Inters inters = new Inters(){
            @Override
            public void show() {
                System.out.println("这是匿名内部类中的方法(来源于接口的方法重写)");
            }
        };
        // 方法调用
        inters.show();
    }
}

// 接口Inter
interface Inter{
    // 接口(抽象类)不能被实例化
}

// 接口Inters
interface Inters{
    // 接口(抽象类)不能被实例化
    // 抽象方法
    void show();
}

静态内部类(Static Inner Class)
    静态内部类是定义在其他类内部的静态类
    静态内部类类似于外部类的静态成员,不依赖于外部类的实例
    静态内部类可以直接通过外部类访问,不需要创建外部类的实例

   public class OuterClass {
       // 外部类的代码

       public static class StaticInnerClass {
           // 静态内部类的代码
       }
   }
12. package和import
➤ package:用于声明包
作用:避免类的命名冲突
规定:同包中的类不能同名,但不同包中的类可以同名
▶ 类的全称:包名.类名,包名常常用层次结构
▶ 建议:包名所有字母都小写
➤ import:用于导入类
作用:访问不同包中的类,使代码简洁化
▶ 建议:import导入类,再访问类

构造方法与普通方法
构造方法是一种特殊类型的方法,用于创建和初始化对象,在实例化类时被自动调用,与类的名称相同,并没有返回类型
  方法名称与类名相同:构造方法的名称必须与类的名称完全相同,包括大小写
  没有返回类型:与其他方法不同,构造方法不具有返回类型,甚至没有声明 void
  不能使用 return 语句:由于构造方法没有返回类型,因此不能使用 return 语句
  可以重载:你可以在一个类中定义多个构造方法,只要它们的参数列表不同

普通方法是用于执行类中特定任务或操作的常规方法。普通方法可以有任意的名称、参数和返回类型,并且与构造方法存在明显的区别。普通方法可以被对象调用,通过对象引用.方法名的形式来调用

13. 访问控制修饰符
访问控制修饰符指定了类、接口、变量、方法和构造函数的可见性和访问级别
作用:保护数据的安全(隐藏数据、暴露行为),实现封装
设计:数据(成员变量)私有化(private),行为(方法)大部分公开化(public)
▶ 类的访问权限:只能是public或默认的c
▶ 成员的访问权限:4种访问控制修饰符都可以
➤ Java四种访问控制修饰符:private,默认的,protected,public
▶ public:公开的,任何类
▶ private:私有的,本类
▶ protected:受保护的,本类、派生类、同包类
▶ default:默认的,什么也不写,本类同包类

标准JavaBean

  1. 属性私有
  2. 具有无参数的公共构造函数
  3. 提供公共的访问属性的get/set方法
  • 标准的JavaBean
package oop.encapsulation;

public class Point {
    /* 属性私有
     * 具有无参数的公共构造函数
     * 提供公共的访问属性的get/set方法
     */
     // 属性私有
    private int x;
    private  int y;

    public Point() {
    // 无参数的公共构造函数
    }

    public int getX() {
    // 更好的保证数据的合法性(因为方法中可以做条件控制制)
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

标准JavaBean的命名和规范
    命名规范
      类名应该使用大写字母开头,且不包含下划线或其他特殊字符
      应该具有无参数的公共构造函数
      应该提供有意义的get/set方法,遵循命名规范
    属性规范
      属性应该是私有的,并使用private修饰符进行封装
      属性的命名应该使用小写字母开头,可以采用驼峰式命名规则
      对于布尔类型的属性,get方法应该以is开头而不是get
    公共方法规范
      应该提供公共的访问属性的get/set方法
      可以根据需要添加其他自定义的公共方法

变量修饰符(访问权限修饰符、非访问权限修饰符):指定变量的访问权限和其他属性
  访问权限修饰符
      private:私有的变量只能在声明它们的类内部访问
      protected:受保护的变量可以在当前类、同一个包内的其他类以及子类中访问
      public:公共的变量可以在任何地方被访问
  非访问权限修饰符
      final:final修饰的变量表示常量,其值不能被修改
      static:static修饰的变量属于类级别,而不是实例级别,在类加载时初始化,并且可以通过类名直接访问
      transient:transient修饰的变量在序列化过程中会被忽略,不会被保存
      volatile:volatile修饰的变量用于多线程环境中,保证了对变量的可见性和禁止指令重排序优化

成员变量(实例变量和静态变量)
     实例变量:没有static修饰,属于对象,存储在堆中,有几个对象就有几个实例变量,访问:引用/对象.变量名
     静态变量:用static修饰,属于类,存储在方法区中,只有一个,访问:类名.变量名,(对象所共享的数据)

静态代码块 由static修饰的代码块
     特点:1. 属于类,在类被加载时自动执行,用于初始化静态成员变量或执行其他静态操作
        2. 静态代码块只在类加载第一次时执行一次(第二次加载该类不执行),且只能执行静态操作
        3. 静态代码块与静态成员变量、静态方法属于类级别(通过类名直接访问)
        4. 静态代码块按照它们在类中出现的顺序依次执行(在无参构造方法之前执行)

  • 静态变量
public class MyClass {
    private static int count;  // 静态变量

    public static void main(String[] args) {
        count = 10;  // 直接访问静态变量
        System.out.println("count = " + count);

        MyClass obj1 = new MyClass();
        MyClass obj2 = new MyClass();

        obj1.count = 20;  // 使用对象访问静态变量,不推荐
        System.out.println("obj1.count = " + obj1.count);
        System.out.println("obj2.count = " + obj2.count);
    }
}
  • 静态代码块
public class MyClass {
    static {
        // 静态代码块中的代码
        System.out.println("静态代码块执行");
    }

    public static void main(String[] args) {
        // main方法中的代码
        System.out.println("main方法执行");
        MyClass myClass = new MyClass();
    }
}

静态方法 在类级别上定义的由static修饰的方法,不依赖于任何对象的实例
     特点:1. 静态方法属于类(不依赖于任何具体的对象实例)
        2. 静态方法只能访问静态成员(静态变量和静态方法)
        3. 静态方法中不能有关键字this(this代表当前对象的引用,而静态方法不依赖于对象)
        4. 静态方法可以直接从类中调用,无需创建对象实例(静态方法与对象无无关)
        5. 静态方法不能被子类重写,但可以被继承并隐藏
在这里插入图片描述

  • StaticMethod
package oop.encapsulation;

public class StaticMethod {
    int n;
    static int m;

    void show(){
        System.out.println(n);
        System.out.println(m);
    }

    // 静态方法
    static void test(){
        // System.out.println(n);
        System.out.println(m);
    }
}
  • StaticBlock
package oop.encapsulation;

public class StaticBlock {
    String name;
    int age;
    static String className;

    // 静态代码块的作用(初始化静态变量)
    static {
        // 只加载一次(如游戏的第一次资源加载,第二次启动时不再加载静态资源)
        className = "2023001班";
    }
    // 无参构造
    StaticBlock(){}
    // 有参构造
    StaticBlock(String name, int age){
        this.name = name;
        this.age = age;
    }
    void show(){
        System.out.println("姓名:" + name + "  年龄:" + age + "  班级:" + className);
    }
}
  • StaticVar
package oop.encapsulation;

public class StaticVar {
    // 实例变量
    int a;
    // 静态变量
    static int b;

    public StaticVar() {
        a++;
        b++;
    }

    void show() {
        System.out.println("a的值:" + a + "   b的值:" + b);
    }
}

  • Test
package oop.encapsulation;

public class Test {
    public static void main(String[] args) {
        // javabean
        Point a = new Point();
        // 设置a点的值
        a.setX(100);
        a.setY(200);
        // 获取点a的值求和
        int sum = a.getX() + a.getY();
        System.out.println("和:" + sum);

        // 静态变量
        StaticVar var = new StaticVar();
        var.show();

        // 静态代码块
        StaticBlock student = new StaticBlock("李四", 22);
        student.show();

        // 静态方法的访问
        StaticMethod method = new StaticMethod();
        // 通过对象访问普通方法show()
        method.show();
        // 通过类名访问静态方法test()
        StaticMethod.test();
    }
}
14. 常量和枚举
➤ 常量:由static和final修饰的成员变量
特性:1. 必须在声明的同时初始化
   2. 通过类名来访问 类名.常量名
   3. 常量的值一旦被初始化后就不能再修改
   4. 常量通常用大写字母表示,多个单词之间使用下划线分隔
常量在编译时会直接被替换成具体的数(效率高)

➤ 枚举(Enum):一种特殊的数据类型,用于表示一组具有固定数量和值的常量集合
▶ 枚举类型:Java中被定义为一种特殊的类,其中每个枚举常量都是类的实例(枚举类型可以包含属性、方法、构造函数等成员)
▶ 特点:枚举不能继承其他类(默认已经继承了java.lang.Enum类)
枚举的构造方法都是私有的
  • 简单枚举Seasons
package oop.Enums;

public enum Seasons {
    // 季节的固定4个对象(常量)
    SPRING, SUMMER, AUTUMN, WINTER;
}
  • 复杂枚举Week
package oop.Enums;

public enum Week {
    MONDAY("星期一", 1),
    TUESDAY("星期二", 2),
    WEDNESDAY("星期三", 3),
    THURSDAY("星期四", 4),
    FRIDAY("星期五", 5),
    SATURDAY("星期六", 6),
    SUNDAY("星期日", 7);
    private String weekName;
    private int num;

    Week(String weekName, int num) {
        this.weekName = weekName;
        this.num = num;
    }

    public String getWeekName() {
        return weekName;
    }

    public void setWeekName(String weekName) {
        this.weekName = weekName;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
  • 枚举测试
package oop.Enums;

public class Test {
    public static void main(String[] args) {
        // 获取某一元素做操作
        Seasons season = Seasons.AUTUMN;
        System.out.println("秋天:" + season);


        // 获取所有对象
        Seasons[] seasons = Seasons.values();
        for (int i = 0; i < seasons.length; i++) {
            switch (seasons[i]) {
                case SPRING:
                    System.out.println("春天:" + seasons[i]);
                    break;
                case SUMMER:
                    System.out.println("夏天:" + seasons[i]);
                    break;
                case AUTUMN:
                    System.out.println("秋天:" + seasons[i]);
                    break;
                case WINTER:
                    System.out.println("冬天:" + seasons[i]);
            }
        }

        // 复杂枚举
        Week week = Week.MONDAY;
        System.out.println(week.getWeekName() + week.getNum());

        Week[] weeks = Week.values();
        for (int i = 0; i < weeks.length; i++) {
            System.out.println(weeks[i].getWeekName() + " 第" + weeks[i].getNum() + "天");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一半不眠次日si记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值