一、继承
继承是Java在软件重用方面一个重要且功能强大的特征。假定要定义一个类,对圆、矩形和三角形建模。这种类有很多共同的特性。设计这些类类避免冗余并使用系统更易于理解和维护的最好的方式是什么?即继承。
1、父类和子类
继承使得你可以定义一个通用的类(即父类),之后扩充该类为一个更加特定的类(即子类)。
例:父类——Animal类
public class Animal{
/*
该类中的成员变量
*/
public String name;
public int legnum;
/*
如果在一个类中有static方法,则先执行的就是static
静态方法
*/
static{
System.out.println("这个是动物类的静态代码块!");
}
/*
该类中的构造函数——一般来说如果该类中无构造函数则
在实例化的过程即默认为无参的构造函数
构造函数的作用就是初始化成员变量
*/
public Animal(String name,int legnum){
this.name=name;
this.legnum=legnum;
}
/*
成员函数
*/
public void print(){
System.out.print(this.legnum+" "+this.name);
}
}
子类Cat及子类继承父类:
public class Cat extends Animal{
public static String catcolor;
public Cat(String name,int legnum,String catcolor){
/*
super()函数的目的是:因为Cat类继承了Animal类
在Animal类中的构造方法中拥有参数String name、int legnum两个成员函数
为了能够给Animal传参,即使用super()函数
*/
super(name,legnum);
this.catcolor=catcolor;
}
public void print(){
System.out.println("猫的名字是:"+this.name+",猫有"+this.legnum+"条腿,猫的颜色是:"+this.catcolor);
}
}
继承的特点:1、和传统的理解不同,子类并不是父类的一个子集。实际上,一个子类通常比它的父类包含更多的信息和方法;2、父类中的私有数据域在该类之外是不可访问的;3、不是所有的“是一种”is——a关系都该用继承来建模;4、继承是用来为“是一种”关系建模的;5、某些程序设计语言是允许从几个类派生出一个子类。
注意事项——
父类的构造函数被调用,但不代表父类就被创建对象了!
所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用
并且注意super(...) 如果父类没有默认无参构造函数 那么子类构造函数中super()失效了
所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(...)
this(...)是当前类中 本类构造函数调用本类构造函数的方式
super(...)是本类构造函数调用父类构造函数的方式
都必须在第一行 那么这两冲突不?
如果本类构造函数当中不存在调用关系 那么每一个本类构造函数第一句都是super(...)
如果本类构造函数当中存在调用关系,那么最后被调用的那个构造函数第一句绝对是super(...)
this(...)的调用是单向的还是递归的?是单向的,那么最后被调用的第一句绝对就是super(...)
子父类中成员函数的特点:
1、如果只有子类有且非私有 那么就调用子类的
2、如果只有父类有且非私有 那么就调用父类的
3、如果子父类都有且非私有 那么就调用子类的(函数重写)
2、方法的重写
函数重写:在子父类中,同名函数
函数有什么组成:函数声明(权限 类型 返回值类型 函数名 参数列表)+函数体({}里面的内容)
重写的意义在于哪?在于子类继承了父类的函数声明(功能),但是子类可以将该函数的具体实现进行优化或更改
郭德纲会说相声 郭麒麟也会说相声
子承父业!
1.保留父类的功能声明 子类可以进一步优化
2.保留父类的功能声明 子类可以重新定义。重写当中应该注意到的一些细节:
1.函数重名 但是参数列表不同 不构成重写关系
2.函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
3.子类重写父类函数时,权限>=父类权限
4.当然 如果父类函数权限为private 子类压根就继承不到 何谈重写
二、多态
多种状态:就是指一个对象可以有多种状态(他在继承体系中的位置变化)
D->C->B->A->Animal
位置的变化只能是向上变 但不能低于自身
对于C而言 可以当做B来看 也可以当做A来看 也可以当成Animal
小明 男人 人 动物
小明的学校开家长会 小明不想让他爸爸去 他让大明去 大明就是小明他哥
大明冒充Dad去参加家长会的话,那么所表现出来的行为 是不是应该符合他爸行为
不同的视角 不同的角色
无论是在哪个视角场合 对象本身变了没有?只不过我们需要对象在不同的场合表现出相对应的行为
在Java当中 多态代码表现 就是 父类引用指向子类的对象
多态的前提:继承 重写
多态的好处:对代码的功能进行了可扩展性
子类对象可以当做父类对象去使用 但是有限制 只能调用父类函数或重写的函数
不能使用子类特有的行为多态当中 成员变量的特点:只能访问父类中的成员变量
多态当中 成员函数的特点:
1、如果子类没有重写 且父类中有 调用父类的
2、如果子类有重写 调用子类重写的
3、如果不存在重写 父类没有 那就报错了!
三、抽象类
抽象类:模糊不清的类 不具体的类
当我们在抽取一个父类的时候,发现子类当中的一些共同方法在父类中无法进行具体的实现
并且这些方法只能在子类中具体实现时,父类当中的这些函数就只保留函数声明即可,不必写函数体
那么此时这个函数就是 抽象函数! 有抽象函数的类 就是抽象类!
特点:
1.抽象类能否创建对象?不能 对象本身是一个具体的东西 而抽象类中含有不具体的内容
2.抽象类必须作为父类存在吗?必须 抽象类就等着被继承呢!
3.抽象类和一般类有什么区别?就是一般类的特殊情况
唯一的区别只在于抽象类中有抽象函数!
4.抽象类中必须有抽象函数吗?不一定 AWT界面开发
5.abstract这个关键字不能和那些关键字共存?
private 抽象函数就等着被子类重写实现呢!
static 静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据
类名.抽象函数 很尴尬!
如果抽象函数可以被静态 那么我们还需要对象干什么?
具体代码实现:
/*
主函数
*/
class GraphicDemo{
public static void main(String[] args){
/**
多态——父类引用指向子类对象
*/
Graphic g1=new Triangle();
System.out.println("三角形的面积:"+g1.getArea());
System.out.println("三角形的周长:"+g1.getLength());
Graphic g2=new Rectangle();
System.out.println("矩形的面积:"+g2.getArea());
System.out.println("矩形的周长:"+g2.getLength());
Graphic g3=new Triangle();
System.out.println("圆形的面积:"+g3.getArea());
System.out.println("圆形的周长:"+g3.getLength());
}
}
/*
抽象类——父类
关键字——abstract
*/
abstract class Graphic{
//面积
public abstract double getArea();
//周长
public abstract double getLength();
}
/**
求两点之间的距离
*/
class Point{
private double x;
private double y;
private double r;
/**
构造函数——初始化成员数据
*/
public Point(double x,double y){
this(x,y,0);
//this.y=y;
}
public Point(double r){
this(0,0,r);
}
public Point(double x,double y,double r){
this.x=x;
this.y=y;
this.r=r;
}
public double getR(){
return this.r;
}
public double distance(Point p){
return Math.pow((this.x-p.x)*(this.x-p.x)+(this.y-p.y)*(this.y-p.y),0.5);
}
}
/**
求三角形的周长
*/
class Triangle extends Graphic{
//三个点 //三个边
@Override
public double getArea(){
Point p1=new Point(0,0);
Point p2=new Point(4,0);
Point p3=new Point(0,4);
return p1.distance(p2)*p1.distance(p3)*0.5;
}
@Override
public double getLength(){
Point p1=new Point(0,0);
Point p2=new Point(4,0);
Point p3=new Point(0,4);
return p1.distance(p2)+p1.distance(p3)+p2.distance(p3);
}
}
/**
求矩形的面积周长
*/
class Rectangle extends Graphic{
//四个点 //四个边
@Override
public double getArea(){
Point p1=new Point(0,0);
Point p2=new Point(4,0);
Point p3=new Point(0,4);
//Point p3=new Point(4,4);
return p1.distance(p2)*p1.distance(p3);
}
@Override
public double getLength(){
Point p1=new Point(0,0);
Point p2=new Point(4,0);
Point p3=new Point(0,4);
return (p1.distance(p2)+p1.distance(p3))*2;
}
}
/**
求圆的面积和周长
*/
class Circle extends Graphic{
//半径 //圆心点
@Override
public double getArea(){
Point p1=new Point(0,0,4);
return p1.getR()*3.14*p1.getR();
}
@Override
public double getLength(){
Point p1=new Point(0,0,4);
return p1.getR()*3.14*2;
}
}