1.1什么是向上转型
1.向上转型可以理解为
子类对象实例化一个对象
父类对象实例化一个对象
但是这个父类实例化的对象是指向子类实例化对象的,这样就让父类拥有了子类成员变量的全部特征
(比较重要的一点是,父类不能够拥有子类中的方法下面代码就可以详细讲解)
把这个代码方道idea中可以发现代码的第37行报错了而38行是没有报错的!由此可以看出父类被向上转型以后是可以调用子类的成员变量,不能调用子类的成员方法的!
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void barks_1(){
System.out.println(this.name+"狗的名字是");
}
}
class Dog extends Animal{
public String color ;
public Dog (String name,int age,String color){
super(name,age);
this.color = color;
}
public void barks (){
System.out.println(this.name+"正在汪汪叫");
}
}
class Cat extends Animal{
public Cat(String name,int age){
super(name,age);
}
}
public class Frank {
public static void main(String[] args) {
Dog dog = new Dog("旺财",18,"green");
Animal dog_2 = dog ;
dog_2.barks();
dog_2.barks_1();
}
}
2.1什么是多态!
2.1.1理解多态
1.要先理解向上转型。
(1.1已经详细讲解)
2.理解重写
2.1.2 什么是静态绑定!
1.代码(动态绑定代码)
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
}
class Dog extends Animal{
public String color ;
public Dog (String name,int age,String color){
super(name,age);
this.color = color;
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
}
}
public class Frank {
public static void main(String[] args) {
Dog dog = new Dog("旺财",18,"green");
Animal animal = dog ;
animal.eat ();
}
}
2.1.2.1动态绑定是什么(先理解动态绑定)
(1)在父类中也就是Animal类中我定义了一个eat方法,在子类dog中我定义了一个eat方法这两个方法是一样的!
(2)什么是动态绑定:在编译的时候还是认为调用了父类的eat方法,在运行的时候就绑定到了子类当中,(如上面代码就是在编译的时候就是eat方法但是一旦运行就是调用的子类方法)。
2.1.2.2 重写的特征
1.方法名相同。
2.参数列表相同【参数的顺序,类型个数】
3.返回值相同
代码如下
public void eat(){
System.out.println(this.name+"恰饭开心嘿嘿嘿");
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
}
class Dog extends Animal{
public String color ;
public Dog (String name,int age,String color){
super(name,age);
this.color = color;
}
public void eat(){
System.out.println(this.name+"恰饭嘿嘿嘿");
}
}
public class Frank {
public static void main(String[] args) {
Dog dog = new Dog("旺财",18,"green");
Animal animal = dog ;
animal.eat ();
}
}
2.1.2.3 向上转型的几种方式
1.代码
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
}
class Bird extends Animal{
public Bird(String name, int age) {
super(name, age);
}
public void fly(){
System.out.println(this.name+"正在飞");
}
public void eat(){
System.out.println(this.name+"正吃狗粮");
}
}
class Dog extends Animal{
public String color ;
public Dog (String name,int age,String color){
super(name,age);
this.color = color;
}
public void eat(){
System.out.println(this.name+"恰饭嘻嘻嘻嘻");
}
}
public class Frank{
public static void fun(Animal animal){
//第二种转型方式传参
}
public static void main(String[] args) {
Dog dog = new Dog("旺财",18,"green");//子类
Bird bird = new Bird("布谷",18);//子类
Animal animal_2 = bird ;//向上转型第一种方式直接赋值
fun(bird);//第二种向上转型,animal = bird animal就具有了bird子类的特征
fun(dog);//同理
}
}
//class Frank_1 {
// public static void main3(String[] args) {
// Dog dog = new Dog("旺财",18,"green");
// Animal animal = dog ;
// animal.eat ();
// }
//}
我们定jinta5方法是fun,静态方法可以脱离对象,(在这里我们不用调用成员方法和成员变量所以只能用静态方法通过传参的方式进行向上转型),这样就使得animal这个对象有了Dog和Bird子类的特征(第二种向上转型)。
3.多态的展现
3.1我们在2.1.2.3中的第二个向上转型的代码进行补充来实现多态。
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+"正在恰饭");
}
}
class Bird extends Animal{
public Bird(String name, int age) {
super(name, age);
}
public void fly(){
System.out.println(this.name+"正在飞");
}
public void eat(){
System.out.println(this.name+"正吃狗粮");
}
}
class Dog extends Animal{
public String color ;
public Dog (String name,int age,String color){
super(name,age);
this.color = color;
}
public void eat(){
System.out.println(this.name+"恰饭嘻嘻嘻嘻");
}
}
public class Frank{
public static void fun(Animal animal){
//第二种转型方式传参
animal.eat();
}
public static void main(String[] args) {
Dog dog = new Dog("旺财",18,"green");//子类
Bird bird = new Bird("布谷",18);//子类
Animal animal_2 = bird ;//向上转型第一种方式直接赋值
fun(bird);//第二种向上转型,animal = bird animal就具有了bird子类的特征
fun(dog);//同理
}
}
//class Frank_1 {
// public static void main3(String[] args) {
// Dog dog = new Dog("旺财",18,"green");
// Animal animal = dog ;
// animal.eat ();
// }
//}
在fun这个静态方法中,我们通过传参的方式实现了向上转型,这时候我们的animal就有了子类的特征也就是bird和dog类,这时候我们在fun静态方法中调用animal进行向上转型后的eat方法()这时候的运行结果会是
这样就引出了多态!(这个过程是动态绑定在2.1.2.1中有讲解)
可以看到我们调用eat方法出现了两个结果这两个结果是dog子类和bird中的eat方法!!
同一个动作却造成了不同的结果,理解为对你对不同的人会有不同的相处态度!
3.2运用返回值的方式向上转型
代码如下
public static Animal fun_2(){
//第三种转型方式 通过返回值向上转型
return new Bird("布拉",1) ;
}
public static void main(String[] args) {
Bird bird = new Bird("布谷",18);//子类
Animal animal_2 = bird ;//向上转型第一种方式直接赋值
fun_2().eat();
}
}
3.3多态产生条件
1.发生向上转型(在向上转型的过程中会发生动态绑定)。
2.发生重写(2.1.2.2有讲解)
3.必须在继承体系下。
4.重写(覆盖,覆写)详细讲解(override)
4.1重写的注意事项和override关键字
1.重写是子类对父类非静态,非private,非final修饰,非构造方法的实现过程进行重写编写,返回值和形参都不能改变,核心重写!
(被final修饰的不能被重写,被他修饰就是密封了)。
2.@override关键字
帮助你检测这个类中的方法是否已经被重写。
3.被static修饰的方法不能被重写。
4.重写方法的权限
(1)子类重写父类方法的时候
子类权限要大于等于父类的权限
(2)权限大小顺序:public > private >default >private
5.被private修饰的类和方法是不能重写的!!!!!
因为被private修饰的这个方法是只能在这个类的范围内进行使用!!
4.2 重写
4.2.1 重写的规则
1.子类重写父类方法的时候,一般必须于父类方法原型一直:返回值类型 方法名 (参数列表)要完全一致
2.被重写的方法返回值类型不同,但是必须是具有父子一般的关系
3.父类的访问权限一定要大于等于子类的访问权限。
4.父类不能被static private关键字修饰。
5.可以使用@overri注释显示指定,有了这个注释我们就可以进行一些合法性的校验,例如不小心将方法的名字拼错,那么编译器就会报错。
6.重写的方法名构成父子类关系也叫重写
(1)代码(animal是Dog的父类)
(2)被重写的方法一定要有父子类关系。
public Animal eat_1(){
System.out.println("想吃饭");
return null;
}
public Dog eat_1(){
System.out.println("大口吃");
return null ;
}
4.2.2重写和重载的区别
1.重写(override)和重载(overload)是面向对象编程中的两个重要概念。
2.重写是指在子类中重新定义父类的方法,以覆盖父类的实现。重写要求子类方法的名称、参数列表和返回类型与父类方法相同,以确保使用时可以通过子类引用调用父类方法时执行子类的实现。重写可以用于多态的实现,即通过父类引用调用子类对象的方法。
3.重载是指在同一个类中定义多个方法,方法名称相同但参数列表不同。重载可以有不同的参数类型、参数顺序或参数个数。当使用重载方法时,编译器会根据传入的参数进行匹配,选择最合适的方法进行调用。重载可以提供更灵活的方法调用方式,方便程序员根据实际需求选择不同输入参数的方法。
4.总结而言,重写是指在继承关系中,子类重新定义父类的方法;而重载是指在一个类中定义多个名称相同但参数列表不同的方法。
4.2.3重写的设计规则
1.类进来不要修改新建一个类来进行重写
5.1静态绑定
1.称之为前期绑定,即在编译时,更具用户传递的实参类型确定具体调用哪个方法,例如函数的重载。
6.向下转型详细讲解
6.1 向下转型定义
1.当一个子类继承自父类时,通过向上转型可以将子类的对象以父类的形式存储。
2.相当于把bird这个类放到了父类中然后这个bird变成了父类,实例化对象的时候,我通过这个调用了父类中新增的bird方法或者bird成员变量。
3.如果没有向下转型就不能使父类调用子类中的方法
4.代码
我们先通过向下转型使得父类可以访问子类中的方法
记住我们开始讲的多态是通过向上转型然后对子类和父类的方法进行重写再调用的相同的方法而不是使用了子类的方法记住这两个的区别!!!!
public class Frank{
public static void main(String[] args) {
Animal animal_1 = new Dog("旺财",18,"green");//子类
Animal animal_2 = new Bird("布谷",18);//子类
// animal_1.eat();//向上转型
// animal_1.fly();//会报错,这个方法没有重写,所以这个是独属于子类的方法父类访问不了
Bird bird = (Bird) animal_2;
bird.fly;
Bird bird_2 = (Bird) animal_1;//这个是骗过了编译器,运行会报错,因为在dog这个子类中是没有fly方法的
}
}
5.所以上面代码可以看出向下转型是一个比较危险的操作,我们一般向下转型的时候要对其进行判断(记得不是所有的动物都是鸟结合上面代码)
6.为了避免6.1.2中的错误我们引入了instanceof这个关键词,这个关键字结合if语句可以帮助我们向下转型的安全性!代码如下
public class Frank{
public static void main(String[] args) {
Animal animal_1 = new Dog("旺财",18,"green");//子类
Animal animal_2 = new Bird("布谷",18);//子类
animal_1.eat();//向上转型
// animal_1.fly();会报错
// Bird bird = (Bird) animal_2;
//
// Bird bird_2 = (Bird) animal_1;
if (animal_1 instanceof Bird){
Bird bird_2 = (Bird) animal_2;
bird_2.fly();
}else {
System.out.println("这个动物不是鸟");
}
}
}
7.其他注意事项
1.父类的构造方法中,如果调用子类和父类同名的方法也会发生动态绑定。意味着构造方法内也会发生动态绑定。
2.注意,在构造方法中不要调用重写的方法(一般情况我们的构造方法都是用来初始化成员变量的)。
3.运行的化先是父类的构造父类的实例再子类的构造再子类的实例。
8.多态的缺点
1.在java中的多态不能够多继承也就是有多个父类(java用接口解决这个问题下一篇文章会详细讲解)
2.可以更好的使得代码有复用性。