JavaScript -- 07. 面向对象编程

news2024/11/23 23:22:10

文章目录

  • 面向对象编程
    • 1 面向对象编程介绍
    • 2 类
    • 3 属性
    • 4 方法
    • 5 构造函数
    • 6 封装
    • 7 多态
    • 8 继承
    • 9 对象的内存结构
    • 10 原型
      • 10.1 原型链
      • 10.2 原型的作用:
    • 11 修改原型
    • 12 instanceof和hasOwn
      • 12.1 instanceof
      • 12.2 in
      • 12.3 hasOwnProperty
      • 12.4 hasOwn
    • 13 旧类
    • 14 new运算符

面向对象编程

这部分视频讲解了JS中面向对象相关的知识。主要包括:类、属性、方法、构造函数、封装、多态、继承、对象的结构、原型、原型链、旧类、new运算符等内容。

1 面向对象编程介绍

面向对象编程(OOP, Object Oriented Programming)

  1. 程序是干嘛的?
  • 程序就是对现实世界的抽象(照片就是对人的抽象)
  1. 对象是干嘛的?
  • 一个事物抽象到程序中后就变成了对象
  • 在程序的世界中,一切皆对象
  1. 面向对象的编程
  • 面向对象的编程指,程序中的所有操作都是通过对象来完成
  • 做任何事情之前都需要先找到它的对象,然后通过对象来完成各种操作
  1. 事物和对象

    • 一个事物通常由两部分组成:数据和功能

    • 一个对象由两部分组成:属性和方法

    • 事物的数据到了对象中,体现为属性

    • 事物的功能到了对象中,体现为方法

例如对于人来说:

  • 数据:

    • 姓名

    • 年龄

    • 身高

    • 体重

  • 功能:

表现在代码中:

const five = {
    // 添加属性
    name:"王老五",
    age:48,
    height:180,
    weight:100,

    // 添加方法
    sleep(){
        console.log(this.name + "睡觉了~")
    },

    eat(){
        console.log(this.name + "吃饭了~")
    }
}

2 类

使用Object创建对象的问题:

  1. 无法区分出不同类型的对象
  2. 不方便批量创建对象

在JS中可以通过类(class)来解决这个问题:

  1. 类是对象模板,可以将对象中的属性和方法直接定义在类中
  2. 定义后,就可以直接通过类来创建对象
  3. 通过同一个类创建的对象,我们称为同类对象
  • 可以使用instanceof来检查一个对象是否是由某个类创建
  • 如果某个对象是由某个类所创建,则我们称该对象是这个类的实例

语法:

class 类名 {} // 类名要使用大驼峰命名
const 类名 = class {}  

通过类创建对象:

const aa = new 类名()

例如:

// Person类专门用来创建人的对象
class Person{

}

// Dog类式专门用来创建狗的对象
class Dog{

}

const p1 = new Person()  // 调用构造函数创建对象
const p2 = new Person()

const d1 = new Dog()
const d2 = new Dog()

console.log(p1 instanceof Person) // true
console.log(d1 instanceof Person) // false

3 属性

  • 类是创建对象的模板,要创建第一件事就是定义类
  • 类的代码块,默认就是严格模式,
  • 类的代码块是用来设置对象的属性的,不是什么代码都能写
  • 分为实例属性和静态属性
    • 示例属性只能通过实例化后的对象访问:实例化对象.属性名
    • 静态属性只能通过类名访问:类名.属性名
class Person{
    name = "孙悟空" // Person的实例属性name p1.name
    age = 18       // 实例属性只能通过实例访问 p1.age

    // 使用static声明的属性,是静态属性(类属性) Person.test
    static test = "test静态属性" 
    // 静态属性只能通过类去访问 Person.hh
    static hh = "静态属性"   
}

const p1 = new Person()
const p2 = new Person()

console.log(p1)
console.log(p2)
console.log(p1.name, p1.test, Person.test)

image-20221202110721343

4 方法

定义方法和定义函数语法格式都是一样的,只不过可以省掉function关键字

方法中的this和原来一样,谁调用this指向的就是谁

class Person {

    name = "孙悟空"

    // 添加方法的一种方式,不推荐使用这种方式
    // sayHello1 = function () {
    //
    // } 

    // 添加方法(实例方法) 实例方法中this就是当前实例
    sayHello() {
        console.log('大家好,我是' + this.name)
    } 

    // 静态方法(类方法) 通过类来调用 静态方法中this指向的是当前类
    static test() {
        console.log("我是静态方法", this)
    } 
}

const p1 = new Person()

// console.log(p1)
Person.test()
p1.sayHello()

image-20221202111316892

5 构造函数

在前面的定义方法中,每个实例的属性都是我们预先定义好的,没法自定义去改变,唯一的改变方法就是通过下面这种方式,但是这种方式又不能提现类的便捷性

class Person {
    name = "孙悟空" // 当我们在类中直接指定实例属性的值时,意味着我们创建的所有对象的属性都是这个值
    age = 18
    gender = "男"

    sayHello() {
        console.log(this.name)
    }
}

const p1 = new Person()
p1.age = 19
p1.name = "zhangsan"

因此,我们介绍一种新的东西,叫做构造函数,使用方法如下:

  • 在类中可以添加一个特殊的方法constructor
  • 该方法我们称为构造函数(构造方法)
  • 构造函数会在我们调用类创建对象时执行
  • 我们通过new调用函数的时候调用的就是类中的构造函数
  • 默认会有一个无参构造函数
class Person {
    constructor(name, age, gender) {
        // console.log("构造函数执行了~", name, age, gender)
        // 可以在构造函数中,为实例属性进行赋值
        // 在构造函数中,this表示当前所创建的对象
        this.name = name
        this.age = age
        this.gender = gender
    }
}

const p1 = new Person("孙悟空", 18, "男")
const p2 = new Person("猪八戒", 28, "男")
const p3 = new Person("沙和尚", 38, "男")

console.log(p1)
console.log(p2)
console.log(p3)

6 封装

面向对象的特点:封装、继承、多态

封装 —— 安全性
继承 —— 扩展性
多态 —— 灵活性

  • 对象就是一个用来存储不同属性的容器

  • 对象不仅存储属性,还要负责数据的安全

  • 直接添加到对象中的属性,并不安全,因为它们可以被任意的修改

  • 如何确保数据的安全:

    1. 私有化数据
      • 将需要保护的数据设置为私有,只能在类内部使用
    2. 提供setter和getter方法来开放对数据的操作
      • 属性设置私有,通过getter setter方法操作属性带来的好处
        • 可以控制属性的读写权限
        • 可以在方法中对属性的值进行验证
  • 封装主要用来保证数据的安全

  • 实现封装的方式:

    1. 属性私有化在属性名前面加#
    2. 后面再使用的时候通过this.#name修改
    3. 私有化属性必须先声明再复制
    4. 通过gettersetter方法来操作属性
      1. 使用这种方式可以控制用户可以读写的属性
      2. 在修改属性的时候可以先对属性进行检查,如果不符合要求就不修改
    get 属性名(){
        return this.#属性
    }
    
    set 属性名(参数){
    	this.#属性 = 参数
    }
    

例子:

class Person {
    // #address = "花果山" // 实例使用#开头就变成了私有属性,私有属性只能在类内部访问

    #name
    #age
    #gender

    constructor(name, age, gender) {
        this.#name = name
        this.#age = age
        this.#gender = gender
    }

    sayHello() {
        console.log(this.#name)
    }

    // getter方法,用来读取属性
    getName(){
        return this.#name
    }

    // setter方法,用来设置属性
    setName(name){
        this.#name = name
    }

    getAge(){
        return this.#age
    }

    // 可以先检查要修改的值,如果不符合要求就不修改
    setAge(age){
        if(age >= 0){
            this.#age = age
        }
    }

    get gender(){
        return this.#gender
    }

    set gender(gender){
        this.#gender = gender
    }
}

const p1 = new Person("孙悟空", 18, "男")

// p1.age = "hello"

// p1.getName()
p1.setAge(-11) // p1.age = 11  p1.age

// p1.setName('猪八戒')

p1.gender = "女" // 等同于p1.setGender("女")
console.log(p1.gender)

7 多态

  • 在JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递
  • 要调用某个函数,无需指定的类型,只要对象满足某些条件即可
  • 如果一个东西走路像鸭子,叫起来像鸭子,那么它就是鸭子
  • 多态为我们提供了灵活性
class Person{
    constructor(name){
        this.name = name
    }
}

class Dog{
    constructor(name){
        this.name = name
    }
}

class Test{

}

const dog = new Dog('旺财')
const person = new Person("孙悟空")
const test = new Test()

function sayHello(obj){
    // if(obj instanceof Person){
    console.log("Hello, "+obj.name)
    // }
}

sayHello(dog)
sayHello(person)
sayHello(test)

image-20221202121524701

8 继承

  • 可以通过extends关键来完成继承
  • 当一个类继承另一个类时,就相当于将另一个类中的代码复制到了当前类中(简单理解)
  • 继承发生时,被继承的类称为 父类(超类),继承的类称为 子类
  • 通过继承可以减少重复的代码,并且可以在不修改一个类的前提对其进行扩展
class Animal{
    constructor(name){
        this.name = name
    }

    sayHello(){
        console.log("动物在叫~")
    }
}

class Dog extends Animal{
    
}

class Cat extends Animal{
    
}

class Snake extends Animal{

}

const dog = new Dog("旺财")
const cat = new Cat("汤姆")

dog.sayHello()
cat.sayHello()
console.log(dog)
console.log(cat)

但是在上面的代码中,各个动物的sayHello()都是一个东西,但是每个动物的叫声是不一样的,所以可以通过重写父类方法来修改方法

在子类中,可以通过创建同名方法来重写父类的方法

重写构造函数时,构造函数的第一行代码必须为super()

在方法中可以使用super来引用父类的方法,也就是说super指向的是父类对象

OCP 开闭原则:程序应该对修改关闭,对扩展开放

class Animal{
    constructor(name){
        this.name = name
    }

    sayHello(){
        console.log("动物在叫~")
    }
}

class Dog extends Animal{
    // 在子类中,可以通过创建同名方法来重写父类的方法
    sayHello(){
        console.log("汪汪汪")
    }
}

class Cat extends Animal{
    // 重写构造函数
    constructor(name, age){
        // 重写构造函数时,构造函数的第一行代码必须为super()
        super(name) // 调用父类的构造函数
        this.age = age
    }
    
    sayHello(){
        // 调用一下父类的sayHello, 也可以不调用
        super.sayHello() // 在方法中可以使用super来引用父类的方法
        console.log("喵喵喵")
    }
}

const dog = new Dog("旺财")
const cat = new Cat("汤姆", 3)

dog.sayHello()
cat.sayHello()
console.log(dog)
console.log(cat)

9 对象的内存结构

对象中存储属性的区域实际有两个:

  1. 对象自身
    • 直接通过对象所添加的属性,位于对象自身中:this.gender = "男"
    • 在类中通过 x = y 的形式添加的属性,位于对象自身中:name = "zhansgan"
  2. 原型对象(prototype
    • 对象中还有一些内容,会存储到其他的对象里(原型对象)
    • 在对象中会有一个属性用来存储原型对象,这个属性叫做__proto__
    • 原型对象也负责为对象存储属性,
      • 当我们访问对象中的属性时,会优先访问对象自身的属性
      • 对象自身不包含该属性时,才会去原型对象中寻找
    • 会添加到原型对象中的情况:
      1. 在类中通过xxx(){}方式添加的方法,位于原型中
      2. 主动向原型中添加的属性或方法

image-20221202123950992

10 原型

访问一个对象的原型对象

  • 对象.__proto__
  • Object.getPrototypeOf(对象)
class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello,我是", this.name)
    }
}

const p = new Person()
console.log(p.__proto__) // 访问原型对象
console.log(Object.getPrototypeOf(p))

image-20221202124337168

原型对象中的数据:

  1. 对象中的数据(属性、方法等)
  2. constructor (对象的构造函数)

10.1 原型链

注意:原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同

  • p对象的原型链:p对象 --> 原型 --> 原型 --> null

  • obj对象的原型链:obj对象 --> 原型 --> null

    image-20221202124937100

原型链:

  • 读取对象属性时,会优先对象自身属性,

    • 如果对象中有,则使用,没有则去对象的原型中寻找

    • 如果原型中有,则使用,没有则去原型的原型中寻找

    • 直到找到Object对象的原型(Object的原型没有原型(为null))

    • 如果依然没有找到,则返回undefined

  • 作用域链和原型链的比较

    • 作用域链,是找变量的链,找不到会报错
    • 原型链,是找对象属性的链,找不到会返回undefined

所有的同类型对象它们的原型对象都是同一个,也就意味着,同类型对象的原型链是一样的

class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello,我是", this.name)
    }
}

class Dog {}

const p = new Person()
const p2 = new Person()
const d = new Dog()

console.log(p == p2) // false
console.log(p.__proto__ == p2.__proto__) // true
console.log(d == p) // false
console.log(d.__proto__ == p.__proto__) // false

image-20221202180308792

10.2 原型的作用:

  • 原型就相当于是一个公共的区域,可以被所有该类实例访问,
  • 可以将该类实例中,所有的公共属性(方法)统一存储到原型
  • 这样我们只需要创建一个属性,即可被所有实例访问

JS中继承就是通过原型来实现的,当继承时,子类的原型就是一个父类的实例

在对象中有些值是对象独有的,像属性(name,age,gender)每个对象都应该有自己值,但是有些值对于每个对象来说都是一样的,像各种方法,对于一样的值没必要重复的创建

尝试:
函数的原型链是什么样子的?
Object的原型链是什么样子的?

11 修改原型

大部分情况下,我们是不需要修改原型对象

class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello,我是", this.name)
    }
}

const p = new Person()
const p2 = new Person()

// 通过对象修改原型,向原型中添加方法,修改后所有同类实例都能访问该方法 不要这么做
p.__proto__.run = () => {
    console.log('我在跑~')
}

console.log(p)
console.log(p2)

p.run()
p2.run()

注意:千万不要通过类的实例去修改原型(类似上面这样)

  1. 通过一个对象影响所有同类对象,这么做不合适
  2. 修改原型先得创建实例,麻烦
  3. 危险

处理通过__proto__能访问对象的原型外,还可以通过类的prototype属性,来访问实例的原型,修改原型时,最好通过类去修改

Person.prototype === p.__proto__ //true

好处:

  1. 一修改就是修改所有实例的原型
  2. 无需创建实例即可完成对类的修改

原则:

  1. 原型尽量不要手动改
  2. 要改也不要通过实例对象去改
  3. 通过 类.prototype 属性去修改
  4. 最好不要直接给prototype去赋值

12 instanceof和hasOwn

12.1 instanceof

instanceof 用来检查一个对象是否是一个类的实例

  • instanceof检查的是对象的原型链上是否有该类实例,只要原型链上有该类实例,就会返回true

  • dog -> Animal的实例 -> Object实例 -> Object原型

  • Object是所有对象的原型,所以任何和对象和Object进行instanceof运算都会返回true

12.2 in

使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true

class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello,我是", this.name)
    }
}

const p = new Person()
console.log("sayHello" in p) // true
console.log("name" in p) // true

12.3 hasOwnProperty

对象.hasOwnProperty(属性名):用来检查一个对象的自身是否含有某个属性

不推荐使用

class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello,我是", this.name)
    }
}

const p = new Person()
console.log(p.hasOwnProperty("sayHello")) // false
console.log(p.hasOwnProperty("name")) // true

12.4 hasOwn

Object.hasOwn(对象, 属性名) :用来检查一个对象的自身是否含有某个属性

13 旧类

早期JS中,直接通过函数来定义类

  • 一个函数如果直接调用 xxx() 那么这个函数就是一个普通函数
  • 一个函数如果通过new调用 new xxx() 那么这个函数就是一个构造函数
// 等价于:class Person{}
function Person(name, age) {
    // 在构造函数中,this表示新建的对象
    this.name = name
    this.age = age
}

// 向原型中添加属性(方法)
Person.prototype.sayHello = function () {
    console.log(this.name)
}

// 静态属性
Person.staticProperty = "xxx"
// 静态方法
Person.staticMethod = function () {}

const p = new Person("孙悟空", 18)
console.log(p)

上面这种方式定义类比较分散,可以使用立即执行函数把他们写在一起,等价于以下代码

var Person = (function () {
    function Person(name, age) {
        // 在构造函数中,this表示新建的对象
        this.name = name
        this.age = age

        // this.sayHello = function(){
        //     console.log(this.name)
        // }
    }

    // 向原型中添加属性(方法)
    Person.prototype.sayHello = function () {
        console.log(this.name)
    }

    // 静态属性
    Person.staticProperty = "xxx"
    // 静态方法
    Person.staticMethod = function () {}

    return Person
})()

const p = new Person("孙悟空", 18)
console.log(p)

继承的实现方式

var Animal = (function(){
    function Animal(){

    }

    return Animal
})()


var Cat = (function(){
    function Cat(){

    }

    // 继承Animal
    Cat.prototype = new Animal()

    return Cat
})()

var cat = new Cat()

console.log(cat)

14 new运算符

new运算符是创建对象时要使用的运算符

  • 使用new时,到底发生了哪些事情:
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new

  • 当使用new去调用一个函数时,这个函数将会作为构造函数调用,使用new调用函数时,将会发生这些事:

    1. 创建一个普通的JS对象(Object对象 {}), 为了方便,称其为新对象

    2. 将构造函数的prototype属性设置为新对象的原型

    3. 使用实参来执行构造函数,并且将新对象设置为函数中的this

    4. 如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回(千万不要这么做)

    如果构造函数的返回值是一个原始值或者没有指定返回值,则新的对象将会作为返回值返回

    所以一般不要写返回值

function MyClass() {
 	// 第一步
    var newInstance = {}
    // 第二步
    newInstance.__proto__ = MyClass.prototype
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/58925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用上了mac才知道的一些事,献给Mac新手

以前电脑用windows,工作后刚用上mac,发现很多使用逻辑挺让人感觉新奇,甚至摸不着头脑,下面一一列举,帮助想要入手Mac的新手! 1、鼠标滚轮的逻辑和Windows相反。 Mac上滚动鼠标控制页面上下滚动的逻辑和Windows刚好相…

使用 Learner Lab - 使用 S3 静态网页上传图片,搭配 API Gateway 与 Lambda

使用 Learner Lab - 使用 S3 静态网页上传图片,搭配 API Gateway 与 Lambda AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS 的服务,让学生可以在 100 USD的金额下,自行练习所要使用的 AWS 服务,如何进入 Learne…

分割研究~~总结

搬来了基于实例分割的最新进展和发展历程,首先介绍了实例分割的基本逻辑,总结了目前主要研究方法及其原理和网络架构,对已发表的主流实例分割方法进行分析,最后对实例分割任务目前面临 的问题以及未来的发展趋势做出了分析,并针对所面临的问题…

磨金石教育插画干货分享|日本插画为什么独树一帜,那么受欢迎

插画的起源很早,在人类诞生文明的初级阶段,就有了岩画与壁画。在古典文明时代,中国印刷行业有了较大的发展,与之伴随的就是插画的长足发展。中国文化对日本起到了极大的影响。 在插画领域也是如此,客观的说&#xff0c…

CCF走进高校

CCF走进高校(山东大学-人机专委) 陶建华 人工智能与智能交互 人工智能的能力体系 感知智能:发展较快,人机交互场景运用较多; 认知智能:发展相对不成熟。 此外,专用智能领域发展较快&#xff0…

shell编程(一)

shell 简介 Shell 是一个用 C 语言编写的程序,一般我们说的shell编程,是指编写shell脚本。 Shell 负责完成用户与内核之间的交互(shell是一个命令解释器,负责将用户的命令解析成操作系 统所能理解的指令) 第一个shell脚本 创建…

Vue刷新后页面数据丢失问题的解决过程

在做vue项目的过程中有时候会遇到一个问题,就是进行F5页面刷新的时候,页面的数据会丢失,这篇文章主要给大家介绍了关于Vue刷新后页面数据丢失问题的解决过程,需要的朋友可以参考下! 一、为什么刷新后数据会丢失 vuex存储的数据只是在页面中,相当于全局变…

[附源码]计算机毕业设计学习帮扶网站设计与实现Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Linux文件系统调用接口文件描述符的理解

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸 文章目录一、对系统调用进行封装的理由二、文件的系统调用接口① openopen的选项--位图open的权限程序中设置umask权限掩码②close③write④read三、…

字节输入流【InputStream】(读文件)

字节输入流【InputStream】 java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。 public void close(): 关闭此输入流并释放与此流相关联的任何系统资源。 public abstract int read(): …

Telegraf

Telegraf是什么? Telegraf 是 InfluxData 公司开源的一款十分流行的指标采集软件,可以从数据库、系统和物联网传感器收集和发送度量和事件,它用Go编写,编译成一个没有外部依赖的二进制文件–需要非常少的内存,相…

数仓建模理论(一)

学习目录一、关系建模与维度建模二、维度表和事实表(重点)三、事实表类型四、维度模型分类一、关系建模与维度建模 (1)关系建模 关系建模将复杂的数据抽象为两个概念——实体和关系,并使用规范化的方式表示出来。关系…

【计算机毕业设计】73.房屋租赁系统求租合同源码

一、系统截图(需要演示视频可以私聊) 摘 要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,房屋租赁系统当然也不能排除在外。房屋租赁系统是以实际…

Mybatis源码解析(八):插件机制

Mybatis源码系列文章 手写源码(了解源码整体流程及重要组件) Mybatis源码解析(一):环境搭建 Mybatis源码解析(二):全局配置文件的解析 Mybatis源码解析(三):映射配置文件的解析 Mybatis源码解析(四):s…

flex布局列表页(一行内容比较多,长度比较长)

一、Flex 布局是什么? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。 二、基本概念 采用 Flex 布局的元素,称为 Flex 容器(flex co…

Java开发必须掌握的运维知识 (九)-- Docker容器监控信息可视化仪表:Grafana

一、Grafana 是用来干什么的? Grafana 是一个监控仪表系统,它是由 Grafana Labs 公司开源的的一个系统监测 (System Monitoring) 工具。它可以大大帮助你简化监控的复杂度,你只需要提供你需要监控的数据,它就可以帮你生成各种可视…

jdk11新特性——JShell交互性工具

目录一、jshell概述二、jshell位置三、jshell示例3.1、示例一(声明变量并赋值)3.2、示例二(输出打印内容)3.3、示例三(帮助命令)一、jshell概述 java9引入了jshell这个交互性工具,让Java也可以…

BUUCTF Misc 黑客帝国 [MRCTF2020]你能看懂音符吗 [HBNIS2018]caesar [HBNIS2018]低个头

黑客帝国 下载文件 一长串16进制,复制到在线16进制转文本 很明显是一个RAR文件,使用脚本将16进制转换成文件 import binasciihex_data这里填十六进制数据 outopen(res.rar,wb) out.write(binascii.unhexlify(hex_data)) out.close() 需要密码&#xff…

[附源码]计算机毕业设计校园疫情防范管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

# 智慧社区管理系统-核心业务管理-03投诉信息

一 后端 1:entity package com.woniu.community.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public class Complaint {private int id;private int comId;private String c…