继承
1.1 类和类之间的常见关系。
1:既然继承是描述类和类之间的关系,就需要先来了解类和类之间的常见关系
1.1.1 现实生活的整体与部分
举例说明
1:现实生活
1:学生 是人
2:狗 是动物
3:球队 包含 球员 整体与部分的关系,部分可以删除和增加
4:笔记本包含 cpu 整体与部分的关系,部分不可以删除和增加
5:航母编队 包含(航母 护卫舰 驱逐舰 舰载机 核潜艇)
1.1.2 java中的类与类关系
java中的类关系
1:is a 关系 (学生是人)
2:has a 整体与部分
classPerson{
String name;intage;
Address add;
Person(){
}
Person(String name,intage,Address add){this.name=name;this.age=age;this.add=add;
}voidspeak(){
System.out.println("姓名:"+name+" 年龄:"+age+" "+add.print());
}
}classAddress{
String country;
String city;
String street;
Address(){
}
Address(String country,String city,String street){this.country=country;this.city=city;this.street=street;
}
String print(){return "地址:"+country+" "+"城市:"+city+" 街道;"+street;
}
}classDemo3{public static voidmain(String[] args){
Address add=new Address("中国","广州","棠东东路");
Person p=new Person("jack",27,add);
p.speak();
System.out.println();
}
}
1.2 继承
1:描述一个学生类
1:姓名年龄学号属性,学习的方法
2:描述一个工人类
1:姓名年龄工号属性,工作的方法
3:描述一个人类
1:姓名年龄属性,说话的方法。
4:发现学生类和人类天生有着联系,学生和工人都是人。所以人有的属性和行为学生和工人都会有。出现类代码重复
classPerson {
String name;intage;//静态变量(类变量)对象和对象之间的代码重复使用静态变量
static String country = "CN";
Person() {
}voidspeak() {
System.out.println(name+ ":哈哈,我是人!!!");
}
}//让学生类和人类产生关系,发现学生is a 人,就可以使用继承
classStudent {
String name;intage;
Student() {
}voidstudy() {
System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
}
}classWorker {
String name;intage;voidwork() {
System.out.println(name+ ":好好工作,好好挣钱。");
}
}classDemo1 {public static voidmain(String[] args) {
Student s= newStudent();
s.name= "jack";
s.age= 20;
s.study();
Worker w= newWorker();
w.name= "rose";
w.work();
}
}
5:问题:
1:如果没有继承,出现类和类的关系无法描述
2:如果没有继承,类和类之间有关系会出现类和类的描述代码的重复。
1.3 继承特点
1:描述类和类之间的关系
2:降低类和类之间的重复代码
1:降低对象和对象之间的代码重复使用静态变量
2:降低类和类之间的代码重复使用就继承
1.4 extends关键字
继承使用extends关键字实现
1:发现学生是人,工人是人。显然属于is a 的关系,is a就是继承。
2:谁继承谁?
学生继承人,发现学生里的成员变量,姓名和年龄,人里边也都进行了定义。有重 复代码将学生类的重复代码注释掉,创建学生类对象,仍然可以获取到注释的成员。这就是因为继承的关系,学生类(子类)继承了人类(父类)的部分
classPerson {
String name;intage;//静态变量(类变量)对象和对象之间的代码重复使用静态变量
static String country = "CN";
Person() {
}voidspeak() {
System.out.println(name+ ":哈哈,我是人!!!");
}
}//让学生类和人类产生关系,发现学生is a 人,就可以使用继承
class Student extendsPerson {
Student() {
}voidstudy() {
System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
}
}class Worker extendsPerson {voidwork() {
System.out.println(name+ ":好好工作,好好挣钱。");
}
}classDemo1 {public static voidmain(String[] args) {
Student stu= newStudent();
stu.name= "jack";
stu.age= 20;
stu.study();
stu.speak();
System.out.println(stu.country);
System.out.println(Student.country);
Worker worker= newWorker();
worker.name= "rose";
System.out.println(worker.country);
worker.work();
worker.speak();
System.out.println();
}
}
继承细节;
1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类
2:子类并不能继承父类中所有的成员
1:父类定义完整的成员静态成员,非静态,构造方法。静态变量和静态方
法都可以通过子类名.父类静态成员的形式调用成功。
2:所有的私有成员不能继承,private修饰的成员。
3:构造函数不能被继承
3:如何使用继承
1:不要为了使用继承而继承。工人和学生都有共性的成员,不要为了节省代码,让工人继承学生。
/*如何使用继承:验证是否有 is a 的关系
例如:学生是人, 小狗是动物
注意:不要为了使用某些功能而继承,java只支持单继承*/
classDK {voidIp4S() {
System.out.println("好玩");
}
}class BGir extendsDK {
}classDemo {public static voidmain(String[] args) {newBGir().Ip4S();
}
}
1.5super关键字
1:定义Father(父类)类
1:成员变量int x=1;
2:构造方法无参的和有参的,有输出语句
2:定义Son类extends Father类
1:成员变量int y=1;
2:构造方法无参和有参的。有输出语句
1:this.y=y+x;
3:创建Son类对象
Son son=new Son(3);
System.out.println(son.y); //4
classFather {int x = 1;
Father() {
System.out.println("这是父类无参构造");
}
Father(intx) {this.x =x;
System.out.println("这是父类有参构造");
}voidspeak() {
System.out.println("我是父亲");
}
}class Son extendsFather {int y = 1;
Son() {
System.out.println("这是子类的无参构造");
}
Son(inty) {this.y = y +x;
System.out.println("这是子类的有参构造");
}voidrun() {super.speak(); //访问父类的函数
System.out.println("我是儿子");
}
}classDemo6 {public static voidmain(String[] args) {
Son s= new Son(3);
System.out.println(s.y);//4
}
}
4:子类对象为什么可以访问父类的成员。
1:this.y=y+x;有一个隐式的super super.x
5:super关键字作用
1:主要存在于子类方法中,用于指向子类对象中父类对象。
2:访问父类的属性
3:访问父类的函数
4:访问父类的构造函数
6:super注意
this和super很像,this指向的是当前对象的调用,super指向的是当前调用对象的父类。Demo类被加载,执行main方法,Son.class加载,发现有父类Father类,于是Father类也加载进内存。类加载完毕,创建对象,父类的构造方法会被调用(默认自动无参),然后执行子类相应构造创建了一个子类对象,该子类对象还包含了一个父类对象。该父类对象在子类对象内部。this super只能在有对象的前提下使用,不能在静态上下文使用。
2:子类的构造函数默认第一行会默认调用父类无参的构造函数,隐式语句
super();
1:父类无参构造函数不存在,编译报错。
Son(inty) {//super();隐式语句
this.y = y +x;
System.out.println("这是子类的有参构造");
}
3:子类显式调用父类构造函数
在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super()和this()不能同时存在构造函数第一行。
Son(inty) {super(y);//子类显式调用父类构造函数
this.y = y +x;
System.out.println("这是子类的有参构造");
}
Son(inty) {this(); //不能同时存在构造函数第一行
super(y);this.y = y +x;
System.out.println("这是子类的有参构造");
}
4:super思考
如果开发者自定义了一个类,没有显示的进行类的继承,那么该类中成员函数是否可以使用super关健健字?可以使用,继承了Object类,Object类是所有类的父类。
classDemo7 {public voidprint(){
System.out.println(super.toString());
}public static voidmain(String[] args){newDemo7().print();
System.out.println();
}
}
7:重写(Override)
1:定义Father类
1:姓名,吃饭方法,吃窝窝头。
2:定义Son类,继承Father
1:Son类中不定义任何成员,子类创建对象,仍然可以调用吃饭的方法。
2:父类的吃饭的方法,Son不愿吃。Son自己定义了吃饭的方法。
1:此时父类中有一个吃饭的方法,子类中有2个吃饭的方法,一模一样,只是方法体不一样。
2:一个类中两个函数一模一样,是不允许的。
1:编译运行,执行了子类的方法。
2:使用父类的方法,在子类方法中,使用super.父类方法名。
classFather {
String name;voideat() {
System.out.println("吃窝窝");
}
}class Son extendsFather {public void eat() { //继承可以使得子类增强父类的方法
System.out.println("来俩小菜");
System.out.println("来两杯");
System.out.println("吃香喝辣");
System.out.println("来一根");
}
}classDemo8 {public static voidmain(String[] args) {
Son s= newSon();//执行子类的方法
s.eat();
}
}
3:该现象就叫做重写(覆盖override)
1:在继承中,子类可以定义和父类相同的名称且参数列表一致的函数,将这种函数
称之为函数的重写.
4:前提
1:必须要有继承关系
5:特点
1:当子类重写了父类的函数,那么子类的对象如果调用该函数,一定调用的是重写过后的函数。
可以通过super关键字进行父类的重写函数的调用。
2:继承可以使得子类增强父类的方法
6:细节
1:函数名必须相同
2:参数列表必须相同
3:子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访
问权限否则编译报错
4:子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类。不能返回比父类更大的数据类型:如子类函数返回值类型是Object
1:定义A B C类B extends A
2:Father类中定义A getA();
3:Son类中重写getA();方法,尝试将返回值修改为B,C ,Object
1:B编译通过
2:C编译失败,没有继承关系
3:Object编译失败,比父类的返回值类型更大
classA {
}class B extendsA {
}classC {
}classFather {
String name;voideat() {
System.out.println("吃窝窝");
}//定义一个函数,获取A类的对象,
A getA() {return newA();
}
}class Son extendsFather {public void eat() { //继承可以使得子类增强父类的方法
System.out.println("来两杯");
System.out.println("来俩小菜");super.eat();
System.out.println("来一根");
}//B类是A类的子类
B getA() {return newB();
}
}classDemo8 {public static voidmain(String[] args) {
Son s= newSon();
s.eat();
}
}
7:子类对象查找属性或方法时的顺序:
1:原则:就近原则。
如果子类的对象调用方法,默认先使用this进行查找,如果当前对象没有找到属性或方法,找当前对象中维护的super关键字指向的对象,如果还没有找到编译报错,找到直接调用。
8:重载和重写的不同
1:重载(overload):
1:前提:所有的重载函数必须在同一个类中
2:特点:
函数名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)
3:不同:
个数不同、顺序不同、类型不同
2:重写(override):
1:前提:继承
2:特点:
函数名必须相同、参数列表必须相同。
子类的返回值类型要等于或者小于父类的返回值
9:重写练习
描述不同的动物不同的叫法
1:定义动物类
有名字,有吃和叫的方法
2:定义狗继承动物重写父类吃和叫的方法
3:定义猫继承动物重写父类吃和叫的方法
classAnimal{int x=1;
String name;voideat(){
System.out.println("吃东西");
}voidshout(){
System.out.println("我是动物");
}
}class Dog extendsAnimal{voideat(){
System.out.println("啃骨头");
}voidshout(){
System.out.println("旺旺");
}voideat(String food){
System.out.println("吃:"+food);
}
}class Cat extendsAnimal{voideat(){
System.out.println("吃老鼠");
}voidshout(){
System.out.println("喵喵");
}
}classDemo9{public static voidmain(String[] args){
Dog d=newDog();
d.shout();
d.eat();
Cat c=newCat();
c.shout();
c.eat();
System.out.println();
}
}
1.6instanceof关键字
1:快速演示instanceof
Personp=newPerson();
System.out.println( pinstanceofPerson);
2:instanceof是什么?
1:属于比较运算符:
2:instanceof关键字:该关键字用来判断一个对象是否是指定类的对象。
3:用法:
对象instanceof类;
该表达式是一个比较运算符,返回的结果是boolea类型true|false
注意:使用instanceof关键字做判断时,两个类之间必须有关系。
3:案例
定义一个功能表函数,根据传递进来的对象的做不同的事情,如果是狗让其看家,如果是猫让其抓老鼠
1:定义动物类
2:定义狗类继承动物类
3:定义猫类继承动物类
4:定义功能根据传入的动物,执行具体的功能
5:instanceof好处
1:可以判断对象是否是某一个类的实例
/*instanceof
比较运算符
检查是否是类的对象
1:可以判断对象是否是某一个类的实例
用法
对象 instanceof 类;
案例
定义一个功能函数,根据传递进来的对象的做不同的事情
如果是狗让其看家,如果是猫让其抓老鼠
1:定义动物类
2:定义狗类继承动物类
3:定义猫类继承动物类
4:定义功能根据传入的动物,执行具体的功能*/
classAnimal {
String name;voideat() {
System.out.println("吃东西");
}voidshout() {
System.out.println("我是动物");
}
}class Dog extendsAnimal {voideat() {
System.out.println("啃骨头");
}voidshout() {
System.out.println("旺旺");
}
}class Cat extendsAnimal {voideat() {
System.out.println("吃老鼠");
}voidshout() {
System.out.println("喵喵");
}
}classDemo11 {public static voidmain(String[] args) {
Demo11 d= newDemo11();//对象 instanceof 类;
System.out.println(d instanceofDemo11);
d.doSomething(newDog());
d.doSomething(newCat());
}//定义一个功能函数,根据传递进来的对象的做不同的事情//如果是狗让其看家,如果是猫让其抓老鼠//对象 instanceof 类;
voiddoSomething(Animal a) {if (a instanceofDog) {
a.eat();
a.shout();
System.out.println("小狗看家");
}else if (a instanceofCat) {
a.eat();
a.shout();
System.out.println("抓老鼠");
}
}
}
练习:
byte[] bs = new byte[] { 1, 2, 3};int[] is = new int[] { 1, 2, 3};
String[] ss= new String[] { "jack", "lucy", "lili"};
System.out.println(bsinstanceof byte[]); //true
System.out.println(is instanceof int[]); //true
System.out.println(ss instanceof String[]); //true//System.out.println(bs instanceof int[]);//不可转换的类型