:::tips
父类引用指向子类对象,则称为向上转型(upcasting)一般称为自动类型转换
子类引用指向父类对象,称为向下转型(downcasting)一般用于子类中特有的方法,才用下转型这个父类对象是子类向上转型而来,则安全,反之不安全,避免不安全向下转型的方法是先用isntanceof运算符判断向下转型的对象是不是向下转型的目标对象。
个人助记方法: 将父类对象赋值给子类引用,那么是往下走,那么就是向下转型;那么反之,将子类对象赋值给父类引用,那么就是向上走,就是向上转型。
:::
定义三个类:Animals 类、NiuMa 类、A 类:
class Animals{ //Animals类,作为父类
public void eat1(){
System.out.println("几乎都是肉食动物");
}
}
class NiuMa extends Animals{ //NiuMa类:作为子类
public void eat2(){
System.out.println("杂食动物");
}
public void sleep(){
System.out.println("都要睡觉。");
}
}
class A{ //A类:作为参数和返回类型要用到。
public void func1(Animals animals){
animals.eat1();
System.out.println("父类形参");
}
public void func3(NiuMa niuMa){
niuMa.sleep();
System.out.println("子类形参");
}
public NiuMa func2(){
System.out.println("此时返回值类型与public后的引用类型一致");
return new NiuMa();
}
public Animals func4(){
System.out.println("此时返回值类型与public后的引用类型不一致!");
return new NiuMa();
}
public Animals func5(){
System.out.println("此时返回值类型与public后的引用类型一致");
return new Animals();
}
public NiuMa func6(){
System.out.println("此时返回值类型与public后的引用类型不一致!");
return (NiuMa)new Animals();
}
}
Animals 类:作为父类,具有公共方法 eat1() 。
NiuMa 类:作为子类,具有子类独有方法 sleep() 。
A 类:作为其他类,要借助该类实现参数类型和返回值类型的转型。
向上转型:
一、直接赋值法:
class Text{
public static void main(String[] args) {
Animals people1 = new NiuMa();
people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调用重写后的。
}
}
父类引用子类对象:Fu dui1 = new Zi();
可用该对象调用继承后公共部分的方法,若该方法被子类重写,则调用重写后的方法。
二、作为参数法:
class Text{
public static void main(String[] args) {
NiuMa niuma1 = new NiuMa();
A a1 = new A();
a1.func1(niuma1);
}
}
形参为父类,实参为子类。
在方法中实现向上转型,即在 func 方法中已经完成转型任务,完成调用其他方法的实现。
三、作为返回值类型法:
class Text{
public static void main(String[] args) {
//返回值类型法向上转型:
//利用func2():public后面为子类,返回值类型为子类
A a1 = new A();
//用引用类型直接接收:
NiuMa niuma1 = a1.func2();//正常接收。
Animals animals1 = a1.func2();//发生了向上转型
//new对象进行接收:
NiuMa niuma2 = new NiuMa();
Animals animals2 = new Animals();
niuma2 = a1.func2(); //正常接收
animals2 = a1.func2();//发生了向上转型
//利用finc4():public后面为父类,返回值类型为子类
A a2 = new A();
//用引用类型直接接收:
NiuMa niuma3 = (NiuMa) a2.func4();//相当于发生了一次向下转型
Animals animals3 = a2.func4();//正常接收。
//new对象进行接收:
NiuMa niuma4 = new NiuMa();
Animals animals4 = new Animals();
niuma4 = (NiuMa) a2.func4(); //相当于又发生了一次向下转型。
animals4 = a2.func4();//正常接收
//结论:当public后面为父类,返回值为子类时,实际返回值为父类类型。
}
}
此块代码主要看利用 func2() 的,因为返回值类型参考的是 public 后为父类还是子类。
父类引用,接收返回类型为子类的方法,实现向上转型。
向下转型:
class Text{
public static void main(String[] args) {
Animals people2 = new NiuMa();//要先发生一次向上转型
NiuMa people3 = (NiuMa) people2; //将people2强制类型转换成NiuMa类,用people3接收
people1.eat1();
people3.sleep();
}
}
要先发生向上转换:Fu dui2 = new Zi();
向下转换:Zi dui3 = (ZI) dui3;
二、作为参数法:
class Text{
public static void main(String[] args) {
Animals animals1 = new NiuMa();//先发生强制类型转换
A a2 = new A();
a2.func3((NiuMa) animals1);
}
}
形参为子类,实参为父类。
在方法中实现向下转型,即在 func 方法中已经完成转型任务,完成调用其他方法的实现。
传参时要进行强制类型转换。
三、作为返回值类型法:
public Text{
public static void main(String[] args) {
//返回值类型法向下转型:
//利用func5():public后面为父类,返回值类型为父类。
A a1 = new A();
//用引用类型直接接收:
NiuMa niuma1 = (NiuMa) a1.func5();//发生了向下转型
Animals animals1 = a1.func5();//正常接收
//new对象进行接收:
NiuMa niuma2 = new NiuMa();
Animals animals2 = new Animals();
niuma2 = (NiuMa) a1.func5();//发生了向下转型
animals2 = a1.func5();//正常接收
//利用func6():public后面为子类,返回值类型为父类。
A a2 = new A();
//用引用类型直接接收:
NiuMa niuma3 = a2.func6();//正常接收
Animals animals3 = a2.func6();//相当于向上转型
//new对象进行接收:
NiuMa niuma4 = new NiuMa();
Animals animals4 = new Animals();
niuma4 = a2.func6(); //正常接收
animals4 = a2.func6();//相当于向上转型
//小结:当public后面为子类,返回值类型为父类的时候,返回值类型为子类。
}
}
此块代码主要看利用 func5() 的,因为返回值类型参考的是 public 后为父类还是子类。
子类引用,接收返回类型为父类的方法,实现向上转型,要注意进行强制类型转换。
注意点:
一、以下为错误代码:
class Text{
public static void main(String[] args) {
//⭐错误代码:
Animals people = new Animals();
A a = new A();
a.func3(people);
//形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
}
}
此时代码直接会报错
因为该代码与是否发生向上转型或向下转型无关。而向下转型的本质是已经发生过向上转型,通过强制类型转换从而回来罢了,但是该处错误直接类型不匹配。
由此我们也可以得出一个结论:
形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
二、关于返回值类型同方法上下不匹配:
在 func4() 与 func6() 中,public 后的引用类型与返回值类型不匹配,但在主函数中用某引用类型去接收该返回值的时候,一定要用 pubic 后的引用类型。
三、为什么会发生向上转型和向下转型?
向上转型是为了调用父类中的方法,向下转型是为了使用完后转回子类,以此才能调用父类中没有的方法。
总结:
向上转型:自动转型,父类引用子类对象。for调父类方法。
向下转型:强制类型转换,本质上就是子类已经发生了向上转型,再次转回来而已。for调父类中没有的子类方法。
以下为整合代码:
放入 Idea 里分别把 main 方法放开运行理解更深刻:
class Animals{
public void eat1(){
System.out.println("几乎都是肉食动物");
}
}
class NiuMa extends Animals{
public void eat2(){
System.out.println("杂食动物");
}
public void sleep(){
System.out.println("都要睡觉。");
}
}
class A{
public void func1(Animals animals){
animals.eat1();
System.out.println("父类形参");
}
public void func3(NiuMa niuMa){
niuMa.sleep();
System.out.println("子类形参");
}
public NiuMa func2(){
System.out.println("此时返回值类型与public后的引用类型一致");
return new NiuMa();
}
public Animals func4(){
System.out.println("此时返回值类型与public后的引用类型不一致!");
return new NiuMa();
}
public Animals func5(){
System.out.println("此时返回值类型与public后的引用类型一致");
return new Animals();
}
public NiuMa func6(){
System.out.println("此时返回值类型与public后的引用类型不一致!");
return (NiuMa)new Animals();
}
}
public class ZhuAn {
public static void main4(String[] args) {//主要为向下转型。
//返回值类型法向下转型:
//利用func5():public后面为父类,返回值类型为父类。
A a1 = new A();
//用引用类型直接接收:
NiuMa niuma1 = (NiuMa) a1.func5();//发生了向下转型
Animals animals1 = a1.func5();//正常接收
//new对象进行接收:
NiuMa niuma2 = new NiuMa();
Animals animals2 = new Animals();
niuma2 = (NiuMa) a1.func5();//发生了向下转型
animals2 = a1.func5();//正常接收
//利用func6():public后面为子类,返回值类型为父类。
A a2 = new A();
//用引用类型直接接收:
NiuMa niuma3 = a2.func6();//正常接收
Animals animals3 = a2.func6();//相当于向上转型
//new对象进行接收:
NiuMa niuma4 = new NiuMa();
Animals animals4 = new Animals();
niuma4 = a2.func6(); //正常接收
animals4 = a2.func6();//相当于向上转型
//小结:当public后面为子类,返回值类型为父类的时候,返回值类型为子类。
}
public static void main3(String[] args) {//主要为向上转型:
//返回值类型法向上转型:
//利用func2():public后面为子类,返回值类型为子类
A a1 = new A();
//用引用类型直接接收:
NiuMa niuma1 = a1.func2();//正常接收。
Animals animals1 = a1.func2();//发生了向上转型
//new对象进行接收:
NiuMa niuma2 = new NiuMa();
Animals animals2 = new Animals();
niuma2 = a1.func2(); //正常接收
animals2 = a1.func2();//发生了向上转型
//利用finc4():public后面为父类,返回值类型为子类
A a2 = new A();
//用引用类型直接接收:
NiuMa niuma3 = (NiuMa) a2.func4();//相当于发生了一次向下转型
Animals animals3 = a2.func4();//正常接收。
//new对象进行接收:
NiuMa niuma4 = new NiuMa();
Animals animals4 = new Animals();
niuma4 = (NiuMa) a2.func4(); //相当于又发生了一次向下转型。
animals4 = a2.func4();//正常接收
//结论:当public后面为父类,返回值为子类时,实际返回值为父类类型。
}
public static void main2(String[] args) {
//传参法:在方法内实现向上转型,在方法内调用方法。
//向上转型:
NiuMa niuma1 = new NiuMa();
A a1 = new A();
a1.func1(niuma1);
//向下转型:
Animals animals1 = new NiuMa();//先发生强制类型转换
A a2 = new A();
a2.func3((NiuMa) animals1);
//⭐错误代码:
//Animals people = new Animals();
//A a = new A();
//a.func3(people);
//形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
}
public static void main1(String[] args) {
//直接赋值法
//向上转型
Animals people1 = new NiuMa();
people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调用重写后的。
//向下转型
Animals people2 = new NiuMa();//要先发生一次向上转型
NiuMa people3 = (NiuMa) people2; //将people2强制类型转换成NiuMa类,用people3接收
people1.eat1();
people3.sleep();
}
}