黑马程序员-----java基础面之面向对象(3)
------- android培训、java培训、期待与您交流! ----------
方向不对,努力白费!
每天静坐十分钟, 静坐的好处:1,消除负能量 2,吸收正能量。
多态(重点)
多态: 多种状态,多种形态
多态的前提:1.有存在继承关系 2.要有重写
多态的优点:
1.提高了程序前期的扩展性
2.提高了程序后其的可维护性.
多态伪代码:
class宠物{
void 叫(){
}
}
class狗 extends 宠物{
void 叫(){
system.out.println(“汪汪-----”);
}
}
class猫 extends 宠物{
void叫(){
system.out.println(“喵喵-------”);
}
}
ClassDemo (){
Publicstatic void main(String[] args){
//父类引用指向子类对象
宠物 cw=new 狗();
宠物 cw=new 猫();
}
}
多态存在时,成员属性与成员方法表现
class Father{
Stringname="tom"; //实例属性
staticString country="zh"; //类属性
//实例方法
publicvoid show(){
System.out.println("father类中的show");
}
//类方法
publicstatic void method(){
System.out.println("father类中的静态方法");
}
}
class Son extends Father{
Stringname="tony"; //将从父类中的继承的name属性隐藏了. 实例属性
static Stringcountry="china"; //类属性
//子类中重写的方法 实例方法
publicvoid show(){
System.out.println("son类中的show");
}
//子类重写父类中的静态方法
publicstatic void method(){
System.out.println("son类中的静态方法");
}
}
Fathera=new Son();
1.实例属性 a.name
编译时:查看Father中是否存在name属性
执行时:调用的是Father中的name属性
2.类属性 a.country
编译时:查看Father中是否存在country属性
执行时:调用的是Father中的country属性
3.类方法 a.method();
编译时:查看Father中是否存在method()静态方法
执行时:调用的是Father中的method()静态方法
4.实例方法 a.show();
编译时:查看Father中是否存在show()实例方法
执行时:执行的是子类Son中的show()实例方法。
结论:1.关于属性都是查看父类中是否存在该属性,调用的也是父类中的属性静态方法也是一样的。
2.对于实例方法来说编译时查看父类中是否有这个方法,真正执行时执行的是子类中的重写方法。
多态的弊端
程序有好处肯定也有弊端, 来看看多态的弊端是什么.
父类引用指向子类对象时,缺点就是不能调用子类中所特有的成员
多态存在时类型的转换
前提:必须存在多态
自动转换(向上转型) :父类引用指向子类对象 Father f=new Son();
强制转换(向下转型): Sonson=(Son)f;
在做向下转型时会使用到一个 instanceof 关系操作符
它的作用是判断某个引用所指向的对象的类型是否是指定的类型
格式 引用(对象) instanceof 类型
它操作后得到的结果是一个boolean类型的值。
instanceof只能判断有关系的操作。
使用instanceof会有一个问题,如果判断的是父类类型,它返回的也是true.
如果真正要判断一个引用所指向的对象的真实类型 通过getClass()方法去获得.
多态小练习:
简单计算器操作
关于计算器我们提供了 加 减 乘 除class Test3
{
publicstatic void main(String[] args)
{
inta=10;
intb=5;
char[]ch={'+','-','*','/'};
charc=ch[0];
//我们现在要求a,b这两个数做c操作后的结果.那么我们就需要一个运算类对象
Operationop=OperationFactory.getInstance('+'); //Operation op=new Add();
int result=op.oper(a,b);
//父类引用指向子类对象调用实例方法时,调用的是子类中重写的方法。
System.out.println(""+a+c+b+"="+result);
}
}
//这是一个运算的工厂类,它的作用是可以生产运算对象
classOperationFactory
{
//生产运算对象的方法,这个方法是根据传递的符号来判断生产哪一个对象.
/*
参数: charc 判断的符号
返回值:Operation对象
*/
publicstatic Operation getInstance(char c){
Operationop=null;
switch(c){
case'+':op=new Add();break;
case'-':op=new Sub();break;
case'*':op=new Mul();break;
case'/':op=new Div();break;
}
returnop; //new Add();
}
}
//运算类
classOperation
{
//计算行为
intoper(int a,int b){
return0; //存在的一个弊端.
}
}
//加法类
classAdd extends Operation{
//计算行为
int oper(int a,int b){
returna+b;
}
}
//减法
classSub extends Operation{
//计算行为
intoper(int a,int b){
returna-b;
}
}
//除法类
classDiv extends Operation{
//计算行为
int oper(int a,int b){
returna/b; //除数不能为0 这也是一个弊端
}
}
//乘法
classMul extends Operation{
//计算行为
intoper(int a,int b){
returna*b;
}
}
抽象类
抽象类也是一个类,也存在多态
抽象类:
使用abstract修饰的类就是抽象类.
abstractclass A{ //抽象类
}
抽象方法:
使用abstract修饰的方法就是抽象方法,抽象方法只有方法的声明,而没有方法的实现.
abstractclass A{
abstractvoid show(); //对于抽象方法来说,它只有方法的声明,而没有方法的实现。
}
抽象类与抽象方法的特点
1.抽象类不能被实例化不能new
2.抽象类是用来被子类继承的。
3.抽象类中可以有抽象方法。(抽象方法必须存在于抽象类中)
4.对于包含抽象方法的抽象类,子类必须将其中的所有抽象方法重写.
抽象类详解:
1.抽象类中没有抽象属性这个概念
2.抽象类中的构造方法
1.抽象类中是否有构造方法?
有
2.抽象类中的构造方法有什么有?
帮助子类进行实例化
3.如果父子都是抽象类那么有什么情况?
子类可以对父类中的抽象方法进行选择性重写。
4.如果父类是一个普通类,子类是一个抽象类
可以
5.抽象关键字abstract不可以和哪些关键字共存?
修饰类 final
修饰方法 private static final
final是否可以与abstract共存?
不能共存
final修饰类代表这个类不能被继承 而abstract的类必须被继承
final修饰方法代表这个方法不能被重写 而abstract方法必须被重写
abstract是否可以与static共存吗?
static方法可以通过类名直接调用,但是abstract方法没有实体
private是否可以与abstract共存吗?
不行
6.抽象类中的抽象方法是否可以不是抽象?
1.全是抽象
2.全不是抽象 行 适配器
3.混合到一起 行 模板方法模式
模板方法模式
模板方法模式:它的作用
它将要执行的动作的顺序进行限定,
将其进行隐藏,这样提高了代码的安全性.
现在规定连接数据库有三步
1.进行连接
2.进行操作
3.关闭数据库
对于不同的数据库我们在连接时,与操作时,关闭时它细节性的内容不同。
abstractclass ConnectDb{
abstractvoid connection();
abstractvoid operation();
abstractvoid close();
//这个方法不是抽象的
voidrun(){ //运行
connection();
operation();
close();
}
}
classOracleConnection extends ConnectionDb{
void connection(){}
void operation(){}
void close(){}
}
接口
接口你可以理解成一个特殊的抽象类
看类的组成部分
class类名{
成员属性
成员方法
}
接口的组成
1.接口的声明 interface
interface接口名{
属性 默认修饰符 public static final
方法 默认修饰符 public abstract
}
接口中的成员的权限全是public
接口的作用:
1. 接口可以多实现
实现的关键字: implements
interfaceA{
voida();
}
interfaceB{
voidb();
}
classC implements A,B{
publicvoid a(){}
publicvoid b(){}
}
java中不能多继承,为什么可以多实现
classA{
voida(){} //实体方法
}
classB{
voida(){} //实体方法
}
classC extends A,B{
publicvoid a(){} //是重写A类还是B类区分不开.
}
接口中不会出现混淆问题
interfaceA{
voida(); //只是方法声明
}
interfaceB{
voida(); //只是方法声明
}
classC implements A,B{
publicvoid a(){}
}
2.接口用来解耦合
解决类与类之间的问题
3.接口是程序功能的扩展
继承描述的是 is 关系 基本功能键
接口描述的是 like 扩展功能
//抽烟的人
interfaceSmokingPerson{
}
//打球的人
interfacePlayBall{
}
classPerson{
voideat(){}
voidrun(){}
}
classStudent extends Person implements PlayBall{
voideat(){
}
voidrun(){
}
}
classTeacher extends Person implements SmokingPerson
{
voideat(){
}
voidrun(){
}
}
4.对外暴露的规则
接口强制性规定应该做什么
接口与类的关系 实现 implements
当一个类实现了某个接口,那么这个类必须将接口中所有方法重写.
因为接口中的方法都是抽象的。
类与类之间关系 继承 extends
接口与接口之间也存在关系extends 子接口将父接口中的所有成员都继承.
interfaceA{
voida();
}
interfaceD{
voidd();
}
interfaceB extends A,D{
voidb();
}
classC implements B{
publicvoid b(){}
publicvoid a(){}
}
接口的思想
其时就是一种公共的标准。
面向接口的编程
一般我们在说接口时有两种概念
1.java中的接口 interface
2.公共的标准.
API 应用程序接口
接口关系总结:
类与类 extends 只能单继承
类与接口 implements 可以多实现
接口与接口 extends 可以多继承
抽象类与接口的区别
1.抽象类是一个类,它是用来被继承的,只能单继承
接口是用来被实现的,它可以多实现
2.抽象类描述的是is 它描述的是基本功能
接口描述的是like 它描述的扩展的功能
3.抽象类中可以有抽象方法也可以没有抽象方法
接口中的方法全是抽象的。
接口也存在多态(接口回调),但是接口中的成员全是虚拟的概念,它没有构造方法.
为什么没有,因为接口中的属性全是static
多态的前提:1必须存在继承或实现 2.必须有重写
在实际开发中,我们现在继承也可以,实现也可以。
一般首选实现
Object类介绍
它是java中所有类的父类基类 根类 超类.
在Object类中定义的方法,所有的类中都有。
学习一个类步骤:
1.查看当前类的声明 观看这个类修饰符特点 父类是谁 实现了什么接口.
2.查看这个类的说明
3.创建这个类的对象 观看其提供的构造方法
4.查看这个类的成员方法
点击超连接,可以查看当前这个方法的详细说明
Object类中的代表方法介绍
1.toString
Object类中的toString 方法
声明 public String toString()
作用 对象字符串化
Object类中的toString方法返回的字符串是 类名+@+16进制的hash码值
在实际开发中toString方法怎样重写?
一般我们使用toString方法完成的是对象的属性显示
2.equals
声明 publicboolean equals(Object obj)
比较两个对象是否相等
Object类中的equals方法的实现与==是一样的,
它都是用来比较两个对象的地址值
对于同一个类的对象,如果属性相同,我们认为它们相等。
这个时候就可以对equals方法进行重写来判断
从Object类中继承的equals方法它比较的是对象的地址,与==操作是一样的
我们重写equals方法的目的,为了比较对象的属性是否相等。
如果对象的属性一样,我们让equals方法返回true。否则返回
false,这个时候的equals方法就是比较对象的内容.
3.hashCode
当咱们讲集合时会说
当我们重写equals方法时,需要将hashCode方法也重写.
4.clone
声明 protectedObject clone();
作用:创建一个对象的副本
注意
1.必须在被克隆类中重写clone方法
2.必须让被克隆类实现cloneable接口
5.finalize
声明:protectedvoid finalize()
throws Throwable
作用:这个方法就是当垃圾回收机制执行时要执行的方法。
这个方法一般我们不进行重写.
6.getClass
声明:publicfinal Class getClass()
这个方法的返回值是Class,它代表的是字节码文件对象.
对于Class类中我们需要知道一个方法 String getName()
作用就是获得字节码文件名字
内部类
内部类:在一个类中又声明了一个类.
伪代码:
class A{ //外部类
classB{ //内部类
}
}
内部类的作用
内部类一般是在分析阶段.
发现某一个实体是另外一个实体的不可分隔的部分
伪代码举例:
class 人{
class心脏{
}
class脑{
}
}
内部类的定义位置细节
1. 内部类可以声明在类的成员位置上,对于这种情况,
内部类是可以使用成员修饰符的。 private static
2. 内部类可以声明在方法内.
内部类声明在成员位置上
对于内部类来说它可以直接访问外部类的成员
a.应用的比较多的访问方式(建议访问方式)
在外部类定义方法,去访问内部类的成员
b.在外部去直接访问内部类的成员
非static修饰的内部类, 外部类名.内部类名引用=new 外部类名().new 内部类名();
static修饰的内部类, 外部类名.内部类名 引用=new 外部类.内部类();
关于内部类声明在成员位置上时它的static修饰的问题
1.如果内部类使用static修饰,在内部类中就不能直接访问外部类的非static成员
2.如果内部类中有static成员,内部类必须使用static修饰
3.如果内部类使用static修饰,那内部类的成员可以是static,也可以不是.
在实际开发内部类一般都会是使用private,这时候只能合适我们所说的第一种方式方法
如果是非private可以使用其它方式
内部类定义在局部位置(定义在方法内)
只能在局部位置创建内部类的对象去访问
a.内部类可以直接外部类的成员
b.内部类可以直接访问局部变量,局部变量必须使用final修饰
c.内部类中如果出现与外部类同名的成员,
这个时候的this代表的是内部类对象,而要使用外部类
需要 外部类名.this 这个代表的是外部类的对象
举例:
//关于内部类定义在局部时访问局部变量
classOuter{
Stringname="tom1"; //外部类的成员
publicvoid show(final String name){
//finalString name="tom";
classInner{
Stringname="tom2"; //内部类的成员
publicvoid print(){
Stringname="tom3"; //局部变量
System.out.println(name);
System.out.println(this.name);
System.out.println(Outer.this.name);
}
}
}
}
内部类产生的.class文件特点
在成员位置 外部类名$内部类名.class
在局部位置 外部类名$序号内部类名.class
匿名内部类
内部类的一种简化写法,图形化界面时会比较常用
格式
new类名|接口名([参数]){
//属性-------->很少使用
//方法-------->可以是自定义方法但是绝大多数情况下都是重写的方法。
};
new代表创建一个匿名内部类对象
类名|接口名 代表的是匿名内部类继承的父类或实现的接口
{}它代表的是匿名内部类的内容
小笔试题:
Object obj=new Object(){
publicvoid show(){
System.out.println("show....");
}
};
obj.show();//父类引用指向子类对象不能调用子类特有的方法
newObject(){
publicvoid show(){
System.out.println("show....");
}
}.show();//子类对象调用自己的方法
我们在实际开发中,使用匿名内部类在局部位置上的时候比较多,
并且一般都是将其做为一个参数进行传递.
------- android培训、java培训、期待与您交流! ----------