黑马程序员--------java面向对象 继承、接口、多态、Object类

时间:2023-02-16 17:09:48


 -----------android培训java培训、java学习型技术博客、期待与您交流!------------

                                               继承、接口、多态、Object类

继承

一 继承的概述

1、提高代码复用性
2、让类与类之间产生关系。有了这个关系,才有了多态的特性
3、java只支持单继承和多层继承,不支持多继承。因为多继承容易带来安全隐患:当多个父类中定义相同功能,功能内容不同时,子类对象不确定要运行哪一个。但是java保留了这种机制,并有另一中体现形式来完成——多实现
4、java支持多层继承。也就是一个继承体系,如何使用一个继承体系中的功能呢?
 1)要想使用体系,先查阅体系父类的描述,因为父类中定义的是该体系*性功能,通过了解共性更能,就可以知道该体系的基本功能。
 2)在具体调用时,要创建最子类的对象:一是因为有可能父类不能创建对象;二是子类对象可以使用更多的功能,包括基本的也包括特有的。

二 继承的特点
1、子父类出现后,类成员特点
1)变量:如果子类中出现非私有同名成员变量时,子类要访问本类中的变量,用this,子类要访问父类中的同名变量,用super。super的使用和this几乎一致。This代表本类对象的引用,super代表父类对象的引用
2)函数:当子类中出现和父类一模一样的函数时,子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样。这种情况是函数的另          一个特性:重写(覆盖)
     当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备了该功能,但功能内容却和父类不一致,这时在子类子类中没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容
**覆盖注意事项:子类覆盖父类,必须保证子类权限大于等于父类权限,否则编译失败
**重写和重载区别
   重载:只看同名函数的参数列表
   重写:子父类方法要一模一样
3)构造函数:this()调用本类构造函数 super()调用父类构造函数
   在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类构造函数第一行有一条隐式语句 super() 。super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super()。一般父类的构造函数先进行初始化
   为什么子类一定一定要访问父类中的构造函数:是因为父类中的数据子类可以直接获取,所以子类对象在建立时,先要查看父类时如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super()语句的方式来访问
三 子类的实例化过程
结论:
1、 子类的所有构造函数,都会默认访问父类中的空参数的构造函数,因为子类每一个构造函数第一行都有一句隐式super()
2、 当父类没有空参数的构造函数时,子类必须手动同过super()语句形式来指定要访问父类中的构造函数
3、 当然子类的构造函数第一行也可以手动指定this()语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。


四 final关键字
1、final可以修饰类、方法、变量(成员变量和局部变量)
2、final修饰的类不可以被继承
3、final修饰的方法不可以被覆盖
4、final修饰的变量是一个常量
5、内部类定义在局部位置上时只能访问被final修饰的局部变量

五 抽象类 abstract关键字
1、当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取,这时只抽取功能定义,而不抽取功能主体——abstract void study();
2、特点:
1)抽象方法一定在抽象类中
2)抽象方法和抽象类必须被abstract关键字修饰
3)抽象类不可以用new创建对象,因为调用抽象方法没意义
4)抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用,如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
5)抽象类既可以有抽象方法,又可以有非抽象方法
6)抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象

抽象类练习 员工 经理

/*

假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:
姓名、工号、工资。经理也是员工,除了含有员工属性外,另外还有一个奖金属性
。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问

思路:1、员工类和经理类都属于员工,都有员工的基本属性 ,可以让员工类和经理类继承员工属性
2、他们都需要工作,但是工作类容不同,这时可以向上抽取他们的共性功能定义
而不抽取功能主体
3、经理类有自己的奖金机制,需要单独描述
*/
abstract class Employee
{
String name;
String id;
Double pay;
Employee(String name,String id,Double pay)//用于员工属性初始化
{
this.name=name;
this.id=id;
this.pay=pay;
}
public abstract void work();//定义员工抽象的的工作方法
}
class Manager extends Employee
{
int bonus;
Manager(String name,String id ,Double pay,int bouns)
{
super(name,id,pay);
this.bonus=bonus;

}
public void work()
{
System.out.println("管理");
}
}
class Pro extends Employee
{
Pro(String name,String id,Double pay)
{
super(name,id,pay);
}
public void work()
{
System.out.println("工作");
}
}
class AbstractDemo
{
public static void main(String[] args)
{
Pro p =new Pro("lisi","9527",500.0);//创建子类对象,并初始化
System.out.println(p.name+".."+p.id+".."+p.pay);
p.work();

}
}
打印结果:

黑马程序员--------java面向对象 继承、接口、多态、Object类


六 模板设计方法

1、  概念:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,那么这是就将不确定的部分暴露出去(一般抽象化,也可以不抽象化)。由该类的子类去完成

示例:

/*
需求:获取一段程序运行的时间
原理:获取程序开始和结束的时间相减即可

获取时间:System.currentTimeMillis();
*/
abstract class GetTime
{
public final void getTime()//加上final不让子类复写这个方法
{
Long start =System.currentTimeMillis();//开始时间

runCode();//运行代码

Long end = System.currentTimeMillis();//结束时间

System.out.print("毫秒:"+(end-start));
}

public abstract void runCode();//定义一个抽象的方法,对外暴露获取
//程序运行时间的接口

}
class SubTime extends GetTime
{
public void runCode()
{
for(int x=0;x<4000;x++)
System.out.print(x);
}
}
class TemplateDemo
{
public static void main(String[] args)
{
SubTime st = new SubTime();
st.getTime();
}
}
打印结果:

黑马程序员--------java面向对象 继承、接口、多态、Object类

 接口 

 关键字implements

一、接口:初期理解可以认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示
格式: interface{ }
二、接口中的成员修饰符是固定的
*接口常量:public static final
*常用函数:public abstract
三、接口是不可以创建对象的,因为有抽象方法,需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例化。否则子类是一个抽象类。
四、接口的出现将“多继承”通过另一种形式体现出来,即“多实现”
五、一个类可以继承另一个类的时候实现多个接口
六、接口与接口间的关系是继承关系
七、接口总结:

1,接口是对外暴露的规则
2,接口是程序功能的扩展
3,接口可以用来多实现
4,接口与接口之间是实现关系,而且类可以继承一个类的同时实现多个口
5,接口与接口之间可以有继承关系
6,基本功能一般定义在类中,扩展功能一般定义在接口中


多态

1、 定义:某一类事物的多种存在形态。
2、 例:动物中的 猫、狗
   *猫这个对象对应类型是猫类型:猫 x = new 猫()
   *同时猫也是动物的一种,也可以把猫称为动物:动物 y =new 猫(),动物是猫和狗具体事物中抽取出来的父类型,即父类型引用指向了子类对象
3、多态的体现
   *父类引用指向子类对象
   *父类引用可以接收自己的子类对象
4、多态的前提
   *必须是类与类之间有关系,要么继承,要么实现
   *通常还有一个前提:存在覆盖
5、多态的好处和局限
   *好处:提供程序的扩展性
   *局限:提高了扩展性,但是只能使用父类引用访问父类中的方法,子类中特有的方法访问不了,需要向下转型
6、多态中非静态成员函数特点
   *在编译时期:参阅引用型变量所属类中是否有调用的方法,有编译通过,没有失败
   *在运行时期:参阅对象所属的类中是否有调用的方法
   *简单总结就是:成员函数在多态调用时,编译看左边(引用型变量所属的类),运行看右边(具体对象类) Fu f(左边) = new zi();(右边)
7、多态中成员变量和静态成员函数的特点(多面试)
   *无论编译和运行,都参考左边(引用型变量所属的类)

/*
多态实例:
动物:猫,狗

猫 x=new 猫();

动物 x =new 猫();

1,多态的体现
父类的引用,指向了自己子类对象。
父类的引用也可以接收自己的子类对象。
2,多态的前提
必须是类与类之间有关系。要么继承,要么实现
通常还有一个前提:存在覆盖
3,多态的好处
多态的出现大大提高了程序的扩展性

4,多态的弊端
提高了扩展性。但是只能使用父类的引用访问父类中的成员. 不能访问子类特有成员 例如:猫抓老鼠、狗看门、猪拱地(如要应用必须向下转型)
*/
/*
多态的应用
动物
猫,狗。

*/
abstract class Animal
{
public abstract void eat();
}
class Cat extends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanJia()
{
System.out.println("看家");

}
}
class Pig extends Animal
{
public void eat()
{
System.out.println("饲料");
}
public void gongDi()
{
System.out.println( "拱地");
}
}

class DuoTaiDemo
{
public static void main(String[] args)
{


///Animal a=new Cat();//多态应用(父类引用指向自己的子类对象)类型提升,向上转型
///a.eat();
///如果想要调用猫的特有方法时,如何操作?
///强制将父类的引用转成子类的类型
///Cat c=(Cat)a;
///c.catchMouse();

function(new Cat());
function(new Dog());
function(new Pig());
}
public static void function(Animal a)
{
a.eat();

//关键字instaceof 这样就可以访问子类的特有方法了。(不做主要掌握)
if(a instanceof Cat)//关键字instanceof(判断某一类型的引用)来判断传进来的动物是什么
{
Cat c=(Cat)a;//向下强制转型
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d=(Dog)a;//向下强制转型
d.kanJia();
}
else if(a instanceof Pig)
{
Pig p=(Pig)a;//向下强制转型
p.gongDi();
}

}


}
结果:

黑马程序员--------java面向对象 继承、接口、多态、Object类

多态的主板实例:

/*
需求:
电脑运行实例
电脑运行基于主板,预留PCI扩展

思路:定义一个PCI接口,定义网卡和声卡实现PCI接口
在主板的方法里调用接口的引用
*/
interface PCI
{
public abstract void open();
public abstract void close();
}
class MainBoard
{
public void run()
{
System.out.println("主板运行");
}
public void method(PCI c)//父类引用
{
c.open();
c.close();
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("网卡打开");

}
public void close()
{
System.out.println("网卡关闭");
}
}
class SoundCard implements PCI
{
public void open()
{
System.out.println("声卡打开");

}
public void close()
{
System.out.println("声卡关闭");
}
}

class ComputerRun
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.method(new NetCard());
mb.method(new SoundCard());
}
}
运行结果:

黑马程序员--------java面向对象 继承、接口、多态、Object类


Object类
1、Object:是所有说对象的直接或者间接父类,传说中的上帝。该类中定义的肯定是所有对象都具备的功能。

class Demo
{
int num;
Demo(int num)
{
this.num=num;
}
public boolean equals(Object obj)//复写Object类中的equals方法,建立自己类的对象的比较方法
{ //接收d2 相当于Object obj= d2 多态;
if(!(obj instanceof Demo))
return false; //比较传入的对象是不是Demo类,不是直接返回false,因为没有可比性

Demo o =(Demo)obj;//接收的是Object类型的,需要向下转型
return this.num==o.num;
}
}
class Person
{
}
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1 = new Demo(4);
Demo d2 = new Demo(5);
Person p = new Person();
System.out.println(d1.equals(d2));
System.out.println(d1.equals(p));//编译会通过,因为equals是比较对象的方法
System.out.println(d1.toString());//将对象转换为字符串
System.out.println(Integer.toHexString(d1.hashCode()));//获对象的取哈希值
}
}
运行结果:

黑马程序员--------java面向对象 继承、接口、多态、Object类