JavaSE1面向对象4高级.docx
《JavaSE1面向对象4高级.docx》由会员分享,可在线阅读,更多相关《JavaSE1面向对象4高级.docx(19页珍藏版)》请在冰点文库上搜索。
![JavaSE1面向对象4高级.docx](https://file1.bingdoc.com/fileroot1/2023-6/8/998a9bc5-a50d-40fc-b08f-7ac5fe33738a/998a9bc5-a50d-40fc-b08f-7ac5fe33738a1.gif)
JavaSE1面向对象4高级
1、课程名称:
面向对象(高级)
2、知识点
2.1、上次课程的主要知识点
1、面向对象的三个特征:
封装、继承、多态
·封装:
封装可以封装类中的任意的操作,包括属性、方法、构造方法,但是封装之后类中的内容对外部不可见,不可见在进行一些简单操作的时候将非常的麻烦,所以后来使用了内部类来解决的这样问题,但是内部类本身会破坏程序的结构。
所以在此基础之上为了可以方便的扩充类的功能,加入了继承。
·继承:
继承就是扩展已有类的功能的,但是一般的继承并不是继承一个普通的类,而是继承抽象类或实现接口,但是抽象类和接口本身不能直接实例化,所以需要依靠多态性,以通过子类实例化。
·多态:
一个同样的功能操作,可以根据其所在位置的不同,完成的具体操作也不同,包括方法的重载、方法的覆写、以及最重要的对象的多态性,父类或父接口根据实例化其子类的不同,完成的具体操作也不同。
但是操作的标准都是一样的。
2、抽象类和接口的概念及实例化操作
·抽象类本身具备的是一种模板设计,可以按照固定的操作完成相关的代码。
·接口本身以一种标准的形式出现。
3、对象多态性:
子类和父类实例进行相互转型
·向上转型,自动完成的,使用父类接收子类的实例,此种用法使用的最多
·向下转型,强制完成,但是在进行向下转型之前首先一定要发生向上转型,以建立关系,但是一般使用较少
4、设计标准:
一个子类永远不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口。
5、Object类:
是所有类的父类,可以接收所有对象的引用。
·Object类中存在toString()和equals()方法用于对象的输出和比较
·Object类可以接收任意的引用数据类型的实例
2.2、本次预计讲解的知识点
1、抽象类和接口
2、匿名内部类
3、包装类及JDK1.5的新特性
3、具体内容
3.1、抽象类和接口(重点)
抽象类和接口在Java中是最重要的两个概念,那么这两个概念有很多实际的应用,和操作,下面通过一些代码来进行分析。
3.1.1、抽象类和接口的关系
之前学习过了内部类,内部类:
在一个类的内部还包含另外一个类,那么在一个抽象类中也是允许包含其他的抽象类或其他的接口的。
abstractclassA{//定义了抽象类
publicabstractvoidfun();//抽象方法
abstractclassB{//定义了内部抽象类
publicabstractvoidprint();
};
interfaceC{//定义了内部的接口
publicvoidgetInfo();
}
};
在以上的抽象类中包含了一个抽象类和一个接口,当然,在实际中还可以定义更多的抽象类和接口,那么该怎么使用呢?
首先对于抽象类A而言应该被子类所继承。
abstractclassA{//定义了抽象类
publicabstractvoidfun();//抽象方法
abstractclassB{//定义了内部抽象类
publicabstractvoidprint();
};
interfaceC{//定义了内部的接口
publicvoidgetInfo();
}
};
classXextendsA{//继承抽象类A
publicvoidfun(){
System.out.println("HELLOMLDN");
}//子类可以不去实现内部的抽象类和接口
classYextendsB{//定义内部类实现抽象类中的内部抽象类
publicvoidprint(){
System.out.println("HELLOLXH");
}
};
classZimplementsC{
publicvoidgetInfo(){
fun();
newY().print();
}
};
};
publicclassAIDemo01{
publicstaticvoidmain(Stringargs[]){
A.Cc=newX().newZ();
c.getInfo();
}
};
以上的操作代码看起来就一个字“晕”,此种代码二十年都见不到。
所以只是作为一个简单的参考。
反过来,一个接口中也能包含多个抽象类或多个接口。
interfaceA{//定义了抽象类
publicvoidfun();//抽象方法
abstractclassB{//定义了内部抽象类
publicabstractvoidprint();
};
interfaceC{//定义了内部的接口
publicvoidgetInfo();
}
};
classXimplementsA{//继承抽象类A
publicvoidfun(){
System.out.println("HELLOMLDN");
}//子类可以不去实现内部的抽象类和接口
classYextendsB{//定义内部类实现抽象类中的内部抽象类
publicvoidprint(){
System.out.println("HELLOLXH");
}
};
classZimplementsC{
publicvoidgetInfo(){
fun();
newY().print();
}
};
};
publicclassAIDemo02{
publicstaticvoidmain(Stringargs[]){
A.Cc=newX().newZ();
c.getInfo();
}
};
实际上,从以上的程序中可以很好的证明一点,类或接口都永远可以作为内部接口或类的情况出现。
3.1.2、接口应用
(一):
表示工厂设计模式
现在,观察以下的程序代码,分析操作的问题:
interfaceFruit{//定义水果
publicvoideat();//吃水果
}
classAppleimplementsFruit{//定义苹果的子类
publicvoideat(){
System.out.println("**吃苹果。
");
}
};
classOrangeimplementsFruit{
publicvoideat(){
System.out.println("**吃橘子。
");
}
};
publicclassAIDemo03{
publicstaticvoidmain(Stringargs[]){
Fruitf=newApple();
f.eat();
}};
以上的代码已经完成了基本的功能,但是以上的操作是否存在问题呢?
本道程序的问题在于:
客户端(main方法)直接与具体的子类相耦合了,如果以后要想更换操作的子类,则必须修改客户端。
那么这样的操作在开发中是极其不提倡的一种操作。
开发的原则:
如果可以由A直接到B,那么中间最好加上一个过渡的C,ACB。
为了解决以上的问题,中间一个过渡的操作类,通过此过渡的操作类得到接口的实例化对象。
interfaceFruit{//定义水果
publicvoideat();//吃水果
}
classAppleimplementsFruit{//定义苹果的子类
publicvoideat(){
System.out.println("**吃苹果。
");
}
};
classOrangeimplementsFruit{
publicvoideat(){
System.out.println("**吃橘子。
");
}
};
classFactory{
publicstaticFruitgetInstance(StringclassName){
if("apple".equals(className)){
returnnewApple();
}
if("orange".equals(className)){
returnnewOrange();
}
returnnull;
}
};
publicclassAIDemo04{
publicstaticvoidmain(Stringargs[]){
Fruitf=Factory.getInstance(args[0]);
if(f!
=null){
f.eat();
}
}
};
如果以后程序中再增加子类,直接修改Factory类即可,所以这样的设计在设计模式上讲称为工厂设计模式。
3.1.3、接口应用
(二):
代理设计模式
使用接口还可以表示出以下的一种关系。
interfaceSubject{//定义一个操作的主题
publicvoidgiveMoney();//给我钱。
。
。
。
。
}
classRealSubjectimplementsSubject{
publicvoidgiveMoney(){
System.out.println("还钱,就两个字。
。
。
");
}
};
classProxySubjectimplementsSubject{
privateSubjectsub=null;
publicProxySubject(Subjectsub){
this.sub=sub;
}
publicvoidbefore(){
System.out.println("准备刀子,绳索,毒药,电辊,锯。
");
}
publicvoidgiveMoney(){
this.before();
this.sub.giveMoney();//代表真实的讨债人员去要银子
this.after();
}
publicvoidafter(){
System.out.println("销毁一切的罪证,我清白的。
。
。
");
}
};
publicclassAIDemo05{
publicstaticvoidmain(Stringargs[]){
Subjectreal=newRealSubject();
Subjectproxy=newProxySubject(real);
proxy.giveMoney();
}
};
最终结果,真实主题的操作被调用,只是代理要完成一些与具体业务相关的操作。
3.1.4、接口应用(三):
适配器(了解)
接口本身也是表示出一种能力,例如:
说中国话、说英语,都表示的是一种能力。
以见人说人话,见鬼说鬼话为操作的标准。
interfacePerson{
publicvoidsayPerson();
}
interfaceGhost{
publicvoidsayGhost();
}
classWUGUANGXINimplementsPerson,Ghost{
publicvoidsayPerson(){
System.out.println("见人说人话。
。
。
");
}
publicvoidsayGhost(){
System.out.println("见鬼说鬼话。
。
。
");
}
};
publicclassAIDemo06{
publicstaticvoidmain(Stringargs[]){
fun1(newWUGUANGXIN());
fun2(newWUGUANGXIN());
}
publicstaticvoidfun1(Personper){
per.sayPerson();
}
publicstaticvoidfun2(Ghostgh){
gh.sayGhost();
}
};
适配器还可以进行进一步的扩充,例如,现在有以下一种情况:
·正常情况下一个接口中的所有方法在子类中都必须实现,但是现在要求一个子类可以根据自己的需要来选择实现那种方法,该如何操作呢?
interfaceDemo{
publicvoidfunA();
publicvoidfunB();
publicvoidfunC();
publicvoidfunD();
publicvoidfunE();
}
abstractclassDemoAdapterimplementsDemo{
publicvoidfunA(){}
publicvoidfunB(){}
publicvoidfunC(){}
publicvoidfunD(){}
publicvoidfunE(){}
};
classRealDemoextendsDemoAdapter{
publicvoidfunA(){
System.out.println("HelloWorld!
!
!
");
}
};
publicclassAIDemo07{
publicstaticvoidmain(Stringargs[]){
Demod=newRealDemo();
d.funA();
}
};
以上也是适配器的一种设计思路,但是这种设计思路只有在Java的图形界面开发中才会使用,在JavaEE的开发中很少应用。
3.1.5、抽象类和接口的区别(记下)
抽象类与接口在使用上形式如此相似,那么到底两者有那些区别呢,下面通过以下的表格进行罗列,以下的表格要求必须掌握。
No.
区别点
抽象类
接口
1
定义
包含一个抽象方法的类
抽象方法和全局常量的集合
2
语法
通过abstract关键字定义
通过interface关键字定义
3
使用
抽象类通过extends本子类继承
通过implements被子类实现
4
限制
一个子类只能继承一个抽象类
一个子类可以同时实现多个接口
5
关系
一个抽象类可以实现多个接口
一个接口不能继承抽象类,只能继承接口
一个抽象类可以包含多个接口
一个接口中可以包含多个抽象类
6
设计模式
模板设计
工厂设计、代理设计
两者一起使用,可以建立适配置器设计模式
7
开发
存在单继承局限
无此限制
从以上的表中,可以得出以下的一个结论,如果在开发中接口和抽象类都可以同时出现的话,那么接口的使用优先。
3.1.6、观察以下程序的执行结果
abstractclassA{
publicA(){
this.print();
}
publicabstractvoidprint();
};
classBextendsA{
privateinttemp=30;
publicB(inttemp){
this.temp=temp;
}
publicvoidprint(){
System.out.print("temp="+this.temp);
}
};
publicclassAIDemo08{
publicstaticvoidmain(Stringargs[]){
newB(100);
}
};
以上程序的返回值是0,为什么是0呢?
构造方法:
为类中的属性初始化,如果一个类中的构造方法还没有调用,则类中的所有属性的内容都是默认值。
3.2、匿名内部类(重点)
匿名内部类本身是一个在日后的开发中最经常使用到的一种操作,匿名内部类本身是在抽象类和接口的基础之上发展起来的一种产物。
interfaceA{
publicabstractvoidprint();
};
classBimplementsA{
publicvoidprint(){
System.out.println("helloworld!
!
!
");
}
};
classX{
publicvoidfun1(){
this.fun2(newB());
}
privatevoidfun2(Aa){
a.print();
}
};
publicclassAIDemo06{
publicstaticvoidmain(Stringargs[]){
newX().fun1();
}
};
但是,如果现在B类只使用一次的话,那么还有必要将其定义成一个具体的类吗?
所以现在如果将接口的子类单独定义成一个类,就有些多余了,那么此时就可以利用匿名内部类完成操作。
interfaceA{
publicabstractvoidprint();
};
classX{
publicvoidfun1(){
this.fun2(newA(){
publicvoidprint(){
System.out.println("HelloWorld!
!
!
");
}
});
}
privatevoidfun2(Aa){
a.print();
}
};
publicclassAIDemo10{
publicstaticvoidmain(Stringargs[]){
newX().fun1();
}
};
以上的操作语法虽然别扭,但是必须使用,必须熟练掌握,为日后的开发打下基础。
3.3、包装类(重点)
在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就完全不符合于这种设计思想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型的包装类。
No.
基本数据类型
包装类
1
int
Integer
2
char
Character
3
float
Float
4
double
Double
5
boolean
Boolean
6
byte
Byte
7
short
Short
8
long
Long
以上的八种包装类,可以将基本数据类型按照类的形式进行操作。
但是,以上的八种包装类也是分为两种大的类型的:
·Number:
Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
·Object:
Character、Boolean都是Object的直接子类。
以下以Integer和Float为例进行操作
3.3.1、装箱及拆箱操作
将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。
将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作,因为所有的数值型的包装类都是Number的子类,Number的类中定义了如下的操作方法,以下的全部方法都是进行拆箱的操作。
No.
方法
类型
描述
1
publicbytebyteValue()
普通
将包装类的类型变为byte类型,Bytebyte
2
publicabstractdoubledoubleValue()
普通
Doubledouble
3
publicabstractfloatfloatValue()
普通
Floatfloat
4
publicabstractintintValue()
普通
Integerint
5
publicabstractlonglongValue()
普通
Longlong
6
publicshortshortValue()
普通
Shortshort
如果要想装箱,直接使用各个包装类的构造方法即可。
·Integer的构造方法:
publicInteger(intvalue)
·Float的构造方法:
publicFloat(floatvalue)
范例:
观察装箱及拆箱操作
publicclassWrapDemo01{
publicstaticvoidmain(Stringargs[]){
inttemp=10;//基本数据类型
Integerx=newInteger(temp);//将基本数据类型变为包装类,属于装箱操作
inty=x.intValue();//将包装类变为基本数据类型,属于拆箱操作
System.out.println(y*y);
}
};
以上的操作完成之后,下面再以Float为例完成。
范例:
观察Float的操作
publicclassWrapDemo02{
publicstaticvoidmain(Stringargs[]){
floattemp=10.3f;//基本数据类型
Floatf=newFloat(temp);//将基本数据类型变为包装类,属于装箱操作
floaty=f.floatValue();//将包装类变为基本数据类型,属于拆箱操作
System.out.println(y*y);
}
};
以上两个操作完成了基本的装箱及拆箱的操作,但是以上的做法是属于JDK1.4之前的做法。
·在JDK1.4之前,所有的基本数据类型必须进行手工的装箱及拆箱操作,而且包装类本身不能直接进行四则运算,或者自增、自减的操作。
·在JDK1.5之后,Java中增加了新的功能,可以自动装箱和拆箱。
而且可以直接通过包装类进行四则运算和自增加、自减的操作。
范例:
以Float为例,观察自动的装箱和拆箱操作
publicclassWrapDemo03{
publicstaticvoidmain(Stringargs[]){
Floatf=10.3f;//自动装箱
floatx=f;//自动拆箱
System.out.println(f*f);//直接利用包装类完成
System.out.println(x*