java的面向对象(从入门到深入)

目录

一、基本概念:

1.类

2.对象

3.继承

4.多态

5.封装

6.方法

7.接口

8.抽象

二、深入概念:

三:总结


一、基本概念:

1.类

类就是一个一个东西的蓝图,里面有着它的属性和方法。

2.对象

对象是一个类的实例化。

3.继承

继承就是拥有父类的属性和方法。

4.多态

多态就是在不同情况对象有着不同的形态,通过方法重写或重载。

5.封装

封装就是把类中的属性私有化,只能通过公共方法访问。我们的属性只能通过public的set和get方法访问,而不能直接修改。

6.方法

方法就是定义在类中的行为,比如我们的get和set方法还有work方法。

7.接口

接口定义了类中必须要实现的方法。

注意:如果我们的父类实现了接口,那么子类也可以直接使用父类的接口方法,而不需要用implements实现接口。

8.抽象

使用抽象类定义子类必须实现的方法。

注意以下几点:

(1)我们自己在写一些类的时候发现他们之间有共性,所以我们为了简化,可以将公共逻辑提取出来写写一个抽象类,这样可以减少代码冗余。

(2)抽象类只是在普通类的基础上增加了抽象方法,正因如此它不可以直接实例化,因为它的抽象方法没有方法体,所以不可方法调用,故无法实例化。

(3)抽象类必须要有子类继承,一个子类只能继承一个抽象类,并且子类必须重写抽象类的所有抽象方法,否则必须也要命名为抽象类。

(4)关于抽象类用final和static声明的问题:

final的类是不可变的,所以不可以被继承,那么自然抽象类不可以用final修饰。

外部抽象类不能直接用static修饰,而内部抽象类可以用static修饰,修饰后,别的类要继承它只需要用它的外部类.内部类即可。

二、深入概念:

1.类中变量:

一个类中存在这样一些变量,分别是局部变量,成员变量,类变量。

局部变量存在于构造方法,方法,或者语句块内,变量声明和初始化都在其中,在方法执行完后就销毁。

成员变量定义在类中,方法体之外,可以被构造方法,方法,语句块内访问。

类变量也是声明和定义在类中,方法体之外,但必须用static修饰。

2.构造方法:

如果一个类中没有构造方法,那么java虚拟机会默认提供一个无参的构造方法。

3.一个源文件只能有一个public类,可以有多个非public类。

4.三种变量的访问方法:

局部变量:直接使用。

子类成员变量:this.成员变量

父类成员变量:super.成员变量

5.内部类有4种类型:成员内部类,局部内部类,静态内部类,匿名内部类

如果内部类不想被外部类访问可以给内部类加private修饰

成员内部类:作为外部类的一个成员,可以访问外部类的所有成员,包括私有字段

方法:首先创建外部类的对象,然后通过外部类.内部类,就可以在外部类对象的基础上new出内部类对象。

局部内部类:指在方法中定义的类,只在方法中可见,可访问外部类成员以及方法内局部变量(需要声明为final)

方法:在外部类的方法中调用创建内部类对象,并调用方法

静态内部类:只能访问外部类的静态成员变量和静态成员方法。

方法:不需要创建外部类的对象就可以访问,即可以独立存在。

注意:外部类不能用static修饰。

匿名内部类:指没有类名的内部类,用于简化接口和继承

分为两种形式:第一种匿名类继承一个父类,第二种匿名类实现一个接口

下面是第一种形式:

下面是第二种形式:

6.java中的不可变类:

不可变类即在创建对象后不可改变其属性。

注意以下几点:

(1)声明的类用final修饰,防止子类继承。

(2)类中的字段都用final或private修饰。

(3)通过构造函数初始化所有字段,不提供修改字段的方法。

(4)java中常见的不可变类有String,Integer,BigDecimal,LocalDate……

不可变类优缺点:

优点:

(1)线程安全:由于不可修改,故天然就是线程安全的,无需在并发下同步。

(2)缓存友好:不可变对象可以安全的缓存和共享。

(3)防止状态不一致:避免对象被修改而导致不一致的问题。

(4)哈希值不会反复变化,提高哈希表等数据结构的性能。哈希值在第一次计算出来放进缓存中,这就提高了哈希表的性能,不会反复计算。

缺点:由于可能会频繁的创建对象,所以性能开销较大。

下面通过String类的源码讲解一下:

我们可以看到String类使用final修饰的,并且内部用的是byte[]数组存储的(JDK8中是char),那么为何不用char类型呢?其实是为了节省字符串所占有的内存空间。同时还有另一个好处,那就是减少GC(垃圾回收次数减少)

同时String类实现了Serializable接口,Comparable接口,前者意味着可以序列化,后者意味着可以用compareTo方法比较。注意:"=="是用来比较两个对象的地址的,我们可以用equals方法去比较字符串的内容。

更深入一点:

现在的JDK使用coder来表示编码,那先说说字符集吧:

ASCLL,Latin1,Unicode,UTF-8

(1)ASCLL码表实现的是阿拉伯数字和英文字母,以及一些其它的字符,对于英语国家是够用的,但无法表达别的国家的文字。ASCLL码表用一个字节储存,最高位为奇偶效验位,其余7位为存储位。其它大多数编码都是兼容ASCLL码表的。

(2)Latin1是一种单字符集,也就是说最多只能表示256个字母或符号。Latin1是Mysql默认的编码形式。

(3)Unicode是一个庞大的字符集,目前可容纳100多万个字符,几乎可以表达出地球上所有的文字。但是使用的存储空间会稍大一点。

(4)UTF-8是使用最广的一种Unicode编码的实现形式,可以随着不同的符号变换字节长度。注意如果文件中有UTF-8编码的文字,又有GB系列编码的文字,那么就会导致乱码,因为二者不兼容。

在jvm里char是占用两个字节的,使用UTF-8编码,那么也就是说如果我的String类型的字符只用一个字节就可以表示,它也要占用两个字节。

当我们使用byte类型存储,并且使用Latin1字符编码,就会比UTF-8节省很多空间。

下面再说说字符串常量池:

java中存在着字符串常量池,当我们有相同的字符串时,那么这两个字符串指向同一个对象。提高性能,降低内存开销。来想下面一行代码:

String s = new String("abc");

思考一下,它创建了几个对象。

答案是两个,为啥呢?往下看。

当我们使用new创建一个字符串对象时,jvm会先在字符串常量池找有没有这个值的对象,如果有,那么就不会在常量池中创建对象了,而是直接在堆中创建"abc"这个字符串对象。然后将它的地址返回给变量s。变量s在栈上。

如果字符串常量池没有这个对象,那么就会先在常量池中创建"abc"这个字符串对象,然后在堆上创建"abc"这个字符串对象,然后将这个地址返回给s。变量s在栈上。

在java中,对象本身都在堆中,而基本数据类型变量和对象的引用都在栈上。

但是一般我们不通过new来创建字符串对象。看下面的代码:

String s = "abc";

当我们执行上面一行代码时,jvm会先在字符串常量池中找有没有"abc"的对象,如果有,则不用创建任何对象,而是直接将字符串常量池的这个对象地址返回给s。即此时堆中无new出来的对象。只有栈中的s变量去调用字符串常量池的相应对象地址。

如果字符串常量池中没有这个对象,那么现在字符串常量池中创建"abc"这个对象。然后将这个地址返回给s。

所以,如果使用new关键字,那么堆中就有两个对象,如果不使用new关键字,那么堆中只有一个对象,即字符串常量池的那个。

再深入一下intern()方法。

我们之前说过"=="比较的是地址是否相等,equals比较的是内容是否相等。

我们看到下面的代码,s变量指向的是堆中new出来的字符串对象,而ss变量指向的是在字符串常量池中的字符串对象。所以地址不一样,返回false。

 

然而思考一下下面的代码:

为什么现在返回的是true呢?下面将给出解释:

首先在字符串常量池中先创建"def"和"ghi",然后在堆中创建两个匿名对象(也叫临时对象,生命周期一般较短),然后在堆上创建一个新的对象"defghi"(此时字符串常量池没有这个对象),然后b引用这个对象。继续,在字符串常量池找"defghi"这个对象是否存在,此时不存在,但是堆中已经有了这个对象了。那么现在字符串常量池就保存堆中"defghi"这个对象的引用。即现在b和bb的引用地址一直,故返回true。

再说说"+"是怎么拼接两个字符串的吧,实际上,实现创建了一个StringBuilder的对象,然后用append()把"def"和"ghi"加进去,最后使用toString()方法返回新的字符串对象。

我们知道StringBuilder是可变长的字符串变量,不是常量,那么自然不会在字符串常量池中创建。

最后在讲一讲String,StringBuffer,StringBuilder的区别:

String是不可变的,适用于字符串不会频繁变化的场景。

StringBuffer是可变的,内部使用了synchronized关键字保证了线程安全。适用于多线程下频繁改变字符串的场景。

StringBuilder是可变的,不保证线程安全,性能比StringBuffer更好(去掉了保证线程安全的部分)。减少了开销。

那么我们String类到此为止,希望能够对您有所帮助。

7.方法重载与方法重写:

方法重载为一个方法有着不同的参数。

方法重写为子类在继承父类时,可以重写父类中的一些方法,从而实现多态性。

注意:重载与返回值没有关系。重写时,子类的方法访问级别不能比父类更严格。即父类为protected,子类不能为private。子类抛出的异常必须与父类一致,或者是父类异常的子类。

8.为什么要经常重写hashCode和equals方法:

两个方法的关系:如果equals相同,那么hashcode值必须相同,反过来则不一定相同。

在使用HashMap和HashSet等集合时,这些集合利用equals和hashCode确定元素的存储位置。如果不正确重写这两个方法,会导致无法判断对象的相等性。

重写equals方法,必须重写hashCode方法,因为两个对象如果equals方法相等,那么必须hashCode也是返回相等的值。

在基于哈希的数据结构,如果要判断是相等的,那么必须要先用hashCode方法判断哈希码是否相等,再用equals方法判断是否真正相等。由于不同的对象可能有着相同的哈希码,所以会用equals方法判断是否真正相等。

9.静态方法与实例方法:

特性静态方法实例方法
关键字static
归属对象
调用方式通过类名或对象对象
访问权限静态变量,静态方法静态变量,静态方法,实例变量,实例方法
用途工厂类方法,工厂方法改变对象的状态
生命期类加载时存在,类卸载时消失对象创建时存在,对象销毁时消失

10.Object类:

getClass方法:返回对象运行时的信息,通过该方法了解对象的实际类型。

常用于反射机制。

hashCode方法:返回对象的哈希码,哈希码用于在基于哈希的数据结构中,快速地查找对象。当重写equals方法时,也要重写hashCode方法,确保相等的对象有着相同的哈希码。

equals方法:比较两个对象的地址值是否相等,如要比较内容是否相等,需重写equals方法。

clone方法:创建并返回该对象的副本,默认是浅拷贝。即复制对象本身,但不复制其内部引用。

为了使用该方法,类需要实现Cloneable接口,并重写clone方法,否则会抛出异常。

toString方法:返回对象的字符串表现形式,默认返回对象的类名和内存地址的组合。

常常重写该方法返回有意义的字符串。

notify方法:唤醒一个等待在该对象上的线程。

该方法通常与synchronized和wait()方法一起使用,起到线程之间的协调。

notifyAll方法:唤醒所有等待在该对象上的线程。

wait方法有三个:

第一个:无限期等待。

第二个:等待指定的毫秒数。

第三个:等待指定的毫秒数和指定的纳秒数。

通常与synchronized一起使用,达到线程间的协调。

finalize方法:垃圾回收器回收对象时使用,用于清理工作。但不推荐使用,因为java的垃圾回收机制不可预测且过时,所以常使用try-with-resources和AutoCloseable接口进行资源管理。

11.包:

(1)将功能相似的类或者接口放在一个包下,便于类的查找与使用。

(2)包可以避免命名冲突。同一个包中的类名可以是不同的,但是不同的包的类名可以是相同的,只需要用包名加以区分即可。

(3)包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

既然说到了打包,那再来说说导包吧:

import关键字:为了使用别的包中成员,我们需要在程序中导入该包。

12.基本类型和包装类型:

基本类型:java中有8个基本类型,是直接存储数值的,变量位置取决于作用域和声明方式。

分别为short, int,  long, float, double, boolean, char, byte.

包装类型:java中每个基本类型都有一个包装类型,包装类型是类,存储在堆上,可用于面向对象编程。

分别为Short, Integer, Long, Float, Double, Boolean, Character, Char, Byte.

区别:

(1)性能方面:

基本类型占用内存小,效率高。

而包装类型由于是对象,需要涉及内存分配和垃圾回收,性能较低。

(2)比较方式不同:

基本类型只需==就可以判断是否相等。

而包装类型的==是判断对象地址是否相等,使用equals是判断对象内容是否相等。

(3)默认值不同:

基本类型默认值为0或false.

而包装类型的默认值为null.

(4)初始化方式不同:

基本数据类型直接赋值即可。

而包装类型需要new一个对象。

(5)存储方式不同:

基本类型如果是局部变量那么就存储在栈上面,如果是成员变量就存储在堆上面。

而包装类型保存在堆上。

自动装箱与拆箱:

在java中,我们很多时候用到的是包装类型而不是基本类型。在集合当中,我们是不能讲int,double这些类型放进去的,因为集合的中的元素要求是Object类型的,那么为了让基本类型有对象的性质,就把它们包装起来,并添加了相应的属性和方法。

装箱:基本类型自动转为包装类型对象。

拆箱:包装类型对象自动转为基本类型。

缓存机制:

包装类型中的Byte,Short,Interger, Long对一些范围内的值提供了缓存,提升了性能。

下面会通过Integer缓存池详细讲解:

java中的Integer缓存池是为了节省内存,提升性能的,因为实践中大多数操作都集中在值很小的范围内,因此缓存下来可以节省内存分配和垃圾回收的负担,提高性能。

java中Integer缓存的值在-128到127,这些值会被缓存下来复用。

过程:java在自动装箱时,如果int的范围在-128到127之间,会直接返回一个已经缓存的Integer对象,而不是创建新的对象。因此,同一数值的包装类型对象可能是同一实例。

下面是值在缓存池范围内的情况

下面是值不在缓存池范围内的情况

额外扩展:

Long, Short,Byte缓存范围也是-128到127

Float和Double没有缓存池,因为小数可以存的很多。

Character缓存范围为0到127,即ASCLL码表。

Boolean缓存两个值,true和false。

下面给出长度的总结: 

byte(Byte):1字节 -128到127

short(Short):2字节 -32768到32767

int(Integer):4字节 -21474836482147483647

long(Long): 8字节 -92233720368547758089223372036854775807

char(Character):2字节 Unicode字符集中任意字符

float(Float):4字节 约为-3.4E38到3.4E38

double(Double):8字节 约为-1.7E108到1.7E308

13.static关键字:

static的作用有许多:

首先来看下面代码

当我们如果要创建很多个学生对象时,那么每个对象的三个属性都会占用一定的内存,但是其实这些学生的school属性都是相同的,我们如果创建10000个学生对象,那么这10000个学生对象都各自占用一部分内存给school,那么是不是太浪费了?所以我们可以用static修饰,这样我们只要占用1块内存,而不是10000块。

那么此时我们的变量a在栈上,指向的是在堆中的对象的地址,其对象中有张三和18两个属性。

变量b也在栈上,指向的是在堆中对象的地址,其对象中有李四和16两个属性。

我们还有一个静态区,里面存放着school属性"MIT"。

再看下面一段代码:

我们每次创建对象,对象中都有各自的age值,自增完在打印,所以结果都为1,那么我们如果加上static修饰呢?

由于现在的age在静态区,所以我们每次都会自增静态区中的age,所以我们打印的为1,2,3。

这就是静态变量和成员变量之间的区别。

下面再说说静态方法吧:

(1)静态方法属于这个类,但是不是这个类的对象。

(2)调用静态方法时不用创建这个类的对象。

(3)静态方法可以访问静态变量。

change是一个静态方法,所以可以直接访问到静态变量age并修改,并且调用的时候直接用类名.上静态方法即可。主要,静态方法不可调用非静态方法和非静态变量。

那么我们可能会思考为什么main方法是用static修饰的呢?

public static void main(String[] args)

首先我们已经知道静态方法是不用创建对象的,所以,如果不是静态的,对于jvm而言,在执行时要先创建对象,但是main函数是程序执行的入口,创建一个对象就显得多余了,所以用static修饰。

下面再说说静态代码块吧:

来看下面的代码:

我们看到静态代码块优先于main函数执行。但是程序中没有main方法在JDK1.6是可以的,但是在JDK7就不行了。

那么实际开发中静态代码块到底有什么用呢?

a是一个静态的ArrayList,所以不太可能在初始声明时就初始化,因此我们可以在静态代码块中完成初始化。在开发中,我们常常使用静态代码块配置文件到内存中。

14.instanceof关键字

instanceof关键字是判断对象是否是指定的类型。如果不判断的话那么可能会出现ClassCastException 异常。

来看instanceof的运用

最后的结果是true,因为Bigtree是tree的子类,所以说Bigtree和Tree是is-a的关系,故返回true.

同理,对于接口也是如此。

再看以下代码,是我们比较常用的方式,先把当前对象使用instance进行类型判断,然后进行类型强制转换。以下就是两种方式:

第二种方式是JDK16的时候新增的,使代码更加便捷。

三:总结

看到这里,您是不是对于java的面向对象已经有所了解了呢?本文中的所有代码难度不大,应该对初学者比较友好,可以自己练习一下,毕竟编程最重要的就是实践,没有亲自去写,那么就不能抓住代码中的细枝末节,当然也就没有彻底理解。所以,大家要多写,多练,这样才能提高自己!

如果有疑问或者错误的地方可以私信我或者评论区留言。

感谢您的阅读,我们下篇文章详解JAVA集合时再回。

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

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

相关文章

基础数据结构——队列(链表实现)

队列的性质 先进先出(FIFO - First In First Out):最先加入队列的元素最先被移出后进后出(后来的元素排在队尾)只允许在队尾插入元素,在队首删除元素具有先来先服务的特点 链表实现队列 和之前创建链表相…

单纯的查询而言,vector和map谁更快

单纯的查询而言,vector和map谁更快 文章目录 单纯的查询而言,vector和map谁更快一、vector的查询二、vector和map对比三、总结 一、vector的查询 这道题目需要知道vector查询和随机访问的不同。 假设有一个包含 n 个元素的vector集合,需要查…

大A终究是逃不过高开低走的魔咒

大A终究是逃不过高开低走的魔咒,早盘高开太多,周末休市,今天会议结束,各种不确定因素增加等原因导致午盘普跌。其实还是那句话,股市嘛,涨多了会跌,跌多了会涨,别急也别慌。 周末&…

Ceisum无人机巡检视频投放

公司投标内容有个视频投放的功能动画,原本想实现这么一个效果: 案例效果来自别人的展示作品,Leader一眼就相中了这个效果,可惜别人的终究是别人的,又不会白白给你,终究是要自己动手尝试。 动画方面的展示…

Rust闭包(能够捕获周围作用域变量的匿名函数,广泛应用于迭代、过滤和映射)闭包变量三种捕获方式:通过引用(不可变引用)、通过可变引用和通过值(取得所有权)

文章目录 Rust 闭包详解闭包的定义与语法基本语法 闭包的特性- 环境捕获(三种捕获方式:通过引用、通过可变引用和通过值(取得所有权))示例代码 - 内存安全与生命周期示例代码1 示例代码2:闭包所有权转移示例…

【国内中间件厂商排名及四大中间件对比分析】

国内中间件厂商排名 随着新兴技术的涌入,一批国产中间件厂商破土而出,并在短时间内迅速发展,我国中间件市场迎来洗牌,根据市占率,当前我国中间件厂商排名依次为:东方通、宝兰德、中创股份、金蝶天燕、普元…

Java 源码中的 Unicode 逃逸问题,别被注释给骗了

背景 看了一段项目源码,定义了一个 List 对象,往该列表对象 add 的代码前面有注释符号,但是程序运行时列表中却存在对象,为什么呢?仔细看了一下,注释符号和 add 代码之间有一个特殊符号 \u000d&#xff0c…

基于IM场景下的Wasm初探:提升Web应用性能|得物技术

一、何为Wasm ? Wasm,全称 WebAssembly,官网描述是一种用于基于堆栈的虚拟机的二进制指令格式。Wasm被设计为一个可移植的目标,用于编译C/C/Rust等高级语言,支持在Web上部署客户端和服务器应用程序。 Wasm 的开发者参…

基于百度飞桨paddle的paddlepaddle2.4.2等系列项目的运行

PPASR 必看&#xff01;&#xff01;&#xff01; PaddleSpeech develop --> PaddlePaddle 2.5.0/2.5.1 PaddleSpeech < 1.4.1 --> PaddlePaddle < 2.4.2 1.创建虚拟环境 conda create --name test python3.10 2.激活环境&#xff0c;安装ppasr的paddlepaddl…

2024MoonBit全球编程创新挑战赛参赛作品“飞翔的小鸟”技术开发指南

本文转载自 CSDN&#xff1a;https://blog.csdn.net/m0_61243965/article/details/143510089作者&#xff1a;言程序plus 实战开发基于moonbit和wasm4的飞翔的小鸟游戏 游戏中&#xff0c;玩家需要通过上下左右按键控制Bird&#xff0c;在不断移动的障碍pipe之间穿梭&#xf…

浅谈Agent

目录 什么是大模型 Agent &#xff1f; 大模型Agent 有哪些部分组成? 规划&#xff08;Planning&#xff09; Planning类型 不依赖反馈的计划 基于反馈的计划 拆解子目标和任务分解方法 COT TOT GOT LLMP 反思和完善 ReAct(融合推理与执行的能力) Reflexion(动态…

文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现

在众多的 AI 大模型的应用场景中&#xff0c;Text-to-SQL&#xff0c;也就是文本转 SQL&#xff0c;是其中实用性很高的一个。Text-to-SQL 充分利用了大模型的优势&#xff0c;把用户提供的自然语言描述转换成 SQL 语句&#xff0c;还可以执行生成的 SQL 语句&#xff0c;再把查…

DICOM标准:深入详解DICOM医学影像中的传输语法

引言 DICOM&#xff08;数字成像和通信医学&#xff09;标准在医学影像数据交换中扮演着至关重要的角色。其中&#xff0c;*传输语法&#xff08;Transfer Syntax&#xff09;是DICOM标准中定义数据编码和传输方式的核心部分。理解传输语法对于确保不同设备和系统之间的互操作性…

如何提高谷歌收录速度?

相信很多做外贸推广的朋友都遇到过这种情况&#xff1a;网站上线了&#xff0c;但新页面迟迟不被谷歌收录。即使你的内容很优秀&#xff0c;设计也很精美&#xff0c;如果谷歌爬虫抓不到页面&#xff0c;一切努力就白费了。这时候&#xff0c;GSI谷歌快速收录服务就成了“救命稻…

Spring面向切面编程

目录 1.AOP概述及Spring AOP实现原理 AOP概述 AOP的应用场景 AOP的作用 Spring AOP概述 Spring AOP的实现原理 Spring AOP中Advice的分类 2. 通过xml配置实现AOP 实现步骤&#xff1a; 新增模块&#xff1a; 导入相关依赖&#xff1a; 新增实体类User 新增业务类UserS…

Notepad++ 更改字体大小和颜色

前言 在长时间编程或文本编辑过程中&#xff0c;合适的字体大小和颜色可以显著提高工作效率和减少眼睛疲劳。Notepad 提供了丰富的自定义选项&#xff0c;让你可以根据个人喜好调整编辑器的外观。 步骤详解 1. 更改字体大小 打开 Notepad 启动 Notepad 编辑器。 进入设置菜…

香港航空 阿里滑块 acw_sc__v3 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…

Unet++改进3:添加NAMAttention注意力机制

本文内容:添加NAMAttention注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 识别不太显著的特征是模型压缩的关键。然而,它在革命性的注意机制中尚未得到研究。在这项工作中,我们提出了一种新的基于归一化的注意力模块(NAM),它抑制了较不显著…

WPF+MVVM案例实战(二十二)- 制作一个侧边弹窗栏(CD类)

文章目录 1、案例效果1、侧边栏分类2、CD类侧边弹窗实现1、样式代码实现2、功能代码实现3 运行效果4、源代码获取1、案例效果 1、侧边栏分类 A类 :左侧弹出侧边栏B类 :右侧弹出侧边栏C类 :顶部弹出侧边栏D类 :底部弹出侧边栏2、CD类侧边弹窗实现 1、样式代码实现 在原有的…

汽车广告常见特效处理有哪些?

​汽车广告作为展示汽车性能和外观的重要媒介&#xff0c;常常需要借助特效来增强视觉效果&#xff0c;吸引观众的注意力。以下是一篇关于汽车广告中常见特效处理的文章。 在竞争激烈的汽车市场中&#xff0c;广告不仅是推广产品的工具&#xff0c;更是艺术和科技的结合。特效技…