抽象类和接口

目录

抽象类

接口:

定义接口:

接口特性:

实现接口:

拓展接口:

Object

toString

hashCode:

知识补充:内部类

静态内部类:

实例内部类:

匿名内部类

匿名对象

常用接口实现

Comparable

对象的比较

对象的排序

比较器

Cloneable接口和深拷贝

深拷贝


 

抽象类

作用:校验

被abstract修饰的方法叫做抽象方法,含有抽象方法的类必须加abstract,叫做抽象类,抽象类可以含有不抽象方法

除了不能被实例化和加abstract以外,其他成员变量方法等规则均与普通类相同。

抽象方法必须被子类重写(前提是这个子类不是抽象类,若子类是抽像类不需要重写方法),并且抽象方法必须要写成:void func();

不能指代具体事物的均可以抽象为抽象类,比如:Animal,People;

注:抽象方法不能被private,static,final修饰,因为抽象方法必须被重写;抽象方法的构造方法的作用是让子类调用,帮助其初始化。

接口:

定义接口:

使用关键字:interface加接口名

一般定义接口名的时候以大写“I”开头,并且接口名最好是形容词

接口特性:

接口中不加static或者default都会默认为是抽象方法,不能有具体实现,必须写成void func();的形式(即不能加{}),因此接口理所当然不能被实例化

在接口中定义的成员变量默认为:public static final;

在接口中定义的方法默认为       :public abstract;

因此为了代码简洁,可以对成员变量和方法进行简写:

1949c1e3d4da4b3686c8ef4a432e7c6f.png

接口同样可以发生向上转型和动态绑定;

cd42fd6b0e6242aaab43ae784b7d56c3.png

结果为:76dc3d8f0f9449c7ad81f813952b3b09.png

接口不能有静态代码块,和构造方法

如果一个类不能实现接口内所有的抽象方法,那这个类必须定义为抽象类

实现接口:

通过关键字:implements

一个类可以实现多个接口,实现接口后,必须重写里面的抽象方法

设置接口的好处: 

f8b3f2889c454398b1dd64533e4bfb04.png

拓展接口:

接口可以拓展接口,关键词:exdends,接口A拓展了接口B后,就可以拥有B中的方法;

抽象类和接口的主要区别:

1,接口内不能含有普通方法和字段;

2,解决了java当中不能多继承的缺陷;

Object

所有类的父类,所有类都直接或间接继承于Object,因此可以用Object接收所有类的对象

ec30a8beabb64b96821d85216c4cc2cd.png

我们来实现其中比较常用的方法:

toString

该方法之前已经实现过,详见toString实现

equal

equal可以比较字符串内容是否相等,但是当euqal被对象引用时,那么就会调用该对象内equal的方法,当该类中没有这个方法,那么就会调用Object的方法,查看Object内的原码:

81000ecc319d428eaa0c88215f042ba5.png

可知,Object中的方法是比较两个对象的地址,那如果我们想要通过对象引用来比较他们的name属性值是否相同的时候就需要重写equal方法

未重写前结果为false:

d3ad58dd9ad840e0b7da9b3cdc61e14f.png

重写后,结果为true,重写后的equals:

c8c8a64adcab405398f0b3073a19d533.png

强调:在这里,新人可能会搞混,为什么重写equals,还要用equals方法去做比较,前面我已经说过了,对象调用方法,那肯定是去从该对象内找方法进行调用,this.name这个是字符串也就是String类,String类里有自己的equals,因此此处调用的是String类中的equals方法,可以自行查看String中equals的方法

注意向下转型可以访问子类特有的方法和字段,但是在向上转型中,只有子类方法重写后才会调用子类的方法,不存在子类字段重写后调用子类字段(因为向上转型需要动态绑定,字段没有动态绑定,因此字段也没有重写这一说)

hashCode:

Object方法中使用hashCode返回的是对象地址值,因为其最底层是用C++写的,所以无法看到,但当我们有类似这样的需求

b491f7f1a45840239ef62614215cef14.png

当名字和年龄相同时,那么我们调用per1.hashCode(),和per2....时,两者值相同那么我们可以重写hashCode

923b080ee82f4a55a128d03514152bb6.png

知识补充:内部类

当一个事物内部,需要一个完整的结构需要描述,而这个内部完整结构,又只为外部事物提供服务,那么称之为内部类,就是一个类定义在类或者方法的内部,那这个类成为内部类,后者成为外部类

比如:火车车厢是火车的一部分,就可以在火车这个类中定义车厢

4f72ffdf6b9941a9aff8dbb79d0f9b03.png

内部类分为:

静态内部类,实例,,,内部,,,匿名,,,, 

静态内部类:

静态内部类和普通类一样可以有构造方法,自己的成员变量和方法,静态内部类能实例化,格式为:外部类.内部类(),即可调用静态的内部类的成员

86bfc1cc3b8b44b69a80472badd7ec30.png

静态内部类不能直接访问外部类的非静态成员和方法,因为依赖外部类对象,创建外部类对象即可

实例内部类:

命名方式:class+类名

实例内部类中不能定义静态变量(因为内部类依赖对象,static不依赖),如果想被static修饰,那必须为常量,该常量必须在定义的时候赋值,常量在编译的时候就会确定

7ba4779f972f40209fc7b2834f662545.png

实例内部类中可以直接调用外部类的成员,但必须在方法内;当内部类中有和外部类相同的时候,在内部类中会优先使用内部类成员;如果想在内部类中调用外部类的重名的成员可以在内部类中创建外部类对象进行引用;或者通过this,但this具体指外部类还是内部类取决去谁调用了this

69ea3874d6e8418bb0caa79bd0ca758b.png

实例内部类依赖外部类对象,所以要想调用实例内部类,就要先创建外部类对象;

af497d725bb94c54b9c5e670a5daae46.png

注意:new Test()所创建的对象可以不被接收,因此之只写new Test()也不会编译异常

9e33fc8276b04cc483fc4b7c18d3e53d.png

相较于静态内部类,实例内部类需要创建对象较为繁琐

匿名内部类

匿名对象

b05d7e5c49ce4c7aa443aa3471205db7.png

同样调用func调用了两次,上面的只创建了一个对象,而下面的创建了两个对象,同时Test().func被称为匿名对象

匿名内部类:

f922b3f3ae52495eb428d775c5f24b00.png

e4872b08bdfc41e6b7bdcccab8b36cfb.png

此时就可以用a去调用接口中func()方法。可以理解为,使用匿名内部类可以单独实现接口中的方法,不需要再创建其他类实现接口再去调用;(相当于为实例化接口创造了一个方法)

ad723f96387c4feeb0f44b20052e2e9e.png

匿名内部类应该写在方法里,不能写在类里方法外,否则会报错

局部内部类很少用这里就不多赘述

常用接口实现

Comparable

对象的比较

06cf4f7cb99541049492d02830c06f93.png

如果想对student1和2进行名字或者年龄排序,不能直接用>等符号进行比较(引用类型不能直接比较)

如果想通过名字进行比较,可以通过字符串中compareTo方法进行比较,返回类型是int,查看源码可知,String实现了Comparable中的方法

cad9b1b14e3d4c34a2fae5e32a944d2c.png

因此当我们想让compareTo直接去比较对象时,我们就要在该对象中重写该方法

118166f00e2a46bcb4ca10ea31722195.png

仔细观察发现,参数处不是接口类型,不需要用到向下类型转换,这部分知识后面咋学习(实在看不行,自己写接口重写方法,甚至如果只是为了比较这一个类的对象都无需写接口,只需要在该类中写对应方法,自己调用对应方法即可)

下图是通过自己写接口来重写方法的

87355158172c4445b122b39b362be8f0.png

言归正传:要想实现系统中comparable的写法

89d725ad04f749a09a551086492f7e3b.png

“<>”内写相比较的类型,这部分知识后续探究

对象的排序

当我们有一个数组,数组里的元素是自定义对象时,我们想对数组里的对象进行排序;

82cd67c19a2e40c5b3345f66343083f0.png

当我们用数组中Arrays.sort()方法的时候,系统出现了类型不可转换异常

6a4045570d404284a405ba16cb7da832.png

当我们去看Arrays.sort的原码时,发现比较前会被强转为Comparable类型,但因为Student未实现Comparable接口,所以抛出异常,因此我们需要实现Comparable接口,Arrays.sout中用到的比较方法是compareTo,因此重写这个方法后就可以通过名字或者年龄进行排序。需要注意的是comapreTo返回的类型是int。

24fdf9d992a14d389d4b4890338be604.png

04a57b4909f54a46935dca51688ecbc1.png

此时数组是通过年龄排序的,并且如果想要逆序可以写成o.age - this.age

拓展:

Arrays.sort()可以传第二个参数,第二个参数是个比较器,可以通过传入比较器从而来选择用年龄还是名字排序

2a0b876d66dd4b45ae76888d927759aa.png

b78717528c3c4257bf5958e9ec685ec6.png

自己实现排序功能

21bbb44631ed49ae8d0aa912e139075f.png

1.学会冒泡排序;2用compareTo就行比较;3创建接口

比较器

由于compareTo只能选择一种方式进行比较,所以有了Comparator

275b845f73324eafb6f5b90bf11e7dbf.png

创建这两个类实现Comparator接口,就可以通过name或者age进行比较

6f11b8015cd0475eb402b6ed07f4e4ac.png

实现Comparator的好处是固定写法,省事(目前个人拙见)

Cloneable接口和深拷贝

当我们想要将某一个对象克隆给另一个对象的时候我们会用到clone();

遇到的问题

1 该方法在Object中存在,但直接用子类调用会报错,是因为父类中这个方法被protected修饰,因此需要在子类中重写

a7088be9ed80402b9f9eaad4a1155fe5.png

2 要被克隆的类需要实现一个空接口——Cloneable,这个接口又叫标记接口,实现了这个接口说明这个类是可以被克隆的(深度学习以后探究)

3 使用该方法的时候必须要在main函数后抛出异常

b26411518c124d168089fbd7ab4e7dc5.png

4 见代码第三行,发生了强转,因为clone()返回的是Object对象

深拷贝

clone()是浅拷贝:

afa4a9ceb8954b599976fa6c06f13206.png

可见通过对象的引用clone后,对象中的对象并没有创建新的对象,因此不能达到深拷贝的效果

其中Money是类

2fa4b4cb771240efb462bf709465543c.png

当我们在Student类中定义Money类字段的时候,要注意在构造方法中不能这样写

a358b0225e464ebcb915ad42f1fe9c3c.png

运行时会抛出空指针异常,因为此时this这个对象并没有实例化Money这个对象;所以正确写法是要在构造函数内就实例化好对象

e739a6ded6f24320a25341be920f08e5.png

要想深拷贝,不仅要clone()对象,还要clone对象里的对象,因为我们要clone() Money的对象,所以也要在Money这个类中实现clone()接口,并抛出异常。接下来我们就要修改Student中clone方法以达到深拷贝。

88ab13359c7f48968c9c40786ecfaf8a.png

因为retrun只能返回一个对象,所以我们通过中间引用变量去返回,第一步是克隆Student对象,第二步是克隆Student对象中的Money对象;

具体为什么第一行是super.clone(),第二行是却用this

记住就行,因为父类的clone方法是用C++写的,所以看不见,而this.m要确定克隆的对象,后面的clone()也是通过父类的clone实现的,因此要在Money类中重写clone().

以上是常见接口的使用,一定要自己动手实现。

 

 

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值