一、tips
1、方法重写要点:
①方法名与父类中的方法名相同
②方法体不同 或
访问权限大于等于父类 或
返回值类型小于等于父类(即是父类返回值类型的子类)
2、子类继承父类时调用父类的无参构造函数,若父类中没有无参构造函数,则在子类中使用super(参数)显示调用父类中含参构造函数
二、知识点
7.面对对象的特征
7.1.oop三大特征
抽象:定义类,定义属性,定义方法的过程(抓取主要信息,忽略次要信息的过程)
封装:在代码中隐藏实现了过程,提供对外的功能
继承:在继承中必须有父类和子类
父类:公共的属性和公共的行为比较少的类,父类是抽象的
子类:公共的属性和公共的行为比较多的类,子类要比父类更具体
牛 为父类( 四蹄子,比较大, 哞哞叫 )
水牛 为子类(除了牛类的共有特征以为,一天泡在水里)
多态
7.2.继承的实现
在JAVA中,通过extends 实现子类对父类的继承
当子类继承了父类以后,子类就会拥有父类的一些属性和行为(不是全部)
(公有的属性和公有的方法)
如果在子类中调用父类的构造函数,就需要使用super()实现调用父类的构造函数调用,且super() 必须出现在子类构造函数的第一句话
在创建子类对象的时候,首先要调用父类的构造函数,然后才能执行子类自己的构造函数,如果在子类构造函数中使用了super()显示的调用了父类指定的构造函数,则父类无参数的构造函数不会执行,如果子类构造函数中没有显示调用父类的构造函数,则默认执行父类无参数的构造函数
7.3.访问修饰符
访问修饰符:用于限定变量和方法的可见范围
访问修饰符分类: public > protected > 默认 >private
7.4.在继承关系中子类可以继承父类的那些属性和方法
在继承关系中,子类可以继承父类的public 属性和方法,可以继承protected属性和方法,如果子类和父类在同一个包中,则父类默认访问修饰符属性和方法也是可以被子类继承的。父类的构造函数不能继承
7.5.方法重写
在继承关系中,子类的方法签名和父类的方法签名一致,或子类的方法访问修饰符大于父类的方法访问修饰符这时候,子类的方法就重写了父类的方法。
方法重写时子类的返回值类型和父类的返回值类型一致,或者子类的返回值类型是父类返回方法返回值类型的子类也是方法重写。
父类方法如下
public void eat(){
System.out.println("动物都会吃");
}
protected void run(){
}
private void jump(){
}
public Animal getObj(){
return null;
}
子类方法如下:
//子类重写父类的方法
@Override
public void eat(){
System.out.println("sss"); //属于方法重写,可以继承,且方法签名和父类一致
}
@Override
protected void run(){ //属于重写,可以继承,且方法签名和父类一致
}
@Override
public void run(){ //属于重写,可以继承,子类的访问修饰符大于父类访问修饰符
}
@Override
public Dog getObj(){ //属于重写,可以继承,子类方法的返回值类型是父类方法返回值类型的子类
return null;
}
public void jump(){ //不属于重写,服了的私有属性和方法不能被继承,因此不能重写。
}
7.6.方法重载和方法重写的区别
方法重写必须在继承关系中,子类的方法签名和父类的一致(访问修饰符大于等于父类访问修饰符,返回值类型 和父类一样或是父类返回值类型的子类,方法名称一致,参数列表一致) 和参数的名称没有关系,只和类型有关系
方法重载必须在一个类中,方法名称相同,参数列表不同,和返回值无关,和访问修饰符没有关系,和参数的名称没有关系
构造函数不能被继承,构造方法也不能被重写,构造方法可以重载
7.7.Super 关键字 和 this 关键字
This 当前类的当前对象,可以调用当前类中的一些属性和方法
super在当前类中,父类对象的引用,可以调用的是父类的一些属性和方法
Super出现在子类中,用来指定当前子类的父类对象
Super就可以调用父类的属性,父类的方法,父类的构造函数
Super在子类中调用属性和方法的时候,大部分的情况和this调用的属性和方法同一个 this.getName() == super.getName();
当子类重写了父类的方法的时候,super.showInfo() 就是父类的方法,this.showInfo()就是子类重写父类的方法
Super 只能调用父类允许继承的那些方法和属性
This可以调用自己的任何方法(public ,protected,默认的,private)
Super调用父类的构造函数
在默认的情况下,子类的构造函数会默认调用父类的无参数的构造函数
Super() 代表调用父类的无参数构造函数(Super()写不写都一样),必须出现在子类构造函数的第一句
通过super(参数值列表) 来调用父类带参数的构造函数,也必须写在子类构造函数的第一句话
This() 表示子类自己在一个构造函数中调用另一个构造函数,也必须出现在子类构造函数的第一句话( this() 和super()不能同时出现)
//构造函数
public Dog(){
super();
System.out.println("子类的无参数构造函数");
}
public Dog(String name,Integer age,String type)
{
this();
//super(name,age); //直接调用父类的带参数的构造函数
System.out.println("子类的带参数构造函数");
this.type = type;
}
8.多态
向上转型要比向下转型重要的多
8.1.向上转型
把子类对象赋给父类的引用
//向上转型:向上转型安全
//把子类对象赋予父类的引用
Animal animal = new Dog();
Animal animal2 = dog;
向上转型以后,父类的引用可以调用的方法是由父类引用保存的对象决定,调用的方法就是子类从父类中继承的方法或子类重写的父类的方法
//创建一个狗类的对象 调用了无参数的构造函数
Dog dog = new Dog();
System.out.println("dog引用掉方法");
dog.eat(); //从父类中继承的方法
dog.yaoren(); //子类自己扩展的方法
dog.showInfo(); //子类重写父类的方法
//向上转型:向上转型安全
//把子类对象赋予父类的引用
Animal animal = new Dog();
animal.eat(); //子类继承父类的方法
animal.showInfo(); //子类重写父类的方法
同一个父类的引用变量,因为保存的对象不同,导致在调用同一个方法的时候结果也是不一样的
Animal animal2=null;
animal2 = new Animal();
animal2.eat(); //父类定义方法
animal2.showInfo(); //父类中定义的方法
animal2 = new Dog();
animal2.eat(); //Dog子类继承父类的方法
animal2.showInfo(); //Dog子类重写父类的方法
animal2 = new Cat();
animal2.eat(); //Cat子类继承父类的方法
animal2.showInfo(); //Cat子类重写父类的方法
System.out.println("程序结束");
8.2.向下转型(不安全,容易产生类型转换异常)
把父类引用 赋予子类引用
//把父类的引用强转子类的引用,向下转型不安全,取决于父类引用中保存的对象类型
//正确能够向下转型 原因:animal 引用中 保存的就是 dog对象
Animal animal = new Dog();
Dog dog = (Dog)animal;
System.out.println("dog:" + dog);
//向下转型过程中出异常, 原因: animal 引用中保存的是animal对象
animal = new Animal();
Dog dog1 = (Dog)animal;
System.out.println("dog1:" + dog1);
//向下转型过程中出现异常 原因:animal引用中保存的是cat对象
animal = new Cat();
Dog dog2 = (Dog)animal;
System.out.println("dog2:" + dog2);
如何保证向下转型的安全,需要进行父类引用中保存对象的类型判断
使用instanceof 判断父类引用中保存的对象类型
//正确能够向下转型 原因:animal 引用中 保存的就是 dog对象
Animal animal = new Cat();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println("转换成了dog对象");
dog.showInfo();
}
if (animal instanceof Cat) {
Cat cat = (Cat) animal;
System.out.println("转换成了cat对象");
cat.showInfo();
}
8.3.多态的实现
多态的概念:同一个父类引用,因为保存了不同的子类对象,在调用同样的方法的时候(子类重写后的方法),获取了不同的结果 这个就是多态
多态的实现:
1:必须要有继承 2:子类必须要重写父类的方法
3:向上转型 4:使用父类引用调用子类重写的方法
1必须有父类
动物类
public class Animal {
private String name;
private String age;
//构造函数重载
public Animal(){
System.out.println("这是父类的无参数构造函数");
}
public Animal(String name) {
this.name = name;
}
public Animal(String name, String age) {
this.name = name;
this.age = age;
}
//连个eat方法形成了方法重载
public void eat(){
System.out.println("动物:"+this.name+"在吃东西");
}
public void eat(String food){
System.out.println("动物:"+this.name+"在吃"+food);
}
public void show(){
System.out.println("动物的基础信息");
System.out.println("名称:" + this.name);
System.out.println("名称:" + this.age);
}
2:有多个子类
子类1
public class Fish extends Animal {
private String qi; //鱼鳍属性
public Fish(){
System.out.println("这是子类的无参数构造函数");
}
public Fish(String name,String age,String qi){
//显示的调用了父类的带参数的构造函数
super(name,age);
this.qi = qi;
}
//重写的功能
@Override
public void eat(String food) {
System.out.println("小鱼:"+this.getName()+"正在吃:" + food);
}
@Override
public void show() {
super.show();
System.out.println("小鱼有:"+ this.qi);
}
子类2
public class Bird extends Animal{
private String chibang;
public Bird(String chibang) {
super();
this.chibang = chibang;
}
//重写
@Override
public void eat(String food) {
System.out.println("小鸟在吃:"+food);
}
@Override
public void show() {
super.show();
System.out.println("小鸟有:" + chibang);
}
//扩展小鸟自己的东西
public void fly(){
System.out.println("小鸟:" + this.getName()+",在天空中飞翔");
}
3)向上转型(不同子类对象赋予同一个父类引用)
public class Zoo {
//通过多态的方式,可以解决喂食所有动物的功能
public void weishiwu(Animal animal,String food){
animal.eat(food);
}
}
4)调用同样的方法(animal2.showInfo()) 获取了不同的结果
public static void main(String[] args) {
Zoo zoo = new Zoo();
Fish fish = new Fish();
fish.setAge("2");
fish.setName("皇皇");
fish.setQi("像扇子一样的鱼鳍");
Bird bird = new Bird("四只大翅膀");
bird.setAge("3");
bird.setName("菲菲");
zoo.weishiwu(fish, "蚯蚓");
zoo.weishiwu(bird, "谷类");
}