Scala面向对象编程(高级部分)

1. 静态属性和静态方法

(1)回顾Java中的静态概念

public static 返回值类型 方法名(参数列表) {方法体} 静态属性… 说明:
Java中静态方法并不是通过对象调用的,而是通过类对象调用的,所以静态操作并不是面向对象的。

(2)Scala中静态的概念-伴生对象

①Scala语言是完全面向对象(万物皆对象)的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。也没有static关键字, 但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,我们称之为类的伴生对象。这个类的所有静态内容都可以放置在它的伴生对象中声明和调用
  ②伴生对象的小结

1. Scala中伴生对象采用object关键字声明,伴生对象中声明的全是 "静态"内容,可以通过伴生对象名称直接调用。
2. 伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
3. 伴生对象中的属性和方法都可以通过伴生对象名直接调用访问    
4. 从语法角度来讲,所谓的伴生对象其实就是类的静态方法和静态变量的集合
5. 从技术角度来讲,scala还是没有生成静态的内容,只不过是将伴生对象生成了一个新的类,实现属性和方法的调用。
6. 从底层原理看,伴生对象实现静态特性是依赖于 public static final MODULE$ 实现的。
7. 伴生对象的声明应该和伴生类的声明在同一个源码文件中(如果不在同一个文件中会运行错误!),但是如果没有伴生类,也就没有所谓的伴生对象了,所以放在哪里就无所谓了。
8. 如果 class A 独立存在,那么A就是一个类, 如果 object A 独立存在,那么A就是一个"
静态"性质的对象[即类对象], 在 object A中声明的属性和方法可以通过 A.属性 和 A.方法
来实现调用

(3)伴生对象apply方法

在伴生对象中定义apply方法,可以实现: 类名(参数) 方式来创建对象实例.

class Child private (var name: String, var age: Int, var address: String) {
Child.nums += 1
}
object Child {
var nums: Int = _
// apply方法会通过类(实参列表)调用到
def apply(name: String, age: Int, address: String): Child = {
println("apply()...")
new Child(name, age, address)
}
}object Test {
def main(args: Array[String]): Unit = {
//加入apply方法后可以将主构造器加上private修饰,这样就
//只能通过apply方法调用来生成对象了
//val child1 = new Child("小花1", 10, "昌平")
//println(child1.name)
val array1 = new Array[Int](8)
val array2 = Array(1, 3, 8, 7)val child2 = Child("小明", 5, "朝阳")// 自动调用apply方法
println(child2.name)
}
}

2. 单例模式

定义:保证在整个的软件系统中,某个类只能存在一个对象实例。
应用场景:

比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建Session对象。SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个SessionFactory就够,这是就会使用到单例模式。
Akka [ActorySystem 单例] AKKA

Scala中没有静态的概念,所以为了实现Java中单例模式的功能,可以直接采用类对象(即伴生对象)方式构建单例对象

方式一:懒汉式

object TestSingleTon extends App{
val singleTon = SingleTon.getInstance
val singleTon2 = SingleTon.getInstance
println(singleTon.hashCode() + " " + singleTon2.hashCode())
}
//将SingleTon的构造方法私有化
class SingleTon private() {}object SingleTon {
private var s:SingleTon = null
def getInstance = {
if(s == null) {
s = new SingleTon
}
s
}
}
object TestSingleTon extends App {
val singleTon = SingleTon.getInstance
val singleTon2 = SingleTon.getInstance
println(singleTon.hashCode() + " ~ " + singleTon2.hashCode())
println(singleTon == singleTon2)
}
//将SingleTon的构造方法私有化
class SingleTon private() {
println("~~~")
}
object SingleTon {
private val s: SingleTon = new SingleTon
def getInstance = {
s
}
}
//说明:饿汉式

3.接口

(1)回顾Java接口

声明接口interface 接口名
实现接口class 类名 implements 接口名1,接口2
(1)在Java, 一个类可以实现多个接口。
(2)在Java中,接口之间支持多继承
(3)接口中属性都是常量
(4)接口中的方法都是抽象的

(2)Scala接口的介绍

从面向对象来看,接口并不属于面向对象的范畴,Scala是纯面向对象的语言,在Scala中,没有接口, 也没有implements关键字。Scala语言中,采用trait(特质,特征)来代替接口的概念,也就是说,多个类具有相同的特征(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。

(3)特质

trait 的声明trait 特质名 {trait}**

trait 命名 一般首字母大写. Cloneable , Serializable
object T1 extends object T1 extends Serializable { } ,其中 Serializable 就是scala的一个特质。
在scala中,java中的接口可以当做特质使用

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接没有父类:class 类名 extends 特质1 with 特质2 with 特质3 ..
有父类 :class 类名 extends 父类 with 特质1 with 特质2 with 特质3

(4)特质的再说明

Scala提供了特质(trait),特质可以同时拥有抽象方法和具体方法,一个类可以实现/继承多个特质。
特质中没有实现的方法就是抽象方法。类通过extends继承特质,通过with可以继承多个特质
所有的java接口都可以当做Scala特质使用

abstract class Pet(var name:String, var age: Int, var weight: Double) {
var id: Int // 抽象的属性
// 普通方法
// 抽象方法, 没有=和方法体
def eat
override def toString(): String = {
name + "," + age + "," + weight
}
}
class Dog extends Pet("小黄", 2, 2.5) {// Pet(实参列表)作用是调用父类构造器,完成属性的初始化
var id = 20
override def eat = println("吃狗粮")// 如果是方法的实现, 可以省略override
def kanjia(): Unit = {
println("看家狗")
}
}
class Bird(name:String, age: Int, weight: Double)extends Pet(name, age, weight) {
var id = 30
def eat = println("吃虫子")
}object PetTest {
def main(args: Array[String]): Unit = {
//new Pet("小黑", 2, 20)
val dog = new Dog
val bird = new Bird("小飞", 1, 0.2)
println(dog)
println(bird)var v : Pet = new Dog() // 多态
v = bird
//((Dog)v).kanjia
if (v.isInstanceOf[Dog]) {
v.asInstanceOf[Dog].kanjia // 造型
}
}
}

(5)带有特质的对象:动态混入
1.除了可以在类声明时继承特质以外,还可以在构建对象时混入特质,扩展对象的功能
2.此种方式也可以应用于对抽象类功能进行扩展
3.动态混入是Scala特有的方式(java没有动态混入),可在不修改类声明/定义的情况下,扩展类的功能,非常的灵活,耦合性低 。
4.动态混入可以在不影响原有的继承关系的基础上,给指定的类扩展功能。

//写一个特质Flyer, 写两个抽象方法takeOff, fly, 具体方法land
trait Flyer {
var name:String // 这是抽象属性, 在特质中变成抽象方法
var speed: Int = 2000 // 普通属性, 在特质中变成抽象方法def takeOff():Unit
def fly
def land = println("我要着陆了....")
}
//写一个子类Plane, 再混入其他特质 with后面只允许特质, extends后面可以是特质也可以是类
//在类中使用with是静态混入, 只要创建本类对象,都具备这些特质
class Plane extends Flyer with Serializable with Comparable[Plane] {
var name = "大飞机" // 覆盖属性
// 在子类中重新定义
// 特质中的普通属性, 在子类中也仍然需要重新定义, 提供了set方法, 会被特质的特殊类调用.
def takeOff(): Unit = println("飞机起飞中, 推背感强")
override def fly: Unit = println("平稳飞行中...")
override def compareTo(o: Plane) = 0
}class Man {
type T
}class Chinese extends Man {
override type T = String
}
class English extends Man {
override type T = Double
}object TraitExer {def main(args: Array[String]): Unit = {
type P = Plane
var p: P = new P
println(p)
p.fly
}def main3(args: Array[String]): Unit = {
val man1 = new Man
// 在创建对象时使用with特质, 也可以实现混入,称为动态混入, 混入的特质只对当前对象有效
val man2 = new Man with Flyer with Serializable {
var name = "abc"
override def takeOff(): Unit = println("不知怎么就会飞了")
override def fly: Unit = println("引力对我没用")
}
man2.flyval man3 = new Man{} // 匿名内部类}def main2(args: Array[String]): Unit = {
val plane = new Plane
plane.takeOff()
plane.landval flyer2 = new Flyer {
var name = "yyy"
override def takeOff(): Unit = println("lll")
override def fly: Unit = println("fly")
}}
}

(6)叠加特质
构建对象的同时如果混入多个特质,称之为叠加特质,那么特质声明顺序从左到右,方法执行顺序从右到左。

trait Operate4 {
println("Operate4...")
def insert(id : Int)
}
trait Data4 extends Operate4 {
println("Data4")
override def insert(id : Int): Unit = {
println("插入数据 = " + id)
}
}
trait DB4 extends Data4 {
println("DB4")
override def insert(id : Int): Unit = {
print("向数据库")
super.insert(id)
}
}
trait File4 extends Data4 {
println("File4")
override def insert(id : Int): Unit = {
print("向文件")
super.insert(id)
}}
class MySQL4 {}
// 1.Scala在叠加特质的时候,会首先从后面的特质开始执行
// 2.Scala中特质中如果调用super,并不是表示调用父特质的方法,而是向前面(左边)继续查找特质,如果找不到,才会去父特质查找
val mysql = new MySQL4 with DB4 with File4
//val mysql = new MySQL4 with File4 with DB4
mysql.insert(888)

上述程序执行结果为:

Operate4...
Data4
DB4
File4
向文件向数据库插入数据 = 888

debug整个过程发现,最后一行程序执行时先到了trait File4中的insert方法,然后又去了DB4的insert方法,最后去了Data4的insert方法,执行打印语句完毕后按逆顺序出栈

叠加特质
叠加特质注意事项和细节
1.特质声明顺序从左到右。
2.Scala在执行叠加对象的方法时,会首先从后面的特质(从右向左)开始执行
3.Scala中特质中如果调用super,并不是表示调用父特质的方法,而是向前面(左边)继续查找特质,如果找不到,才会去父特质查找
4.如果想要调用具体特质的方法,可以指定:super[特质].xxx().其中的泛型必须是该特质的直接超类类型

将上述程序中Trait File 改为以下内容:

trait File4 extends Data4 {
println("File4")
override def insert(id : Int): Unit = {
print("向文件")
super[Data4].insert(id)
}
}

此时执行结果为:

Operate4...
Data4
DB4
File4
向文件插入数据 = 888

(7)在特质中重写抽象方法
方式1 : 去掉 super()…
方式2: 调用父特质的抽象方法,那么在实际使用时,没有方法的具体实现,无法编译通过,为了避免这种情况的发生。可重写抽象方法,这样在使用时,就必须考虑动态混入的顺序问题。

理解 abstract override 的小技巧分享:可以这里理解,当我们给某个方法增加了abstract override
后,就是明确的告诉编译器,该方法确实是重写了父特质的抽象方法,但是重写后,该方法仍然是一个抽象方法(因为没有完全的实现,需要其它特质继续实现[通过混入顺序])

trait Operate5 {
def insert(id : Int)
}
trait File5 extends Operate5 {
abstract override def insert( id : Int ): Unit = {
println("将数据保存到文件中..")
super.insert(id)
}
}trait DB5 extends Operate5 {
def insert( id : Int ): Unit = {
println("将数据保存到数据库中..")
}
}
class MySQL5 {}
val mysql5 = new MySQL5 with DB5 with File5重写抽象方法时需要考虑混入特质的顺序问题和完整性问题 看4个案例,并判断结果。
var mysql2 = new MySQL5 with DB5 // ok
mysql2.insert(100)
var mysql3 = new MySQL5 with File5 // error
mysql2.insert(100)
var mysql4 = new MySQL5 with File5 with DB5// error
mysql4.insert(100)
var mysql4 = new MySQL5 with DB5 with File5// ok
mysql4.insert(100)

富接口概念:即该特质中既有抽象方法,又有非抽象方法

trait Operate {
def insert( id : Int ) //抽象
def pageQuery(pageno:Int, pagesize:Int): Unit = { //实现
println("分页查询")
}
}

特质中的具体字段

特质中可以定义具体字段,如果初始化了就是具体字段,如果不初始化就是抽象字段。混入该特质的类就具有了该字段,字段不是继承,而是直接加入类,成为自己的字段。

特质中的抽象字段

特质中未被初始化的字段在具体的子类中必须被重写。

特质构造顺序

特质也是有构造器的,构造器中的内容由“字段的初始化”和一些其他语句构成。具体实现请参考“特质叠加”

第一种特质构造顺序(声明类的同时混入特质)
调用当前类的超类构造器
第一个特质的父特质构造器
第一个特质构造器
第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行
第二个特质构造器
…重复4,5的步骤(如果有第3个,第4个特质)
当前类构造器
第2种特质构造顺序(在构建对象时,动态混入特质)
调用当前类的超类构造器
当前类构造器
第一个特质构造器的父特质构造器
第一个特质构造器.
第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行
第二个特质构造器
…重复5,6的步骤(如果有第3个,第4个特质)
当前类构造器
分析两种方式对构造顺序的影响
第1种方式实际是构建类对象, 在混入特质时,该对象还没有创建。
第2种方式实际是构造匿名子类,可以理解成在混入特质时,对象已经创建了。

扩展类的特质

特质可以继承类,以用来拓展该类的一些功能(和java的不同)

trait LoggedException extends Exception{
def log(): Unit ={
println(getMessage()) // 方法来自于Exception类
}
}

所有混入该特质的类,会自动成为那个特质所继承的超类的子类

trait LoggedException extends Exception{
def log(): Unit ={
println(getMessage()) // 方法来自于Exception类
}
}
//UnhappyException 就是Exception的子类.
class UnhappyException extends LoggedException{
// 已经是Exception的子类了,所以可以重写方法
override def getMessage = "错误消息!"
}

如果混入该特质的类,已经继承了另一个类(A类),则要求A类是特质超类的子类,否则就会出现了多继承现象,发生错误。

自身类型

自身类型(self-type):主要是为了解决特质的循环依赖问题,同时可以确保特质在不扩展某个类的情况下,依然可以做到限制混入该特质的类的类型。
应用案例举例说明自身类型特质,以及如何使用自身类型特质

//Logger就是自身类型特质
trait Logger {
// 明确告诉编译器,我就是Exception,如果没有这句话,下面的getMessage不能调用
this: Exception =>
def log(): Unit ={
// 既然我就是Exception, 那么就可以调用其中的方法
println(getMessage)
}
}

4. type关键字

使用type关键字可以定义新的数据类型名称
本质上就是类型的一个别名

type S = String
var v : S = “abc”
def test() : S = “xyz”

5. 嵌套类

在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构。如在类中可以再定义一个类,这样的类是嵌套类,其他语法结构也是一样。
嵌套类类似于Java中的内部类。

public class TestJavaClass {
public static void main(String[] args) {
//创建一个外部类对象
OuterClass outer1 = new OuterClass();
//创建一个外部类对象
OuterClass outer2 = new OuterClass();
// 创建Java成员内部类
// 说明在Java中,将成员内部类当做一个属性,因此使用下面的方式来创建 outer1.new InnerClass().
OuterClass.InnerClass inner1 = outer1.new InnerClass();
OuterClass.InnerClass inner2 = outer2.new InnerClass();//下面的方法调用说明在java中,内部类只和类型相关,也就是说,只要是
//OuterClass.InnerClass 类型的对象就可以传给 形参 InnerClass ic
inner1.test(inner2);
inner2.test(inner1);// 创建Java静态内部类
// 因为在java中静态内部类是和类相关的,使用 new OuterClass.StaticInnerClass()
OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
}}
class OuterClass { //外部类
class InnerClass { //成员内部类
public void test( InnerClass ic ) {
System.out.println(ic);
}}static class StaticInnerClass { //静态内部类
}}

scala嵌套类的使用1:

class ScalaOuterClass {
class ScalaInnerClass { //成员内部类
}
}
object ScalaOuterClass { //伴生对象
class ScalaStaticInnerClass { //静态内部类
}
}
val outer1 : ScalaOuterClass = new ScalaOuterClass();
val outer2 : ScalaOuterClass = new ScalaOuterClass();// Scala创建内部类的方式和Java不一样,将new关键字放置在前,使用 对象.内部类 的方式创建
val inner1 = new outer1.ScalaInnerClass()
val inner2 = new outer2.ScalaInnerClass()
//创建静态内部类对象
val staticInner = new ScalaOuterClass.ScalaStaticInnerClass()
println(staticInner)

scala嵌套类的使用2:

请编写程序,在内部类中访问外部类的属性和方法两种方法。
方式一:

class ScalaOuterClass {
var name : String = "scott"
private var sal : Double = 1.2
class ScalaInnerClass { //成员内部类
def info() = {
// 访问方式:外部类名.this.属性名
// 怎么理解 ScalaOuterClass.this 就相当于是 ScalaOuterClass这个外部类的一个实例,
// 然后通过 ScalaOuterClass.this 实例对象去访问 name 属性
// 只是这种写法比较特别,学习java的同学可能更容易理解ScalaOuterClass.class 的写法.
println("name = " + ScalaOuterClass.this.name
+ " age =" + ScalaOuterClass.this.sal)
}
}
}
object ScalaOuterClass { //伴生对象
class ScalaStaticInnerClass { //静态内部类
}
}
//调用成员内部类的方法
inner1.info()

方式二:
内部类如果想要访问外部类的属性,也可以通过外部类别名访问(推荐)。即:访问方式:外部类名别名.属性名 【外部类名.this 等价 外部类名别名】

class ScalaOuterClass {
myOuter => //这样写,你可以理解成这样写,myOuter就是代表外部类的一个对象.
class ScalaInnerClass { //成员内部类
def info() = {
println("name = " + ScalaOuterClass.this.name
+ " age =" + ScalaOuterClass.this.sal)
println("-----------------------------------")
println("name = " + myOuter.name
+ " age =" + myOuter.sal)
}}
// 当给外部指定别名时,需要将外部类的属性放到别名后.
var name : String = "scott"
private var sal : Double = 1.2
}object ScalaOuterClass { //伴生对象
class ScalaStaticInnerClass { //静态内部类
}
}
inner1.info()类型投影
先看一段代码,引出类型投影class ScalaOuterClass3 {
myOuter =>
class ScalaInnerClass3 { //成员内部类
def test(ic: ScalaInnerClass3): Unit = {
System.out.println(ic)
}
}
}

分析以下代码正确/错误:

object Scala01_Class {def main(args: Array[String]): Unit = {val outer1 : ScalaOuterClass3 = new ScalaOuterClass3();val outer2 : ScalaOuterClass3 = new ScalaOuterClass3();val inner1 = new outer1.ScalaInnerClass3()val inner2 = new outer2.ScalaInnerClass3()inner1.test(inner1) // okinner1.test(inner2) // error 原因是scala内部类对象和外部类对象相关.//这时可以使用类型投影来屏蔽类型不同
}
}

解决方式-使用类型投影
类型投影是指:在方法声明上,如果使用 外部类#内部类 的方式,表示忽略内部类的对象关系,等同于Java中内部类的语法操作,我们将这种方式称之为 类型投影(即:忽略对象的创建方式,只考虑类型)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谈谈对OceanBase单机分布式一体化的思考

关于作者: 杨传辉,OceanBase CTO。2010 年作为创始成员之一加入 OceanBase 团队,主导了 OceanBase 历次架构设计和技术研发,从无到有实现 OceanBase 在蚂蚁集团全面落地。同时,他也主导了两次 OceanBase TPC-C 测试并打…

管理类联考——数学——汇总篇——知识点突破——数据分析——计数原理——排列组合——成双

🌊 配对问题的解题思路:配对问题主要以鞋子或者手套来作为命题对象,其核心在于成双不成双,对于成双问题,直接选取整双即可,对于不成双问题,要先取成双的,然后从每双中取单只即可。 …

go语言学习笔记

Go学习 一直想学一门新语言,难度又不想太大,C和Java都会但是不怎么精通,某天看到Go语言,好的,就是它了。总体来说,go语言的学习还是相对简单,有编程基础的入手很快。 简介 go是一种并发、带垃…

【设计模式】一、设计模式七大原则

文章目录 设计模式概述设计模式七大原则设计模式的目的设计模式七大原则1. 单一职责原则2. 接口隔离原则3. 依赖倒转(倒置)原则4. 里氏替换原则5. 开闭原则(Open-Closed Principle简称OCP原则)6. 迪米特法则7. 合成复用原则(Composite Reuse …

ABB REF615C-D HCFFAEAGABC2BAA1XD控制继电器

多功能保护:REF615C-D 继电器具备多种保护功能,包括过流、短路、地故障、欠频、过频、欠电压、过电压等,可用于监测和保护电力系统中的设备。 通信能力:该继电器支持通信协议,如IEC 61850、Modbus等,使其能…

YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2

前言:Hello大家好,我是小哥谈。EfficientNetV2是一个网络模型,旨在提供更小的模型和更快的训练速度。它是EfficientNetV1的改进版本。EfficientNetV2通过使用更小的模型参数和采用一种称为Progressive Learning的渐进学习策略来实现这一目标。…

Benchmarking Chinese Text Recognition: Datasets, Baselines| OCR 中文数据集【论文翻译】

基础信息如下 https://arxiv.org/pdf/2112.15093.pdfhttps://github.com/FudanVI/benchmarking-chinese-text-recognition Abstract 深度学习蓬勃发展的局面见证了近年来文本识别领域的迅速发展。然而,现有的文本识别方法主要针对英文文本。作为另一种广泛使用的语…

NIFI实现JSON转SQL并插入到数据库表中

说明 本文中的NIFI是使用docker进行安装的,所有的配置参考:docker安装Apache NIFI 需求背景 现在有一个文件,里面存储的是一些json格式的数据,要求将文件中的数据存入数据库表中,以下是一些模拟的数据和对应的数据库…

初试小程序轮播组件

文章目录 一、轮播组件(一)swiper组件1、功能描述2、属性说明 (二)swiper-item组件1、功能描述2、属性说明 二、案例演示(一)运行效果(二)实现步骤1、创建小程序项目2、准备图片素材…

工程管理系统简介 工程管理系统源码 java工程管理系统 工程管理系统功能设计

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管…

微信小程序 房贷计算器 js代码终极版

这里写目录标题 展示图1.在utils 中创建文件calculateMortgage.ts2. 在需要使用的地方引入并传参 展示图 1.在utils 中创建文件calculateMortgage.ts /** 假设房贷本金是60万,贷款年利率为4.8%即月利率为0.4%,分20年即240期偿还,等额本金还款…

AWS-数据库迁移工具DMS-场景:单账号跨区域迁移RDS for Mysql

参考文档: 分为几个环节: 要使用 AWS DMS 迁移至 Amazon RDS 数据库实例: 1.创建复制实例 有坑内存必须8g或者以上,我测试空库 都提示内存不足 2.创建目标和源终端节点 目标空库也得自己创建哈 3.刷新源终端节点架构 4.创建迁…

echarts环图配置

echarts环图配置 1、安装echarts npm install echarts4.9.02、页面引入echarts import echarts from echarts;3、应用 template片段 <div class"chart-wrap"><div id "treeChart" style "width: 180px; height:180px;" ><…

vite介绍

vite vite是一种新的前端构建工具&#xff0c;vite借助了浏览器对ESM的支持&#xff0c;采用和传统webpack打包完全不一致的unbundle打包机制&#xff1b; vite的快主要体现在两个方面&#xff0c;快速的冷启动和快速的热更新 快速的冷启动&#xff1a;vite只需启动一台静态页…

LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II)

文章目录 前置知识122.买卖股票的最佳时机II题目描述贪心-直观写法贪心-优化代码更简洁 55. 跳跃游戏题目描述贪心-借助ability数组贪心-只用int far记录最远距离 45.跳跃游戏II题目描述回溯算法贪心算法 总结 前置知识 参考前文 参考文章&#xff1a; LeetCode刷题笔记【23】…

SpringBoot隐藏文件

1.设置 2.输入file Types 3.点击忽略文件或者文件夹 4.成功

Linux下go环境安装、环境配置并执行第一个go程序

一、安装 1.Golang对Linux的内核版本要求 GO对Linux内核版本最低要求是 2.6.23&#xff0c;对应要求操作系统版本是&#xff1a; RHEL 6.0CentOS 6.0即&#xff0c;不支持 (RHEL 和 CentOS) 的 (4.x or 5.x)。2.下载golang的代码版本 Golang的官网下载地址&#xff1a;https:…

Qt 简单闹钟

//wiget.h#ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> //时间类 #include <QTimer> //定时器类 #include <QTextToSpeech> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPA…

文件上传与下载

文章目录 1. 前端要求2. 后端要求 1. 前端要求 //采用post方法提交文件 method"post" //采用enctype属性 enctype"" //type属性要求 type"file"2. 后端要求 package com.itheima.reggie.controller;import com.itheima.reggie.common.R; impo…

(数字图像处理MATLAB+Python)第十二章图像编码-第三、四节:有损编码和JPEG

文章目录 一&#xff1a;有损编码&#xff08;1&#xff09;预测编码A&#xff1a;概述B&#xff1a;DM编码C&#xff1a;最优预测器 &#xff08;2&#xff09;变换编码A&#xff1a;概述B&#xff1a;实现变换编码的主要问题 二&#xff1a;JPEG 一&#xff1a;有损编码 &am…