java全端课3--java-面向对象(中)

一、类的成员之三:构造器(必须掌握)

1.1 构造器有什么用

构造器的作用是为实例对象的实例变量初始化。在new对象的时候用。

1.2 构造器长什么样?

  • 构造器的名称必须与所在的类名完全一致,包括大小写。
  • 构造器没有返回值类型。不写void,也不写int,String等类型。一旦你写了返回值类型,它就是普通方法。

1.3 构造器有什么特点或要求?

  • 所有类都有构造器
  • 如果一个类没有手动编写构造器,那么编译器会给你自动添加一个默认的无参构造。
  • 但是如果我们手动编写了构造器,那么编译器就不会再给你添加任何构造器了。
  • 构造器可以重载。构造器有时候也叫做构造方法,或构造函数。
  • 构造器的修饰符只能是public、protected、缺省、private,不能加其他修饰符(static,final,abstract等)

1.4 构造器如何快速的创建?

Alt + Insert

二、面向对象的基本特征之一:封装

2.1 为什么要封装?

生活中,快递为什么有包装盒/包装袋?

  • 私密性:保护隐私
  • 安全性:避免损坏
  • 方便运输
  • ......

Java中的类及其成员,也需要封装:

  • 广义的封装概念:边界感,

    • 例如:把一类事物的共同特征封装到一个类中,把一个完整的功能封装到一个方法中。
    • 组件之间的封装,例如:项目中用到第三方的支付功能,微信、支付宝、银行等,只能调用对方开放的接口,无法获取内部的实现细节。
  • 狭义的封装:对类或成员加权限修饰符,控制它们的可见性范围

    • 隐藏实现细节,便于使用
    • 安全
arduino 复制代码
package com.test.constructor;

public class Student {
    private String name;//属性私有化
    private int age;//属性私有化

    public Student() {//无参构造
    }

    public Student(String name, int age) {//有参构造
        this.name = name;
        this.age = age;
    }

    public void setAge(int age){
        if(age >= 18 && age<=35) {
            this.age = age;
        }else{
            System.out.println("年龄不合法!");
        }
    }

    public String getInfo(){
        return "姓名:" + name +",年龄:" + age;
    }
}
csharp 复制代码
package com.test.constructor;

public class TestStudent {
    public static void main(String[] args) {
        //调用Student类的无参构造创建Student对象
        Student s1 = new Student();
        System.out.println(s1.getInfo());

        //调用Student类的有参构造创建Student对象
        Student s2 = new Student("张三",23);
        System.out.println(s2.getInfo());

        //s2.age = -18;//不安全
        s2.setAge(-18);//安全
        System.out.println(s2.getInfo());

        s2.setAge(30);//安全
        System.out.println(s2.getInfo());
    }
}

2.2 四种权限修饰符

对类或成员加权限修饰符,控制它们的可见性范围。

private(私有的) 缺省(不写) protected(受保护) public(公共的)
本类 √ √ √ √
本包其他类 × √ √ √
其他包的子类(继承) × × √ √
其他包的非子类 × × × √

2.3 get/set方法

  • set方法:修改某个或某些属性的值

    • 如果是静态变量的set方法,那么出现局部变量与静态变量重名时,通过"类名.静态变量"进行区分
    • 如果是实例变量的set方法,那么出现局部变量与实例变量重名时,通过"this.实例变量"进行区分
  • get方法:获取某个或某些属性的值

    • 如果某个属性的类型是boolean,那么它的get方法,一般以is开头。

❝

问:有构造器,和get/set会不会冲突?

答:构造器在new对象时,赋初始值。

  • set方法在new对象后,用于修改属性的值。
  • get方法在new对象后,用于获取某个属性的值。
  • 用快捷键生成构造器、get/set方法 Alt + Insert

三、标准Javabean

bean:豆。

Java:产咖啡的印尼的爪哇岛。

Javabean:咖啡豆,Java类。

什么是标准Javabean?

  • 属性私有化
  • 提供无参构造器。有参构造可选。因为后期Java对象的创建通常都是交给Spring等框架,而这些框架默认都是用无参构造创建对象。
  • 提供合适的get/set方法
  • 重写 equals和hashCode,toString方法
ini 复制代码
package com.test.bean;

import java.util.Objects;

public class Employee {
    private int id;
    private String name;
    private int age;
    private char gender;
    private double salary;
    private String tel;
    private String address;

    public Employee() {
        System.out.println("一个新员工入职");
    }

    public Employee(int id, String name, int age) {
        this();//调用本类的其他构造器,调用无参构造
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Employee(int id, String name, int age, char gender, double salary, String tel, String address) {
//        this.id = id;
//        this.name = name;
//        this.age = age;
        this(id,name,age);//调用本类的其他构造器,调用有参构造
        this.gender = gender;
        this.salary = salary;
        this.tel = tel;
        this.address = address;
    }
    
    //... 省略 get set...
    
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", age=" + age +
                ", gender=" + gender +
                ", salary=" + salary +
                ", tel='" + tel + ''' +
                ", address='" + address + ''' +
                '}';
    }
    
    //作用要明确,用于比较两个Employee对象的属性值是不是相同
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;
        return id == employee.id && age == employee.age && gender == employee.gender && Double.compare(salary, employee.salary) == 0 && Objects.equals(name, employee.name) && Objects.equals(tel, employee.tel) && Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + Objects.hashCode(name);
        result = 31 * result + age;
        result = 31 * result + gender;
        result = 31 * result + Double.hashCode(salary);
        result = 31 * result + Objects.hashCode(tel);
        result = 31 * result + Objects.hashCode(address);
        return result;
    }
}
csharp 复制代码
package com.test.bean;

public class TestEmployee {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee(2,"熊二",25);
        Employee e3 = new Employee(3,"张三",23,'男',15000,"10086","北京");


        //toString()作用等价于原来的getInfo()
        //但是它比getInfo()方便,打印对象时,不用手动调用,它会自动调用
/*        System.out.println(e1.toString());
        System.out.println(e2.toString());
        System.out.println(e3.toString());*/
        System.out.println(e1);//如果没有写toString方法,那么打印的是地址值
        System.out.println(e2);
        System.out.println(e3);

        Employee e4 = new Employee(2,"熊二",25);
        System.out.println(e2 == e4);//false
        //e2和e4是地址值,这里比较的是两个对象的地址值
        System.out.println(e2.equals(e4));//比较两个对象是否相等  false
        //默认情况下,equals等价于 ==
        //如果不想让equals方法等价于==,就必须重写
        System.out.println(e1.equals(e2));//false
    }
}

四、对象数组

1、什么是对象数组

把对象存到数组中,这样的数组就称为对象数组。其实,它和普通的数组是一样的,只是因为对象数组使用起来相对复杂一点。

2、如何声明和使用

ini 复制代码
元素的类型[] 数组名; //此时元素的类型是类类型,例如:Student,Rectangle,String等

静态初始化:

ini 复制代码
元素的类型[] 数组名 = {对象1,对象2,对象3};

动态初始化:

ini 复制代码
元素的类型[] 数组名 = new 元素的类型[长度];

数组的遍历:

css 复制代码
for(int i=0; i<数组名.length; i++){
    数组名[i]是元素,此时元素是对象
}

五、面向对象的基本特征之二:继承

5.1 什么是继承?

生活中:

  • 基因
  • 财产
  • 才艺

继承:延续性、扩展性

继承上一代的优良传统,并发扬光大。青出于蓝而胜于蓝。

Java中为什么要有继承的设计呢?

  • 代码的复用性:子类可以复用父类的代码
  • 代码的扩展性:子类可以重写父类的方法或扩展父类没有的成员
  • 表示事物之间的is-a关系。例如:Student类继承Person类,Student is a Person.学生类是人类的一个分支。

5.2 如何继承?(重要)

arduino 复制代码
【修饰符】 class 父类{
    
}
javascript 复制代码
【修饰符】 class 子类 extends 父类{//子类是从父类中延伸出来的新的分类,更具体的分类
    
}

父类:SuperClass,称为父类或超类 ,基类。

子类:SubClass,称为子类或派生类。

5.3 继承的特点或要求(重要)

1、Java中只允许单继承。比喻:每一个子类只有1个亲生父亲。

2、但是Java中支持多层继承。比喻:代代相传。你的父亲仍然有父亲。爷爷的特征到孙子类仍然是保留的。

3、Java中一个父类可以同时有多个子类。比喻:支持多胎。支持家族兴旺。

4、父类的所有成员变量、成员方法都会继承到子类中。因为成员变量代表事物的数据特征,成员方法代表事物的行为/功能特征,而子类是父类这个事物分类下的一个分支,所以这些特征都会延续下来。但是,父类中私有的成员变量、成员方法,在子类中不能直接使用,可以间接使用。

5、父类的构造器不会继承到子类中。但是,子类的构造器中又必须调用父类的构造器。因为子类继承了父类声明的所有成员变量,那么创建子类对象时就需要为这些成员变量初始化,而为这些成员变量初始化的代码已经在父类的构造器中写过了,可以不用重复编写这些代码了,直接调用它们即可。

  • super():表示调用父类的无参构造。这句代码可以省略。
  • super(实参列表):明确表示调用父类的有参构造。这句代码不能省略,一旦省略,就表示调用无参构造了。
  • 它们必须在子类构造器的首行。

案例一:子类直接用父类的成员

arduino 复制代码
package com.test.inherited;

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

    public String getPersonInfo(){
        return "姓名:" + name + ",年龄:" + age;
    }
}
java 复制代码
package com.test.inherited;

public class Student extends Person{

    public int score;//成绩

    public String getStudentInfo(){
        return "姓名:" + name + ",年龄:" + age +",成绩:" + score;
        //直接使用父类非private的属性
    }
}
java 复制代码
package com.test.inherited;

public class Student extends Person{

    public int score;//成绩

    public String getStudentInfo(){
        return getPersonInfo() +",成绩:" + score;
        //间接使用父类非private的方法
    }
}

案例二:子类间接使用父类的成员

arduino 复制代码
package com.test.inherited;

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

    public String getPersonInfo(){
        return "姓名:" + name + ",年龄:" + age;
    }
}
ruby 复制代码
package com.test.inherited;

public class Student extends Person{

    public int score;//成绩

    public String getStudentInfo(){
        //return "姓名:" + name + ",年龄:" + age +",成绩:" + score;
        //报错,因为name和age此时在父类Person中是private
        return getPersonInfo() +",成绩:" + score;
        //直接调用父类的方法,从而间接使用父类的私有属性
    }
}

5.4 方法的重写(重要)

1、什么是方法的重写?

方法的重写(Override)是指子类覆盖/重写/覆写父类的某个方法。因为子类会继承父类的所有方法,但是某些方法的方法体功能实现不适用于子类,那么子类就可以重新实现它。

2、如何重写方法?

  • 修饰符:

    • 权限修饰符:public、protected、缺省、private,其中private的方法是不能被重写的。并且子类重写时,方法的权限修饰符必须大于等于父类被重写方法的权限修饰符。

      • 父类被重写方法是public,子类这个方法只能是public。
      • 父类被重写方法是protected,子类这个方法可以是public,protected
      • 父类被重写方法是缺省,子类这个方法可以是public,protected,缺省
    • 其他修饰符:static,静态方法不能被重写。

  • 返回值类型:

    • void和基本数据类型:子类必须保持一致

    • 引用数据类型:子类重写时,方法的返回值类型可以是小于等于它

      • 例如父类被重写方法的返回值类型是Person,那么子类重写方法的返回值类型可以是Person,也可以是Student
  • 方法名:必须完全相同

  • 形参列表:必须完全相同,这里相同是指类型、个数、顺序。不包括形参名。

  • 方法体:子类重写就是为了重新实现方法体,根据功能的需求来。

3、如何调用父类被重写的方法?

super.父类被重写方法

4、方法重载与重写的区别

方法的重载 方法的重写
位置 同一个类 或 父子类 父子类
英文单词 Overload Override
修饰符 不看 不能重写private和static的方法。权限修饰符必须满足 >=
返回值类型 不看 void和基本数据类型:必须相同 引用数据类型:满足<=
方法名 必须相同 必须相同
形参列表 必须不同 必须相同

5.5 根父类(了解)

Object是java.lang包下的一个类,它是所有Java类的根,老祖宗。我们称为根父类。

Object类的方法,所有子类都会继承,即所有子类都有这些方法。但是,对于toString,equals和hashCode方法来说,子类通常都会重写。

java 复制代码
//重写equals,hashCode,toString
//快捷键Alt + Insert 或 Ctrl + O
    @Override  //这个是注解。它是用于标记以下方法是重写的意思,它会告诉编译器,让编译器对该方法做严格的格式检查,看它是否满足重写的要求
               //但是,如果你本身没有违反重写的要求,@Override可以去掉。
                //加或不加@Override它,不影响重写的本质。只是格式检查是不是彻底的问题。
                //建议重写方法上保留它。

5.6 特殊关键字

5.6.1 native(了解)

native修饰的方法,称为本地方法,或内置的方法,它是内置在JVM相关的底层代码中,通过C/C++语言实现的,不是用Java语言实现。在Java层面看不到它的方法体。

本地方法的执行会自动调用本地方法库。本地方法的执行会在本地方法栈中开辟独立的内存空间。Java虚拟机中的栈空间分为两块:虚拟机栈(服务于Java的方法)和本地方法栈(服务于C/C++的函数)。

❝

提示:native的方法,虽然看不到它的源码,但是(1)在Java中可以正常调用。(2)如果子类继承了本地方法,只要它不是private,不是static,不是final,子类可以对它用Java代码进行重写。即本地方法在使用层面,把它当成普通的方法即可。

5.6.2 final(重要)

final:最终。

在Java中,它是修饰符,可以用于修饰:类、方法、变量。

修饰符类 修饰符方法 修饰变量
作用 这个类不能被继承(比喻:太监类) 这样的方法不能被重写(可以被继承) 这样的变量称为常量,值不能被修改。
举例 String,Math,System等 Object类中的getClass()

❝

对于final修饰变量来说:

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

(2)静态变量 + final 建议大写,其他的变量加final一般不大写

(3)静态变量和实例变量 + final之后,它们都没有set方法,可以有get方法

(4)实例变量 + final,可以在变量后面直接写 = 值,也可以在构造器中进行初始化。

修改单词大小写的快捷键:Ctrl+Shift+U

六、抽象类(重要)

6.1 什么是抽象类?

语法层面来说:有abstract修饰的类,就是抽象类。

csharp 复制代码
【权限修饰符】 abstract class 类名{
    
}

6.2 为什么要有抽象类?

父类是代表很多子类共同的特征,把很多子类共同的属性、方法抽取到父类中,从而避免在不同的子类中重复声明。

随着父类共同方法的抽取越来越抽象,就会出现抽象方法,即在父类中写不了具体方法体的方法,这样方法必须用abstract修饰,表示没有方法体的抽象方法,Java中规定,包含抽象方法的类必须是抽象类,这样的类是不能直接new对象的。

不能对抽象类直接new,如果可以 new 对象,就可以直接通过对象调用抽象方法,但是抽象方法没有方法体可执行。

❝

问:抽象类有构造器吗?

答:一定有。此时构造器是给子类用的。

6.3 抽象类怎么用

抽象类的存在的意义:

  • 它代表所有子类共同的特征

  • 抽象类就是用来被继承的,子类继承抽象类,必须重写抽象类的所有抽象方法,否则子类也是是抽象类

  • 重新父类抽象方法快捷键

    • Ctrl + O 可以重写父类抽象的和非抽象的方法
    • Ctrl + I 重写父类的抽象方法

七、接口(重要)

7.1 什么是接口?

生活中:USB接口,电源插座的接口等,代表连接口。其实还代表了"标准"规范的意思。

Java中的接口也是代表(1)连接口(2)行为规范,方法的规范。

例如:后期做项目时,会调用银行接口,支付宝接口,微信支付接口来完成支付功能。

例如:后端服务器与前端的界面之间要约定双方传数据的规范,标准,这是也是接口的一部分。

从语法层面,说接口是用interface关键字声明的类型。

7.2 如何声明接口

csharp 复制代码
【修饰符】 interface 接口名{
    
}

7.3 接口的成员

回忆类的成员:

scss 复制代码
(1)成员变量:静态变量和实例变量
(2)成员方法:静态方法和非静态方法
(3)构造器:无参构造和有参构造
(4)代码块
(5)内部类

接口的成员有限制,明显与类不同:

JDK8之前:

  • 公共的静态的常量:public static final (3个关键字可以省略),因为接口是代表一种标准规范,那么具体的值必须是明确的,写死的。
  • 公共的抽象方法`:public abstract(2个关键字可以省略),因为接口是代表一种标准规范,只是说它有什么功能,但是功能的具体实现要有子类来实现。抽象方法是没有方法体,子类必须实现/重写它。

JDK8之后:

  • 公共的静态方法:public static(其中public可以省略,static不能省略),静态方法必须有方法体。静态方法的调用不需要接口的对象。

  • 公共的默认方法:public default(其中public可以省略,default不能省略)

    • 为了接口的升级,Java允许定义默认方法。默认方法是可以写方法体的,子类可以选择实现它,也可以选择不实现它。
    • 如果没有默认方法,按照之前的语法规则,接口中只能增加抽象方法,一旦父接口增加抽象方法,就会影响所有的实现类。

JDK9之后:

  • 私有的方法(了解):用于表示接口中内部使用的方法,通常是因为两个静态方法,或两个默认方法之间有共同代码,抽取出来的一个内部方法,这段代码只是功能的一部分,不是完整的功能,不希望外部调用,所以私有化。

7.4 接口的特点

  • 接口不能直接new对象
  • 接口允许多实现
  • 接口与接口支持多继承

❝

问:抽象类与接口有什么区别?

相同的:它们都不能new对象,因为它们里面都可能有抽象方法。

不同点:

(1)成员不同(见上)

(2)类与类之间有"单继承"的限制,需要通过接口来解决这个问题,接口允许多实现

7.5 如何使用接口的各个成员

  • 静态的,用接口名.静态成员
  • 非静态的,创建子类对象,然后对象名.非静态成员

7.6 接口的作用/意义

因为接口允许多实现,可以解决抽象类单继承的限制问题。

类与接口之间可以是简单的has-a或like-a的关系,而不是死板的is-a的关系。

  • 如果是is-a的关系,在逻辑层面要求比较严格。

    • Bird is a Animal。
    • Student is a Person。
    • Circle is a Shape。
  • 而has-a或like-a的关系的话,我们只要某个类想要拥有这个接口的方法,那么就可以继承它,不用管逻辑关系。

    • Bird has a fly方法。
    • Plane has a fly方法。
    • Kite has a fly方法。
    • Superman has a fly方法。
    • UFO like a flyable things。

例如:连接wifi,不一定是电脑,手机。可以是任意设备,只要遵循wifi的通信规则设计连网能力,家里任何设备都可以连接wifi。

相关推荐
system_error_x24 分钟前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn2 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈3 小时前
AI 读你的提示词,其实很没耐心
后端
用户8356290780514 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我123454 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒4 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记4 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk598784 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端
雨中飘荡的记忆4 小时前
Claude Code 入门必会:@、!、Slash Commands,一篇讲清楚
人工智能·后端
用户8356290780514 小时前
如何使用 Python 在 Word 文档中创建和格式化列表
后端·python