一,继承
1.继承的由来:当我们在定义若干个类的时候,发现某一些类中具有相同的属性和行为,那么,我们就可以将这些相同的部分进行抽取,独立生成另外一个类,那么这个生成出来的类我们称之为是父类,其他的被抽取内容的类称之为子类
2.我们将被继承的类称为父类;继承的类称为子类 使用extends关键字实现继承关系
3.java中的继承是一种单继承关系 一个子类只能有一个父类,一个父类可以有多个子类
在C++中,继承是多继承的,不太符合实际的社会问题,所以Java更加符合现实编程;
当然Java当中也有多继承的时候,-----如果是类与类之间 必须是单继承;如果是接口与接口之间,可以是多继承
既然有了继承,那么在Java当中就有了继承体系:A----->B------>C------>D : A是B的子类,B是C的子类,C是D的子类
在Java继承体系当中,所有类的最终父类都是Object,Object不存在父类;如果我们在定义一个类的时候,没有显著声明父类的时候 那么该类的父类默认是Object
4.子类可以使用父类的属性和方法,但父类不能访问子类独有的属性和方法
5.创建子类对象时,默认先执行父类的构造方法,再执行子类的构造方法
6.子类如果想要调用父类的构造方法时,使用super关键字调用 super 与this相对
super父类的引用---超类的引用 用法和this关键字类似
局部变量和成员变量如果重名了 this区分----- this.成员变量=局部变量(将局部变量的值赋给成员变量)
子类的局部变量/成员变量和父类变量重名了 super区别 -----一旦成员变量前面加上super,则代表调用的父类对应的变量
class Extends{
public static void main(String[] args){
Zi zi=new Zi();
System.out.println(zi.num1);
}
}
class Fu{
int num1=20;
static int num2=40;
static int num3=50;
}
class Zi extends Fu{
int num1=30;
static int num2=30;
void show(){
System.out.println(num1+","+num2+","+num3);//30,30,50
//局部变量/成员变量和父类变量重名了 super区别
System.out.println(super.num1+","+super.num2+","+super.num3);//20,40,50
}
}
7.如果在父类中加入静态代码块 在子类中也加入静态代码块 那么创建子类对象时,它的执行顺序为:父类的静态代码块--子类的静态代码块--父类的构造函数--子类的构造函数
子父类中成员变量/静态变量的特点(相当于就近原则):
如果只有子类有且非私有 那么就调用子类的
如果只有父类有且非私有 那么就调用父类的
如果子父类都有且非私有 那么就调用子类的
(成员变量之间 是不存在重写关系的!!!)
子类.属性 顺序:子类对象成员->子类静态->父类成员->父类静态
子类成员函数在内部调用变量时 局部变量->子类对象成员->子类静态->父类成员->父类静态
public class Animal{
public String name;
public int legnum;
static{
System.out.println("this is static Animal");
}
public Animal(String name,int legnum){
this.name=name;
this.legnum=legnum;
System.out.println("this is animal");
}
public void happy(){
System.out.println("叫");//方法体
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setLegnum(int legnum){
this.legnum=legnum;
}
public int getLegnum(){
return legnum;
}
}
public class Dog extends Animal{
public Dog(String name,int legnum){
super(name,legnum);//原因是先要调用父类的构造函数
System.out.println("this is dog");
}
static{
System.out.println("this is static dog");
}
public void f(){//dog里面的方法
System.out.println(name);//访问name这个属性
System.out.println(legnum);
}
public void happy(){
System.out.println("叫");
}
}
public class Cat extends Animal{
public Cat(String name,int legnum){
super(name,legnum);
}
public void happy(){
System.out.println("叫");
}
}
public class Testa{
public static void main(String[] args){
Animal a=new Animal("哈哈",4);
Dog d=new Dog("花花---",4);//创建子类的时候先要调用父类的构造方法
System.out.println(d.getName());
}
}
8.子父类中构造函数的特点:现象:子类的构造函数在调用运行的时候 先执行父类的构造函数
在子类的构造函数当中,有一句默认的super(...)隐藏了,而且这句代码必须是在第一行------ 对super的调用必须是构造器中的第一个
既然子类继承自父类 那么必然会继承到父类当中的一些数据 ,所以,在子类构造函数之中,必须先让父类把这些数据进行一些初始化才能继承给子类
注意:父类的构造函数被调用,但不代表父类就被创建对象了!所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用
class Extends{
public static void main(String[] args){
Zi zi=new Zi();
System.out.println(zi.num1);
}
}
class Fu{
int num1=20;
static int num2=40;
static int num3=50;
Fu(){
System.out.println("这是父类的构造方法");
}
}
class Zi extends Fu{
int num1=30;
static int num2=30;
Zi(){
//隐藏了 super();
System.out.println("这是子类的构造方法");
}
void show(){
System.out.println(num1+","+num2+","+num3);
//局部变量/成员变量和父类变量重名了 super区别
System.out.println(super.num1+","+super.num2+","+super.num3);
}
}
并且注意super(...) 如果父类没有默认无参构造函数 那么子类构造函数中super()失效了,所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(...)
this(...)是当前类中 本类构造函数调用本类构造函数的方式, super(...)是本类构造函数调用父类构造函数的方式
如果本类构造函数当中不存在调用关系 那么每一个本类构造函数第一句都是super(...)
如果本类构造函数当中存在调用关系,那么最后被调用的那个构造函数第一句绝对是super(...)
this(...)的调用是单向的,那么最后被调用的第一句绝对就是super(...)
class Extends{ public static void main(String[] args){ Zi zi=new Zi();//创建Zi类,调用子类的无参构造函数 } } class Fu{ int num1=20; static int num2=40; static int num3=50; Fu(){ System.out.println("这是父类的构造方法"); } } class Zi extends Fu{ int num1=30; static int num2=30; Zi(){ this(0,0); System.out.println("这是子类的构造方法1"); } Zi(int num1){ this(0,0); System.out.println("这是子类的构造方法"); } Zi(int num1,int num2){ super(); this.num1=num1; this.num2=num2; System.out.println("这是子类的构造方法2"); } void show(){ System.out.println(num1+","+num2+","+num3); //局部变量/成员变量和父类变量重名了 super区别 System.out.println(super.num1+","+super.num2+","+super.num3); } } /*打印结果为: 这是父类的构造方法 这是子类的构造方法2 这是子类的构造方法1 */
子父类中成员函数的特点:
如果只有子类有且非私有 那么就调用子类的
如果只有父类有且非私有 那么就调用父类的
如果子父类都有且非私有 那么就调用子类的(函数重写)
二,重写
1. 满足条件:
- )一定发生在两个类中这两个类一定是继承关系
- )访问修饰符相同 返回类型相同 方法名字相同 方法体不同 子类的访问修饰符不能比父类更严格 父类更抽象,子类更具体
- )重写是多态的表现特征之一 具体实例如下 happy()方法:
public class Animal{
public Animal(){
}
/**
描述动物开心
子类更具体,父类更抽象
*/
//方法
public void happy(){
System.out.println("叫");//方法体
}
}
public class Dog extends Animal{
public Dog(){
super();//原因是先要调用父类的构造函数
}
public void f(){//dog里面的方法
}
public void happy(){
System.out.println("汪汪!!!!");//方法体--方法体一定要在方法内部
}
}
public class Testa{
public static void main(String[] args){
Dog d=new Dog();//创建子类的时候先要调用父类的构造方法
d.happy();
}
}
2.重写的意义:在于子类继承了父类的函数声明(功能),但是子类可以将该函数的具体实现进行优化或更改
3.(1.)保留父类的功能声明 子类可以进一步优化
(2.)保留父类的功能声明 子类可以重新定义
4.重写当中应该注意到的一些细节:
1.)函数重名 但是参数列表不同 不构成重写关系
2.)函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
3.)子类重写父类函数时,权限>=父类权限
4.)当然 如果父类函数权限为private 子类压根就继承不到 就不可能重写父类的方法
三,多态
1.多态是面向对象的特征之一 ----- 多态顾名思义:就是指一个对象可以有多种状态(他在继承体系中的位置变化)---位置的变化只能是向上变 但不能低于自身 eg:A-->B-->C-->--D:对B而言可以当C看,也可以当D看
2.多态的好处:对代码的功能进行了可扩展性;换句话说就是:子类对象可以当做父类对象去使用 但是有限制 ,只能调用父类函数或重写的函数,不能使用子类特有的方法
3.父类引用指向子类对象是多态最主要的表现之一
eg:
Animal a=new Dog("dog",4);
Animal acat=new Cat("cat",4);
4.多态当中 成员变量的特点:只能访问父类中的成员变量
5.多态当中 成员函数的特点:
如果子类没有重写 且父类中有 调用父类的
如果子类有重写 调用子类重写的
如果不存在重写 父类没有 那就报错了!
四,数据类型转换(向上转型和向下转型)
向上转型对应着:自动转换
public class Testa{
public static void main(String[] args){
Animal a=new Animal("哈哈",4);
Dog d=new Dog("花花---",4);
a=d;
System.out.println(a.getName());//输出为花花----
}
}
向下转型对应着:强制转换
public class Testa{
public static void main(String[] args){
//父类引用指向子类对象
Animal a=new Dog("dog",4);
Dog d=new Dog("花花---",4);//创建子类的时候先要调用父类的构造方法
d=(Dog)a;
System.out.println(d.getName());//输出为 dog
}
}
满足条件:两者之间要存在继承或者是实现关系(接口)
五,抽象类(在类名前加abstract)
1.抽象类:顾名思义就是模糊不清的类 不具体的类
2.当我们在抽取一个父类的时候,发现子类当中的一些共同方法在父类中无法进行具体的实现,并且这些方法只能在子类中具体实现时,父类当中的这些函数就只保留函数声明即可,不必写函数体 -----那么此时这个函数就是 抽象函数! 有抽象函数的类 就是抽象类!
3.特点:
1.)抽象类不能创建对象------ 对象本身是一个具体的东西 而抽象类中含有不具体的内容
2.)抽象类必须作为父类存在----- 抽象类就等着被继承呢!
3.)抽象类和一般类的区别!抽象类就是一般类的特殊情况,唯一的区别只在于抽象类中有抽象函数!
4.)抽象类中不一定有抽象函数, AWT界面开发会有
5.)abstract这个关键字不能和那些关键字共存?
private 一旦加了private子类就不会访问到这个方法,更不要说重写-----而抽象函数存在就是等着子类重写该方法
static 静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据
class Test{
public static void main(String[] args){
Dog d=new Dog();
Cat c=new Cat();
Pig p=new Pig();
feed(d);
feed(c);
feed(p);
}
public static void feed(Animal a){
a.eat();
//判断对象的本质类型 instanceOf
if(a instanceof Pig){
Pig pp=(Pig)a;
pp.gongBaiCai();
}
}
}
abstract class Animal{
abstract void eat();
abstract void jiao();
}
class Pig extends Animal{
void eat(){
System.out.println("猪啥都吃......");
}
void jiao(){
System.out.println("猪哼哼哼......");
}
void gongBaiCai(){
System.out.println("猪拱白菜......");
}
}
class Dog extends Animal{
void eat(){
System.out.println("狗吃狗粮......");
}
void jiao(){
System.out.println("狗汪汪汪......");
}
void lookDoor(){
System.out.println("狗看家~......");
}
}
class Cat extends Animal{
void eat(){
System.out.println("猫吃鱼......");
}
void jiao(){
System.out.println("猫喵喵喵......");
}
void catchMouse(){
System.out.println("猫捉老鼠~......");
}
}