10 多态 内部类
对象的多态性:
class 动物
{
}
class 猫 extends 动物
{
}
class 狗 extends 动物
{
}
猫 x = new 猫();
动物 x = new 猫();//一个对象,两种形态.
猫这类事物既具备了猫的形态,又具备着动物的形态,
这就是对象的多态性.
简单说:就是一个对象对应着不同类型.
多态在代码中的体现:
父类或者接口的引用指向其子类的对象.
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容,
abstract class Animal { abstract void eat(); } class Dog extends Animal { void eat() { System.out.println("啃骨头"); } void lookHome() { System.out.println("看家"); } } class Cat extends Animal { void eat() { System.out.println("吃鱼"); } void catchMouse() { System.out.println("抓老鼠"); } } class Pig extends Animal { void eat() { System.out.println("饲料"); } void gondDi() { System.out.println("拱地"); } } class Demo { public static void main(String[] args) { method(new Dog()); method(new Cat()); method(new Pig()); } /* public static void method(Cat c) { c.eat(); } public static void method(Dog d) { d.eat(); } */ public static void method(Animal a) { a.eat(); } }
多态的弊端:
前期定义的内容不能去调用后期子类的特有内容.
多态的前提:
1.必须有关系,继承,实现.
2.要有覆盖.
class Demo { public static void main(String[] args) { Animal a = new Cat();//自动类型提升,猫对象提升为动物类型. //但是特有功能无法访问. //作用就是限制对特有功能的访问. a.eat(); //如果还想用具体动物猫的特有功能; //你可以将该对象进行向下转型. Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法. c.eat(); c.catchMouse(); } /* public static void method(Cat c) { c.eat(); } public static void method(Dog d) { d.eat(); } */ public static void method(Animal a) { a.eat(); } }
注意:对于转型,自始至终都是子类对象在做着类型的变化.
Animal a =new Dog();
Cat c = (Cat) a;//ClassCastException
/* 毕老师和毕姥爷的故事(不会被和谐) */ class 毕姥爷 { void 讲课() { System.out.println("管理"); } void 钓鱼() { System.out.println("钓鱼"); } } class 毕老师 extends 毕姥爷 { void 讲课() { System.out.println("Java"); } void 看电影() { System.out.println("看电影"); } } class Demo { public static void main(String[] args) { 毕姥爷 x = new 毕老师(); x.讲课();//java x.钓鱼(); 毕老师 y = (毕老师)x; y.看电影(); } }
向上转型为了提升扩展性,限制子类的特有功能.
向下转型为了使用子类的特有功能.
abstract class Animal { abstract void eat(); } class Cat extends Animal { void eat() { System.out.println("鱼"); } void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { void eat() { System.out.println("啃骨头"); } void lookHome() { System.out.println("看家"); } } class Demo { public static void main(String[] args) { method(new Cat()); method(new Dog()); } public static void method(Animal a) { a.eat(); //a instanceof Animal -->true if(a instanceof Cat) //instanceof:用于判断对象的具体 { //类型,只能用于引用数据类型判断 Cat c = (Cat)a; c.catchMouse(); } else if(a instanceof Dog) { Dog d = (Dog)a; d.lookHome(); } } }
多态时成员的特点:
class Fu { int num = 3; //如果把这行注释,下面会报错. } class Zi extends Fu { int num =4; } class Demo { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num);//3 } } //变量不能覆盖,只有方法才会覆盖
1.成员变量:
编译时:参考引用型变量所属的类中是否有调用的成员变量,有,编译通过,没有,编译失败.
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量.
简单说:编译和运行都参考等号的左边(父类的).
2.成员函数(非静态):
class Fu { void show() { System.out.println("fu show"); } } class Zi extends Fu { void show() { System.out.println("zi show"); } } class Demo { public static void main(String[] args) { Fu f = new Zi(); f.show(); } }
如果子类没有show()方法,才会去父类调用show();
编译时:参考引用型变量所属的类中是否有调用的函数,有,编译通过,没有,编译失败.
运行时:参考的是对象所属的类中是否有调用的函数.
简单说:编译看左边,运行看右边.
3.静态函数:
简单说:编译和运行都看左边.
静态函数放在方法区中,不会覆盖父类的方法,
直接去找父类的了.因为静态不涉及对象也可以直接用类名调用方法,
故静态其实可当做不考虑多态.
内部类:
把一个类定义在另一个类的里面(内置类,嵌套类);
/* 内部类访问特点: 1.内部类可以直接访问外部类中的成员. 2.外部类要访问内部类,必须建立内部类的对象. */ class Outer { private int num=3; class Inner //内部类 { void show() { System.out.println("show run..."+num); } } public void method() { Inner in = new Inner(); in.show(); } }
//直接访问外部类中的内部类中的成员.
Outer.Inner in = new Outer().new Inner();
一般用于类的设计,
分析事物时,发现该事物的描述中还有事物,而且这个事物还在访问被描述
事物的内容,这时就是还有的事物定义成内部类来描述.
如果内部类是静态的,相当于一个外部类
class Outer { private static int num=3; static class Inner //内部类 { void show() { System.out.println("show run..."+num); } } public void method() { Inner in = new Inner(); in.show(); } } class Demo { public static void main(String[] args) { Outer.Inner in = new Outer.Inner(); in.show(); } }
如果内部类是静态的,成员是静态的.
class Outer { private static int num=3; static class Inner //内部类 { void show() { System.out.println("show run..."+num); } static void function()//如果内部类中定义了静态成员,该内部类也必须是静态的 { System.out.println("function run"+num); } } public void method() { Inner in = new Inner(); in.show(); } } class Demo { public static void main(String[] args) { Outer.Inner.function(); } }
为什么内部类能直接访问外部类中的成员呢?
那是因为内部类持有了外部类的引用,外部类名.this.
class Outer { int num =3; class Inner { int num=4; void show() { int num=5; System.out.println(Outer.this.num); //num-->4 //this.num-->5; //Outer.this.num-->3; } } void method() { new Inner().show(); } } class Demo { public static void main(String[] args) { new Outer().method(); } }
内部类在局部位置上只能访问局部中被final修饰的局部变量.
(自己测试的可以访问,网上说1.8以后的新特性?)
/* 内部类可以存放在局部位置上. 内部类在局部位置上只能访问局部中被final修饰的 局部变量. */ class Outer { int num=3; Object method() { final int x= 11; class Inner { void show() { System.out.println("show..."+x); } } Object in = new Inner(); return in;//0x0045 } } class Demo { public static void main(String[] args) { Outer out = new Outer() Object obj = out.method(); //方法一出栈x就没了, } }
匿名内部类:
就是内部类的简写格式.
必须有前提:
内部类必须继承或实现一个外部类或者接口.
匿名内部类:其实就是一个匿名子类对象.
格式:new 父类or接口(){子类内容}
abstract class Dm { abstract void show(); } class Outer { int num=4; public void method() { new Dm() { void show() { System.out.println("show..."+num); } void haha() { } }.show(); } } class Demo { public static void main(String[] args) { new Outer().method(); } }
通常使用的场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个.可以用匿名内部类作为实际参数进行传递.
interface Inter { void show1(); void show2(); } class Outer { /* class Inner implements Inter { public void show1() { } public void show2() { } } public void method() { Inner in = new Inner(); in.show1(); in.show2(); }*/ public void method() { Inter in = new Inter() { public void show1() { } public void show2() { } }; in.show1(); in.show2(); } } class Demo { public static void main(String[] args) { new Outer().method(); //show(new InterImpl()); show(new Inter() { public void show1(){} public void show2(){} }); } public static void show(Inter in) { in.show1(); in.show2(); } } /* class InterImpl implements Inter { } */
class Outer { void method() { Object obj = new Object() { public void show() { System.out.println("show run"); } } obj.show();//出错 //因为匿名函数类这个子类对象被向上转型为Object //这样就不能再使用子类的特有方法了 //这其实是多态和匿名函数的结合. } }
class Fu { Fu() { show(); } void show() { System.out.println("hehe"); } } class Zi extends Fu { int num = 9; Zi() { //super(); //在这里进行显示初始化 System.out.println("zi constructor..."+num); } void show() { System.out.println("show run"+num); } } class Demo { public static void main(String[] args) { new Zi(); //show run 0; //zi constructor 9 } }