接口的初步认识及编码

接口

需求:需要飞到北京出差
飞机、鸟和超人不能归于一个类属, 但是具备有相同的特性:会飞的。所以引入了一个新概念叫做接
口,可以用于规范实现接口的类中必须实现接口中抽象方法。接口可以理解为一种契约使用关键字interface定义接口
●接口中只能定义抽象方法,从DK1.8引入default关键字开始允许提供默认实现

 public interface 会飞的{
public void起飞O; 
public void 巡航飞行O;
public void降落O;
}
接口不能直接使用,必须有对应的实现类
public class飞机类 implements 会飞的{ //共性 是通过实现接口来表示的
private string name; //名称, 这是类属的属性,这里可以定义字节类的成员,和接口无关
//如果当前类不是抽象类,则必须实现接口中的所有抽象方法
@override
public void 起飞O {
system. out .print1n("使劲的跑,一抬头就 飞起来了");
@override
public void 迎航飞行O {
system. out .print1n("使劲的烧油..");
@override
public void 降落O {
system. out .print1n("我对准...");
通过接口定义变量,使用具体类的实例,进行调用
会飞的obj = new 飞机类O;
? obj.起飞O;
obj. 巡航飞行O;
obj .降落O; 
引入接口的目的在于隔离实现
public void 出差(飞机obj){}
? //这种写法当前类和飞机是耦合的,如果需要坐超人出差,则必领修改源代码
public void出差(会 飞的obj){}

//当前类只是和接口耦合, 任何实现了接口的对象都可以作为参数进行传入
使用接口而不是使用具体的类,则可以实现在实现接口的多个具体实现类之间进行更换,例如定义出超人

什么是接口

在Java中不直接支持多继承,因为会出现调用的不确定性,所以Java将多继承机制进行改良,在Java中
变成了多实现。一个类可以实现多个接口,-个接口可以继承多个接口

interface IA{}//按口中如果不使用defau1t只能定义抽象方法,也可不定义方法。如果没有方法
的接口称之为标识接口或者旗标接口
 interface IB{}
interface IC extends IA,IB{} //正确的, 类不允许多重继承,接口允许多 重继承。其中IC中
的方法等于IA+IB
class A implements IA,IB{} //允许一个类实现多个接口
 //要求实现类必须实现所有接口中的抽象方法,否则当前类就是抽象类
A a=new AO;
B b=new AO);
//接口是一 种特殊的抽象类,接口只能被abstract或者public修饰。 实际上从语法的角度上说,外部接口还允许package范围限定,但是跨包不能访问,所以不使用
●没有构造器方法
public interface IA {
public IAO {} //语法报错
 }
●没有属性,只能定义常量
public interface IA {
//I11ega1 modifier for the interface field IA.age; only public,
static & final are permitted
private int age; 
string USER NAME="zhangsan"; //这里定义的限定词可以不写,默认就是pub1ic
static final. 如果要写不能冲突
//常量的命名规范,全大写,下划线分词
}

●可以包含抽象方法,也可以没有抽象方法。从DK1 8开始允许在方法前添加关键字default定义方法
的默认实现
●在JDK1.8中允许在接口中定义静态方法

interface IC1 extends IB1 {
//在JDK1 .8中允许在接口中定义静志方法
public static void ffO { //这个静态方法可以通过接口名称直接调用
IC1. ffO),注意没有抽象静态方法的概念
system .out. prinf0f(Fffff*);
}
}

抽象方法必须在实现类中提供实现

interface IA{} //定 义接口
class AImp1 implements IA{} //实现类
●可以使用default关键字给抽象方法提供默认实现, 有默认实现的方法在实现类中可以重新定义,也
可以不重新定义
报错原因: Java中不支持类的多重继承,-个类只能有一个双亲类, 但是允许接口多重继承
public class A{}
public class B{}
public class C extends A,B{} //语法错误
接口
public interface A{}
public interface B{}
public interface C extends A,B{} //语法正确
default带来的问题
| interface IA2 (
default void ppO《
System . out .print1n("IA2 default"); }interface IB2《
default void ppO《
system. out .print1n("IB2 default");
}:
 //语法报错的原因是pp方法的实现不唯一
 interface IC2 extends IA2,IB2 {
//提供新的默认实现即可以解决报错问题
default void ppO {
IA2. super. ppO; //调用IA2接口中的默认实现
system. out .print1n("IBC defau1t");
IB2. super. ppO;//调用IB2接口中的默认实现
//语法报错的原因是pp方法的实现不唯一
class D2Imp1 implements IA2, IB2 {
//提供新的方法实现即可以解决报错问题
@override
public void ppO {
IA2.super. ppO; //调用IA2接口中的默认实现
System . out .print1n("D2Imp1 implements");
IB2. super. ppO;//调用IB2接口中的默认实现
}}

最佳编程实践

允许-一个类实现多个接口,但是每个接口的抽象方法都必须提供实现,否则是抽象类。提供的实现也可以是继承
●首先通过接口定义调用的规范
●然后使用抽象类实现接口,其中定义公共实现
●最后定义子类继承抽象类,实现所有的抽象方法

 pub1ic interface IAl{
public void p1();}
 publ1ic interface IA2{
public void p2O;
|}
 public class Al{
public void p1O0} } public class A2 extends A1 implements IAl, IA2{
public void p2O{} //继承实现了p1方法, 由于A2类 不是抽象类,所以必领实现p2方法
}
public abstract class A3 extends Al implements IAl, IA2{}//因为p2方法没有实现

接口的出现避免了单继承的局限性,这样定义C接口则拥有A+B的所有定义,可以使用A和B接口以及父类D声明变量类型,直接new T。但是约束时,用谁声明变量编译器系统识别就是谁这种类型,也就意味只能调用识别类型中的方法,不能调用其他方法

interface A
public void p1O;
interface B
public void p2O;
interface C extents A,B{} //语法正确, 接口允许多重继承。但是类不允许多继承
class D{
public void abcO{}
class T extends D implements C{
public void p1O{}
public void p2O{}
}
D d-new TO ;这里只能调用abc方法, 如果使用其他方法则需要进行类型转换
A a-new TO) ;这里只能调用A接口中声明的方法p1
B b-new TO ;这里只能调用B接口中声明的方法p2
T tenew TO; 可以调用所有方法

语法规则

1| 访问修饰符interface 接口名{ }一 般建议接口名称使用形容词,外部接口范围限定词可以使用public或者默认package,内部接口4个都能使用,如果定义public接口, 则规则和定义pubic类- 致,要求接口名称和文件名称-致。一个文件中可以定义无数个类或者接口,但是只能定义一个公共类或者公共接口,要求public和文件名称-一致,在一个包中不允许名称冲突,不论是接口名称还是类名称。记得接口也是一 种特殊的类
●外部的接口只能使用public. 默认这两个范围限定词;如果定义内部接口则可以使用4大范围限定词
●接口实际上提供了同一的操作界面(方法) , 如果是DK1.8-版本则- 一个方法也不实现,等待某类或某几个类去实现它的方法[接口中的所有方法必须是抽象的]。如果使用的是DK1.8+允许使用,default在接口中定义默认实现,这个实现允许在实现类中重新定义覆盖,同时允许定义静态方法
●接口中没有属性,只能定义常量,它提供一些常量,实现它的类可以共享这些常量,接口可以给出访问控制符,用public修饰的是公共接口, 到处可见;如果定义接口没有范围限定词,则只能在同包中访问
●在接口中不能定义静态块static0,但是可以定义静态方法。静态方法必须有实现,没有抽象静态方法的概念
接口中不能定义构造器,不能定义非静态代码块
接口不能被实例化,只能通过实现类所实现,但是可以用于声明变量的类型。
接口变量名=new实现接口类O;
接口的特殊特征
●一个类只能有一个父类!
●一个类可以实现多个接口!
●-个接口可以继承多个接口

接口的作用

●统一访问
按接口obj-new 实现1;
可以还有实现2,实现3等
obj 只能调用接口中定义的方法
●解耦通过接口可以隔离具体实现
解耦就是在使用者和实现者之间没有关系。无论实现者如何改变实现, 对于使用者使用不会变化

接口和抽象类的异同点

●相同点:都是不断向.上抽取而来的
●不同点:
。抽象类需要被继承,而且只能单继承
。接口需要被实现,而且可以多实现
●抽象类中可以定义抽象方法和非抽象方法,子类继承后可以直接使用非抽象方法。定义抽象类的主要目的在于延迟实现和公共方法骨架
●接口中只能定义抽象方法,必须由子类去实现; JDK1.8+中允许接口中的方法有默认实现,实现类中可以直接使用默认实现,允许覆盖定义
●抽象类的继承是is a关系,在定义该体系的基本共性内容
●接口的实现是like a关系,在定义体系额外功能
●接口中只能定义常量,而且必须被初始化,抽象类中可以定义属性,允许在声明时直接初始化,也可以不初始化,同时允许定义常量接口中的方法必须全部是抽象的(DK1.8+版本中可以通过default关键字定义方法的默认实现,允许定义静态方法),抽象类中可以有抽象方法也可以有普通方法

如何使用接口

一般使用接口隔离具体实现,可以将类之间的相互依赖变为类对接口的依赖。例如出差类和会飞的东西是通过会飞的接口进行隔离,这样不管出差类需要修改或者会飞的东西需要修改,都不会相互影响
如果- -组相关的类中有公共的方法和特殊的方法,可以使用抽象类,在抽象类中固化公共的方法,而无需具体子类重复实现:但是在抽象类中无法实现的方法可以延迟到子类中再实现。例如排序器BubbleSorter,其中抽象类BubbleSorter固化了 所使用的冒泡排序算法,而将无法实现的bigger比较算法延迟到BubbleSorter的子类PigSorter中实现,同时PigSorter中也不需要重新定义排序算法
最佳软件开发实践:先定义接口规范调用方法,在使用抽象类实现接口定义公共方法,最后再定义具体子类实现所有的方法

接口和抽象类的使用场景

从设计层面看,抽象类体现继承关系isa,它主要描述类的从属关系或者父子关系,抽象类和它的派生类之间是典型的IS-A关系,即子is 父。
interface可以多实现,而且不要求实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。它主要描述的是类型间的行为合同,接口和它的实现类之间是典型的CAN-DO关系,即子can do父。
为什么接口需要默认方法
在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。

Comparable和Comparator接口

int k=10;
if(k>0)
3|
int aa=100;
System. out. print1n(aa);

Comparable接口

含义是可比较的,如果对象所在的类实现了Comparable 接口,这类对象就是可以进行大小的比较,接
口就是用于指定对象排序规则的
此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序,类的compareTo方法被称为它的自然比较方法。实现此接口的对象列表(和数组)可以通过Collections.sort (和
Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器。
强烈推荐(虽然不是必需的)使自然排序与equals -致。所谓与equals- 致是指对于类C的每一个e1和e2来说,当且仅当(e1.compareTo((Object)e2) == 0)与e1.equals((Object)e2)具有相同的布尔值时,类C的自然排序才叫做与equals一致。

public interface Comparable<T> {
public int compareTo(T o); //必须实现的方法, 这里定义两个对象的比较规则,如果相
当返回为0:如果当前对象大于参数o则返回正数:如果当前对象小于参数o则返回负数
}
例如猪是可比较的,则需要Pig类实现Comparable接口
 public class Apple implements Comparable {
private double re; //半径值
@override
public int compareTo(object obj) {
if (obj != nu11 && obj instanceof Apple) {
Apple app■CApp1e) obj;
if (this.re > app.re){
return 1:
} else if (this.re =- app.re){ //浮点数无法精确存放
Math. abs(this.re-app.re)<le-6
return 0;
}
}
return -1;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FFmpeg是一个开源的多媒体框架,它提供了许多对音视频的处理、编解码、封装等功能的API接口。下面是关于FFmpeg封装编码接口的介绍。 封装接口 FFmpeg封装的主要作用是将音视频数据打包成一个容器格式,例如AVI、MP4、MKV等。在FFmpeg中,封装的主要接口是AVFormatContext。通过AVFormatContext可以设置封装格式、音视频流的参数、写入数据等。 下面是一个简单的示例代码: ``` AVFormatContext *fmt_ctx = NULL; avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, filename); if (!fmt_ctx) { // error handling } // 添加视频流 AVStream *video_stream = avformat_new_stream(fmt_ctx, NULL); if (!video_stream) { // error handling } video_stream->codecpar->codec_id = AV_CODEC_ID_H264; video_stream->codecpar->width = width; video_stream->codecpar->height = height; video_stream->codecpar->format = AV_PIX_FMT_YUV420P; // 添加音频流 AVStream *audio_stream = avformat_new_stream(fmt_ctx, NULL); if (!audio_stream) { // error handling } audio_stream->codecpar->codec_id = AV_CODEC_ID_AAC; audio_stream->codecpar->sample_rate = sample_rate; audio_stream->codecpar->channels = channels; audio_stream->codecpar->channel_layout = av_get_default_channel_layout(channels); // 打开输出文件 avio_open(&fmt_ctx->pb, filename, AVIO_FLAG_WRITE); avformat_write_header(fmt_ctx, NULL); // 写入数据 AVPacket pkt = { 0 }; av_init_packet(&pkt); // 写入视频数据 avcodec_send_frame(video_codec_ctx, frame); while (avcodec_receive_packet(video_codec_ctx, &pkt) == 0) { av_write_frame(fmt_ctx, &pkt); av_packet_unref(&pkt); } // 写入音频数据 avcodec_send_frame(audio_codec_ctx, frame); while (avcodec_receive_packet(audio_codec_ctx, &pkt) == 0) { av_write_frame(fmt_ctx, &pkt); av_packet_unref(&pkt); } // 关闭输出文件 av_write_trailer(fmt_ctx); avformat_free_context(fmt_ctx); ``` 在上面的代码中,我们首先创建了一个AVFormatContext对象,并设置了要输出的文件名和封装格式。然后,我们添加了一个视频流和一个音频流,并设置了它们的参数。接着,我们打开了输出文件,并使用avformat_write_header()函数写入文件头。最后,我们使用av_write_frame()函数将编码后的数据写入文件,并使用av_write_trailer()函数结束文件的写入。 编码接口 FFmpeg的编码接口主要用于将原始音视频数据编码成压缩格式,例如H.264、AAC等。在FFmpeg中,编码的主要接口是AVCodecContext。通过AVCodecContext可以设置编码器类型、编码参数、输入数据等。 下面是一个简单的示例代码: ``` AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { // error handling } AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { // error handling } codec_ctx->width = width; codec_ctx->height = height; codec_ctx->framerate = { fps, 1 }; codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; codec_ctx->time_base = { 1, fps }; codec_ctx->gop_size = 10; codec_ctx->bit_rate = 1000000; avcodec_open2(codec_ctx, codec, NULL); AVFrame *frame = av_frame_alloc(); if (!frame) { // error handling } frame->width = width; frame->height = height; frame->format = AV_PIX_FMT_YUV420P; av_frame_get_buffer(frame, 0); AVPacket pkt = { 0 }; av_init_packet(&pkt); // 填充视频帧数据 ... avcodec_send_frame(codec_ctx, frame); while (avcodec_receive_packet(codec_ctx, &pkt) == 0) { // 处理编码后的数据 av_packet_unref(&pkt); } ``` 在上面的代码中,我们首先使用avcodec_find_encoder()函数查找H.264编码器。然后,我们创建了一个AVCodecContext对象,并设置了编码器的参数。接着,我们使用avcodec_open2()函数打开编码器。接下来,我们创建了一个AVFrame对象,并使用av_frame_get_buffer()函数分配内存。最后,我们使用avcodec_send_frame()函数将原始数据发送给编码器,并使用avcodec_receive_packet()函数获取编码后的数据。 总结 FFmpeg提供了许多封装、编码、解码等功能的API接口,可以方便地进行音视频处理。在使用FFmpeg进行封装编码时,需要了解AVFormatContext和AVCodecContext等对象的使用方法,并根据具体的需求进行参数的设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值