【自顶向下看Java——深度剖析抽象类和接口】

系列文章目录

        欢迎大家订阅《计算机底层原理》、《自顶向下看Java》专栏、能够帮助到大家就是对我最大的鼓励、我会持续为大家输出优质内容,敬请期待!


系列文章目录

文章目录

前言

一、抽象类

什么是抽象类?

 为什么要使用抽象类?

抽象类和普通类有什么区别?

拓展:为什么抽象方法不可以使用static来修饰

 二、接口

1.定义接口:

2.接口特性:

3.多接口实现:

4.接口继承:

5.使用接口实例化对象:

6.静态方法:

 总结


前言

        这篇文章将为大家重点讲解有关Java当中的抽象类和接口的知识,全方位无死角带你彻底掌握抽象类和接口当中的重要知识点。


一、抽象类

什么是抽象类?

        在Java当中,抽象类(Abstract Class)是一种不能够实例化的类、他的目的是为了被其他的类继承而设计的,抽象类可以包含抽象方法也可以包含普通方法。

        抽象方法是一种没有实现体的方法,它只有方法签名而没有方法体、继承这个抽象类的子类必须实现这个抽象类当中的所有抽象方法,如果不实现的话,那么就意味着这个子类继承来父类的抽象方法,而没有实现这些抽象方法,就说明这个子类也是抽象类,那么子类必须也使用abstract修饰。

        定义抽象类的关键字是abstract定义抽象方法的关键字也是abstract,一个类如果包含抽象方法那么这个类必须声明为抽象类。

package Yangon;abstract public class Person {private int age;abstract public void Print();
}
class Student extends Person{@Overridepublic void Print() {System.out.println("Hello World!");}
}
class Main{public static void main(String[] args) {Student student = new Student();student.Print();Person person = new Student();person.Print();}
}

        抽象类是不可以被实例化的,只能通过它的子类对象当中的重写方法来进行调用。在面向对象的概念当中所有的对象都需要通过类来描述,但是并不是所有的类都是用来描述对象的,有些类仅仅为了提供一种使用规范,这个类当中并没有足够的信息来描述这个类吗,就比如我定义了一个抽象类Animal,这个类当中定义了很多的抽象方,例如 eat() 方法、sleep()方法,所有的动物对象都会吃饭并且睡觉,这些方法我全部定义成为抽象方法,不提供具体实现,因为不同的动物虽然都会进行这些动作,但是不同的动物再进行这些动作的时候,状态是不一样的,例如🐎是站着睡觉的,而🐕就是躺着睡觉的,所以Animal抽象类当中的抽象方法是不可以提供具体实现的,只能够被具体的子类继承并且重写这些抽象方法的时候才可以实现这些方法。
 

abstract class Animal{abstract public void eat();abstract public void sleep();
}
class Dog extends Animal{@Overridepublic void eat() {System.out.println("吃狗粮!");}@Overridepublic void sleep() {System.out.println("躺着睡!");}
}
class Horse extends Animal{@Overridepublic void eat() {System.out.println("吃牧草!");}@Overridepublic void sleep() {System.out.println("站着睡!");}
}

 为什么要使用抽象类?

        我们从代码的效果来看的话,继承是完全可以解决这些问题的,那么为什么要使用抽象类呢?继承确实是一种实现代码重用和多态性的方式,但并不一定非要使用抽象类、抽象类和继承是相关的概念,但他们有不同的目的和用途。

        1.目的不同:抽象类的目的是为了作为其他类的基类,提供一个通用的模板,抽象类可以包含抽象方法,这些方法需要在子类中被具体实现,通过继承抽象类,子类必须实现这些抽象方法,通过强制子类实现从而确保子类具有一定的行为,抽象类还可以包含具体方法,这些方法可以在子类当中直接继承或者重写。

        2.机制不同:继承是代码重用的一种机制,但是它不一定需要使用抽象类,你可以使用普通的类继承来获得代码重用的好处,抽象类的主要优势是它可以包含抽象方法,而这些方法在子类当中必须被实现,从而强制执行一定的约定。

        我们在选择使用抽象类还是普通类或者是我们一会要提到的接口,取决于我们的具体需求,如果我们希望提供一个通用的模板、并且要求子类必须实现特定的方法,那么抽象类是一个合适的选择,如果我们更关注行为的规范而不是具体的实现,接口可能是更好的选择(接口我稍后会为大家具体讲解),但是如果我们想要使用普通类来继承实现代码重用的话一定要注意,继承普通类的确是一种有效的代码重用方式,但是要注意避免深度继承和过度耦合。


抽象类的访问限定符有什么意义?

        1.public:抽象类可以被其他任何类访问,对的是任何类。

        2.protected:只能被子类和同一个包内的所有类访问。

        3.default:这个时候只能被同一包内的类访问。

        4.private:抽象类不可以使用private来修饰,因为抽象类的目的就是为了被继承,但是private是不可以被继承的,所以这与抽象类的设计初心相违背,所以不允许。

        那么抽象方法使用访问限定符的规则与普通方法完全一样,这里就不做特别的声明了。注意一点抽象方法也不可以被声明为private,因为这个方法也是必须被子类继承并且实现的。


抽象类和普通类有什么区别?

        抽象类和普通类在Java当中的实现是非常类似的,他们都会被编译成为字节码并且在Java虚拟机当中执行,以下我为大家列举出一些相似点和区别点。

        相似点:

        1.字节码生成:抽象类和普通类都会生成字节码文件、其中包含了类的结构、字段、方法等信息。

        2.内存管理:对象的内存分配和释放由Java虚拟机进行管理,这对于抽象类和普通类都是一样的,他们都会存储在JVM的方法区当中。

        3.方法调用:对象的方法调用采用虚方法调用的方式,确保在运行时根据对象的实际类型进行动态绑定来实现多态(关于动态绑定和多态的知识点我在上一篇文章已经详细地介绍过了,如果大家需要可以去看我之前的文章,这里就不做赘述了)。

        区别点:

        1.实例化:抽象类不能实例化,但是普通类可以直接实例化,抽象类需要通过子类实现并且实例化。

        2.构造器:抽象类也可以有构造器、用于初始化抽象类的实例、普通类也有构造器、但是抽象类的构造器不能够直接实例化抽象类,而是由子类的构造器来进行调用。

        3.抽象方法:抽象类可以包含抽象方法,这是一种声明但是不实现的方法,普通类可以包含抽象方法,但是不需要。

        从底层的视角来看的话,抽象类其实和普通类没有太大的区别,Java编译器和JVM在处理抽象类和普通类时并没有太大的区别,它们都会被翻译成为相应的字节码,然后在虚拟机上执行。抽象类主要提供了一种面向对象的设计机制,强制要求子类实现抽象方法,而相比于抽象类普通类会更加地灵活,可以直接实例化!

拓展:为什么抽象方法不可以使用static来修饰

         首先我先为大家讲解一下抽象方法和静态方法的区别:

          静态方法使用static关键字来进行修饰,在编译时会同类的结构信息一同加载到方法区当中,所以静态方法的调用是依赖于类的,属于类级别而不依赖于类的实例,同样静态方法是不可以访问类的实例成员和变量只能访问类的静态成员和变量,而静态方法可以被继承,但是它不会被子类重写,如果子类定义了与父类同名的静态方法,子类当中的静态方法不会覆盖父类当中的静态方法,最重要的一点就是静态方法是不具备多态性的,他在编译时就可以确定方法调用的目标。

        但是反观抽象类,抽象类被abstract修饰,在抽象的父类当中声明并且必须在子类当中提供实现,然后通过子类的对象实例调用,可以访问父类当中的实例成员和变量,抽象方法和普通方法一样都具有多态性,可以被继承可以被重写,通过向上转型就可以实现多态。

        其实我说到了这里,大家应该也已经明白了,为什么抽象方法不能够被static修饰,因为抽象方法和静态方法在设计理念上就是相违背的,这里还要多提一句抽象方法也不能够被final修饰,因为抽象方法必须被子类重写。


 二、接口

        Java中接口是一种抽象数据类型,用于定义一组抽象方法、但是不提供方法的具体实现,接口允许类实现这些抽象方法,并在类中提供实现。

1.定义接口:

        使用interface关键字来定义接口,接口当中包括抽象方法、常量,要注意这里的常量被隐式地指定为public static final,以及默认方法和静态方法。

        抽象方法:首先说到抽象方法,接口当中的抽象方法就是没有方法体的方法,只有方法签名,实现接口的类必须提供这些方法的具体实现。这里要专门提一句,接口当中的抽象方法会被隐式地修饰成为public abstract,所以接口当中的方法定义不需要很复杂。

        变量(常量):在接口当中声明的所有变量都是常量,都会被编译器隐式地修饰成为public static final类型,因为接口就是需要被实现的,所以使用public,这些接口当中的变量(实际上是常量)必须被初始化,并且在类当中不可以被修改。

        默认方法:从Java8 开始引入,默认方法是在接口中包含方法体的方法、他们允许在接口当中添加新的方法,而不会破坏实现这个接口的类。

        静态方法:静态方法是在接口当中使用static关键字定义的方法。

interface IPrint{void Print();default void Func(){System.out.println("Hello default Func()");}int I_Value = 10;static void StaticFunc(){System.out.println("Hello static Func()");}
}
class Student2 implements IPrint{@Overridepublic void Print() {System.out.println("Hello Print()");}@Overridepublic void Func() {//IPrint.super.Func();  调用接口当中原本的默认方法System.out.println("我重写了父类的默认方法!");}public static void main(String[] args) {IPrint iPrint = new Student2();iPrint.Func();iPrint.Print();System.out.println(I_Value);}
}

拓展:

        很多的小伙伴可能第一次听说接口的默认方法的概念,那么什么是默认方法呢?默认方法的引入是为了在接口当中添加新的方法,而不会影响这个接口的已有类,也就是说,如果我定义了一个接口,并且已经使用类对他进行实现,但是这个时候我发现这个接口并不完善,想要在这个接口当中补充一些新的方法,可是如果我们继续定义抽象方法的话,那就意味着凡是实现过这个接口的类都必须实现这个新增的方法,也就是牵一发而动全身,非常的麻烦,所以也就引入了默认方法,在Java8之前,一旦一个接口当中定义了新的方法,所有实现该接口的类都必须提供该方法的实现,否则就会编译报错。

        默认方法通过在接口当中直接提供方法体,使得接口可以包含具体的方法实现,这样,实现接口的类如果没有显式提供对默认方法的实现,那么就会使用接口当中的默认实现,这位接口的演进提供了一种向后兼容的方式。

        在实现类当中,如果希望使用默认方法提供的实现,可以直接继承接口当中的默认方法,如果需要覆盖默认方法,可以在实现类中重新实现该方法。

        这种设计的好处在于,当接口需要添加新的方法的时候,不会破坏已有的实现类,因为它们可以选择是否提供新的方法,而不会强制所有类都做出修改,这有助于在不破坏现有代码的情况下,为接口添加新的功能,增强接口的灵活性。

interface IWork{void eat();int I_Value = 10;default void print(){System.out.println("接口当中的常量:" + I_Value);}
}
public class Animal {private String name;
}
class Dog extends Animal implements IWork{@Overridepublic void eat() {}@Overridepublic void print() {IWork.super.print();}
}

        如上面的代码所示,接口当中定义了默认方法,如果类当中没有明确重写这个接口当中的默认方法,那么默认还使用接口当中原本定义的默认方法,大家可以运行一下看看效果。

这里要提示一下大家,可能会有小伙伴认为既然是默认方法,那么这个default访问权限不写也可以,他还是默认方法,这是绝对不可以的这里的default关键字必须加上,这是Java8之后独有的特性,就是为了和抽象方法做区分,如果不写的话,编译器会自动将其识别为public abstract的抽象方法。

2.接口特性:

        接口并不能直接使用,必须有一个类来实现它,实现的关系通过关键字implements来完成。

         1.接口类型是一种引用类型,不能直接使用new关键字来实例化接口。、

         2.接口当中的每一个没有实现的方法都是public的抽象方法,即接口当中的方法会被隐式地指定为public abstract,当然我刚才提到的默认方法是Java8之后的一个特性,大家在这里自行做一个区分。

        3.接口当中的方法是不能在接口当中实现的,只能由类来实现。

        4.当我们重写接口当中的方法的时候只能使用public访问权限,注意这里非常重要,即便是重写接口当中的默认方法,也只能使用public修饰,因为接口就是为了提供一种规范供所有人使用,即便是默认方法也是为了让大家去实现的,所以重写接口的方法必须是public修饰。

        5.接口当中的变量会被隐式地指定为public static final变量,说白了也就是常量,接口当中定义的变量其实都是常量,编译器不允许修改,还是之前的原因,接口就是为了提供一种规范,如果接口当中的属性可以随意修改那就乱套了,大家都知道秦始皇同意度量衡,书同文、车同轨,就是为了提供一种规范,那么大家觉得这种规范我们作为程序员可以随意修改吗?显然是不行的。

        6.接口当中不可以有静态代码块和构造方法。首先我们先说为什么不能定义构造方法,很简单,大家还记得构造函数的作用是什么吗?是不是就是为了实例化对象的时候为这个实例化对象进行初始化的?这就是构造函数的作用,那么接口是不可以被实例化的,他就是一个规范,那么这样不能够被实例化的接口提供构造函数有什么意义呢?

        那么我们再谈为什么接口当中不能够定义静态代码块呢?首先我先说结论,不只是静态代码块,即使是普通代码块,接口当中也不可以定义,接口当中主要为了提供一套规范,用于定义抽象方法、常量默认方法和静态方法。这些都是属于静态绑定,在程序的编译期间就已经绑定和确认了,在接口当中定义静态代码块和普通代码块,它们根本就没有执行的时机,况且接口属于类级别,编译后会加载到方法区内,但是普通代码块是在实例化对象的时候执行的,它们属于实例的初始化阶段属于对象的初始化过程,而接口不能够被初始化,所以自然也就不能定义普通代码块,静态代码块自然也不行,虽然静态代码块不依赖于对象的实例,但是接口的存在就是为了提供一套规范,并不是为了执行某种逻辑存在的,所以在接口当中定义代码块不论是什么类型的代码块都是不被允许的。

        7.接口虽然不是类,但是接口编译完成后的字节码文件的后缀格式也是.class。

        8.如果类没有实现接口中的抽象方法,则类必须设置为抽象类。

        9.接口当中还可以包含default方法(刚才已经讲过了)。

 3.多接口实现:

        我们都知道类和类之间是单继承的,一个类只允许有一个父类,但是接口不一样,Java当中不支持多继承,但是一个类当中是可以有多个接口的,也就是说一个类可以实现多个接口。

interface IFly{void fly();
}
interface IRun{void run();
}
public class Animal implements IFly,IRun{@Overridepublic void fly() {System.out.println("我会飞");}@Overridepublic void run() {System.out.println("我会跑");}
}

        多继承的实现代码已经给大家展示出来了,就这些内容。

 4.接口继承:

        在Java当中类和类之间是单继承的,一个类可以实现多个接口,接口于接口之间可以多继承,接口之间的继承同样也是extends来实现的。我用一段代码来为大家展示一下,接口之间的继承,这段代码里面涉及到了默认方法,所以大家需要将我之前讲的有关默认方法的知识全部吸收,否则这里会理解困难。

package Demo2;interface Interface1{void method1();default void defaultMethod(){System.out.println("Default method in Interface1");}
}
interface Interface2{void method2();default void defaultMethod2(){System.out.println("Default method in Interface2");}
}
interface ExtendsInterface extends Interface1,Interface2{void additionalMethod();@Overridedefault void defaultMethod() {//Interface1.super.defaultMethod();System.out.println("我重写了第一个接口当中的默认方法!");}@Overridedefault void defaultMethod2() {//Interface2.super.defaultMethod2();System.out.println("我重写了第二个接口当中的默认方法!");}
}
class MyClass implements ExtendsInterface{@Overridepublic void method1() {System.out.println("这个类实现了接口当中的method1()方法!");}@Overridepublic void method2() {System.out.println("这个类实现了接口当中的method2()方法!");}@Overridepublic void additionalMethod() {System.out.println("这个类当中实现了接口当中的method2()方法!");}
}
public class Main {public static void main(String[] args) {MyClass myClassObj = new MyClass();myClassObj.method1();myClassObj.method2();myClassObj.additionalMethod();myClassObj.defaultMethod();myClassObj.defaultMethod2();}
}

 5.使用接口实例化对象:

        使用接口的实例化类似于多态,通过向上转型,来访问子类重写父类的方法,一个类实现了这个接口,通过向上转型就可以访问类重写接口的方法,整体的用法类似于多态。这里就不进行过多地赘述了。

        这里再为大家展示出一份相较于之前更为完整的一份代码。

package Demo2;interface Interface1{void method1();default void defaultMethod(){System.out.println("Default method in Interface1");}
}
interface Interface2{void method2();default void defaultMethod2(){System.out.println("Default method in Interface2");}
}
interface ExtendsInterface extends Interface1,Interface2{void additionalMethod();@Overridedefault void defaultMethod() {//Interface1.super.defaultMethod();System.out.println("我重写了第一个接口当中的默认方法!");}@Overridedefault void defaultMethod2() {//Interface2.super.defaultMethod2();System.out.println("我重写了第二个接口当中的默认方法!");}
}
class MyClass implements ExtendsInterface{@Overridepublic void method1() {System.out.println("这个类实现了接口当中的method1()方法!");}@Overridepublic void method2() {System.out.println("这个类实现了接口当中的method2()方法!");}@Overridepublic void additionalMethod() {System.out.println("这个类当中实现了接口当中的额外默认方法!");}@Overridepublic void defaultMethod(){System.out.println("在继承接口重写的基础之上我又一次重写了第一个接口的默认方法");}@Overridepublic void defaultMethod2(){System.out.println("在继承接口重写的基础之上我又一次重写了第二个接口的默认方法");}
}
public class Main {public static void main(String[] args) {MyClass myClassObj = new MyClass();myClassObj.method1();myClassObj.method2();myClassObj.additionalMethod();myClassObj.defaultMethod();myClassObj.defaultMethod2();System.out.println("================================");ExtendsInterface extendsInterfaceObj = new MyClass();extendsInterfaceObj.additionalMethod();extendsInterfaceObj.defaultMethod();extendsInterfaceObj.defaultMethod2();}
}

 6.静态方法:

        Java8以及更高的更新版本使用接口的时候,我们可以在接口当中定义静态方法,这些静态方法是于接口本身相关的,而不是于实现接口的类相关的。

interface IUsb{static void Print(){System.out.println("Hello World!");}
}

        静态方法不需要再类当中实现,可以直接通过接口的名称来进行调用这些静态方法,不需要创建接口的实例。使用这种方式,接口可以提供一些于接口本身直接相关的使用方法,而不必依赖于实现类的实例,这对于定义一些通用的辅助或工具方法非常有用。
 

public class Main {public static void main(String[] args) {IUsb.Print();}
}
interface IUsb{static void Print(){System.out.println("Hello World!");}
}

        代码如上图所示,这就是接口当中的抽象类静态方法的使用方式,就为大家介绍到这里。


 总结

        Java当中抽象类和接口就为大家介绍到这里,还有关于深浅拷贝和Object类的相关内容我放到下一篇文章再去讲解,离过年不远了,我也要准备开始我的《编译原理》专栏的准备工作了,争取在阴历年前把编译原理的所有重点全部系统地整理出来,真的很久没有用心地去准备做一件事情了,自律的快乐超过了所有物质享受给我带来的快乐,各位小伙伴们一起加油!

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

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

相关文章

@Data@NoArgsConstructor@AllArgsConstructor 这几个常用注解什么意思?

这三个注解通常用于简化Java类的开发,特别是在使用一些框架时,如Lombok。让我们逐个解释这些注解的作用: 1. Data Data 是 Lombok 提供的一个组合注解,它包含了一组常用注解的功能,如 ToString、EqualsAndHashCode、…

一种解决Qt5发布release文件引发的无法定位程序输入点错误的方法

目录 本地环境问题描述分析解决方案 本地环境 本文将不会解释如何利用Qt5编译生成release类型的可执行文件以及如何利用windeployqt生成可执行的依赖库,请自行百度。 环境值操作系统Windows 10 专业版(22H2)Qt版本Qt 5.15.2Qt Creator版本5.0…

K8S的一个pod中运行多个容器

通过deployment的方式部署 创建一个deployment文件 [rootk8s-master1 pods]# cat app.yaml apiVersion: apps/v1 kind: Deployment metadata:name: dsfnamespace: applabels:app: dsf spec:replicas: 1selector:matchLabels:app: dsftemplate:metadata:labels:app: dsfspec:i…

P2P如何使用register_attention_control为UNet的CrossAttention关联AttentionStore

上次的调试到这里了,写完这篇接着看,prepare_latents_ddim_inverted 如何预计算 inversion latents: /home/pgao/yue/FateZero/video_diffusion/pipelines/p2p_ddim_spatial_temporal.py 1. 原始的UNet3D的CrossAttention和SparseCausalAtte…

深度学习中的潜在空间

1 潜在空间定义 Latent Space 潜在空间:Latent ,这个词的语义是“隐藏”的意思。“Latent Space 潜在空间”也可以理解为“隐藏的空间”。Latent Space 这一概念是十分重要的,它在“深度学习”领域中处于核心地位,即它是用来学习…

C#基础知识 - 操作数与运算符篇

C#基础知识 - 操作数与运算符篇 4.1 表达式 - 操作数与运算符组成4.1.2 C#中常见的表达式类型:4.1.2 表达式示例 更多C#基础知识详解请查看:C#基础知识 - 从入门到放弃 4.1 表达式 - 操作数与运算符组成 C#中,表达式(expression…

kafka入门(四):kafka生产者发送消息

创建生产者实例和构建消息之后,就可以开始发送消息了。 发送消息主要有三种模式:发后即忘、同步、异步。 发后即忘: 就是直接调用 生产者的 send方法发送。 发后即完,只管往 kafka中发送消息,而不关心消息是否正确…

用GitBook制作自己的网页版电子书

用GitBook制作自己的网页版电子书 前言 几年前阅读过其他人用GitBook创建的文档,可以直接在浏览器中打开,页面干净整洁,非常清爽,至今印象深刻。 GitBook非常适合用来为个人或团队制作文档,对于我这种偶尔写博客的人…

和鲸科技CEO范向伟受邀出席港航数据要素流通与生态合作研讨会,谈数据资产入表的战略机会

近日,由上海虹口数字航运创新中心、龙船(北京)科技有限公司(下简称“龙船科技”)、华东江苏大数据交易中心联合举办的“港航数据要素流通与生态合作研讨会”圆满落幕,来自港航领域的近百名企业代表共同参与…

【Spark面试】Spark面试题答案

目录 1、spark的有几种部署模式,每种模式特点?(☆☆☆☆☆) 2、Spark为什么比MapReduce块?(☆☆☆☆☆) 3、简单说一下hadoop和spark的shuffle相同和差异?(☆☆☆☆☆…

Spring Boot Docker Compose 支持中文文档

本文为官方文档直译版本。原文链接 Spring Boot Docker Compose 支持中文文档 引言服务连接自定义镜像跳过特定的容器使用特定Compose文件等待容器就绪控制 Docker Compose 的生命周期激活 Docker Compose 配置文件 引言 Docker Compose 是一种流行的技术,可用于为…

黑马头条--day02--2文章详情

一.上传之前的配置 1.上传js和css文件 在minio中创建leadnews桶, 在leadnews下面创建/plugins目录,在该目录下面分别创建js和css目录, 也就是/plugins/css和/plugins/js,向css中上传以下index.css: html {overflow-x: hidden; }#app {position: rel…

GPT实战系列-探究GPT等大模型的文本生成

GPT实战系列-探究GPT等LLM文本生成 GPT专栏文章: GPT实战系列-Baichuan2等大模型的计算精度与量化-CSDN博客 GPT实战系列-GPT训练的Pretraining,SFT,Reward Modeling,RLHF-CSDN博客 GPT实战系列-ChatGLM3本地部署CUDA111080Ti…

kali虚拟机无网络

1.查看虚拟机的网卡模式 在虚拟机设置里,一般选择桥接模式,也可以选择NAT模式。 2、你的IP地址是否写死了(设置为静态IP) vim编辑模式下的命令: 按a或i进入编辑模式,然后按esc键退出编辑模式,s…

LV.13 D5 uboot概述及SD卡启动盘制作 学习笔记

一、uboot概述 1.1 开发板启动过程 开发板上电后首先运行SOC内部iROM中固化的代码(BL0),这段代码先对基本的软硬件环境(时钟等...)进行初始化,然后再检测拨码开关位置获取启动方式,然后再将对应存储器中的uboot搬移到内存,然后跳…

如何在STM32上配置DMA通道

STM32系列微控制器具有DMA(Direct Memory Access)功能,它允许外设直接访问存储器,从而减轻CPU的负担。在本文中,我们将介绍如何在STM32上配置DMA通道。 Step 1: 选择DMA通道 STM32微控制器通常具有多个DMA通道&#x…

mysql复习笔记04(小滴课堂)

mysql的存储引擎介绍 基于表的。 查看数据库支持的引擎: 查看支持的版本: 查看表的引擎: 查看所有表的存储引擎: 也可以修改默认引擎。 这有一张数据量庞大的表。 表是通过执行shell脚本快速创建的. 创建的表. 执行成功后会有个s…

Flink系列之:集合操作

Flink系列之:集合操作 一、集合操作二、UNION三、INTERSECT四、EXCEPT五、IN六、EXISTS 一、集合操作 适用于流、批操作 二、UNION UNION 和 UNION ALL 返回两个表中的数据。 UNION 会去重,UNION ALL 不会去重。 Flink SQL> create view t1(s) as…

PIG框架学习1——密码模式登录认证获取Token流程

文章目录 O、前言一、总流程概括:二、具体流程分析PIG提供的具体流程图:鉴权请求报文示例0、网关前置处理1、客户端认证处理2、正式接受登录请求3、组装认证对象4、认证管理器进行认证(授权认证调用)5、认证成功处理器 O、前言 对…

论文阅读:Learning sRGB-to-Raw-RGB De-rendering with Content-Aware Metadata

论文阅读:Learning sRGB-to-Raw-RGB De-rendering with Content-Aware Metadata Abstract 大多数的 Camera ISP 会将 RAW 图经过一系列的处理,变成 sRGB 图像,ISP 的处理中很多模块是非线性的操作,这些操作会破坏环境光照的线性…