多态、内部类、匿名内部类
来源:互联网 发布:ubuntu安装到u盘上 编辑:程序博客网 时间:2024/06/02 21:21
一、多态
1.定义:可以理解为事物存在的多种体现形态.
人:男人,女人;
动物:猫,狗;
猫 x= new 猫();类与对象的关系;
动物 x = new 猫();类与类产生关系以后,原来实体还可以具备其他类型,对象的另一种形态;即多态性;
在java中我们强调对象的多态性,事实上,函数也有多态性,比如重载和覆盖就是函数的多态性体现;同一个函数名称在一个类中有多个,也是多态;
简单说:就是一个对象对应着不同类型
2.多态的体现;
父类的引用指向了自己子类的对象;
父类的引用也可以接受自己的子类对象;
3.多态的前提;
必须是类与类之间有关系,要么继承,要么实现;
存在覆盖;
4.多态的好处;
(1)多态的出现大大的提高了程序的扩展性;
(2)前期的代码可以使用后期的内容
5.多态的应用;
6.多态的弊端:
(1) 提高了扩展性,但是只能使用父类的引用访问父类中的成员
(2)前期定义的内容不能使用(调用)后期子类的特有内容,因为自始至终只能是子类在变化,父类只是引用指向了子类
举例:
package day02;abstract class Animal{// 所有动物都吃,强迫子类都是实现这个方法abstract void eat();}class Cat extends Animal{//复写父类的抽象方法public void eat(){System.out.println("吃鱼");}//子类特有方法 捉老鼠public void catchMouse(){System.out.println("抓老鼠");}}class Dog extends Animal{////复写父类的抽象方法public void eat(){System.out.println("吃骨头");}//子类特有方法 看家public void kanjia(){System.out.println("看家");}}class Pig extends Animal{public void eat(){System.out.println("饲料");}public void gongDi(){System.out.println("拱地");}}public class DuotaiDemo{public static void main(String[] args){/*Cat c = new eat();c.eat();function(new Cat());functin(new Dog());Animal c = new Cat();c.eat();*/Animal a = new Cat();/*自动类型提升,猫对象提升了动物类型。但是特有功能无法访问。 作用就是限制对特有功能的访问。 专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。*/a.eat();//如果想要调用猫的特有方法时,如何操作?//强制将父类的引用,转成子类类型;向下转型。Cat c = (Cat)a;c.catchMouse();/*加入动物可以实例化对象,不允许出现下面的情况,将父类对象转成子类类型;我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升;多条自始至终都是子类对象在作者变化;*//*Animal a = new Animal();Cat c = (Cat)a*//*毕姥爷 x = new 毕老师();x.讲课();毕老师 y = (毕老师)x;y.看电影();*/function(new Cat());function(new Dog());}//定义一个方法专门对子类对象类型进行判断,进而访问子类特有功能public static void function(Animal a)//Animal a = new Cat();{a.eat();if(a instanceof Cat){Cat c = (Cat)a;c.catchMouse();}else if(a instanceof Dog){Dog c = (Dog)a;c.kanjia();}}//这样定义比较麻烦,抽象成一个特有函数就可以了/*public static void function(Cat c)//Cat c = new Cat();{c.eat();}public static void function(Dog d){d.eat();}public static void function(Pig p){p.eat();}*/}
运行结果:
7.多态时各组成的变化
(1)成员变量
无论编译和运行,都参考左边 原因:参考的是引用型变量所属的类
(2)成员函数(非静态)。
编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
原因:成员函数存在覆盖特性。
(3)静态函数。
无论编译和运行,都参考左边;
原因:当类一被加载,静态函数就随类绑定在了内存中。此时,不需要创建对象,就可以使用类名直接调用。同时,父类中的静态成员函数一般是不被复写的。
package day02;class Fu{int num = 3;void show(){System.out.println("fu show");}static void method(){System.out.println("fu static method");}}class Zi extends Fu{int num = 4;void show(){System.out.println("zi show");}static void method(){System.out.println("zi static method");}}public class DuoTaiDemo2{public static void main(String[] args){System.out.println("调用静态方法时");Fu.method();Zi.method();System.out.println("调用非静态方法时");Fu f = new Zi();//f.show();System.out.println("调用成员变量时时");System.out.println("多态时:"+f.num);Zi z = new Zi();System.out.println("子类对象调用时:"+z.num);}}
运行结果:
8.多态应用
需求:
电脑运行实例:
电脑运行基于主板。
接口的出现提高了功能扩展性,接口的引用指向子类对象也提高了程序的扩展性;接口降低了耦合,提高了功能扩展性,提供了规则;
package day02;/*接口的出现提高了功能扩展性,接口的引用指向子类对象也提高了程序的扩展性;接口降低了耦合,提高了功能扩展性,提供了规则;*/// 接口PCIinterface PCI{void open();void close();}//网卡实现接口class NetCard implements PCI{public void open(){System.out.println("NetCard_open");}public void close(){System.out.println("NetCard_close");}}//声卡实现接口class SoundCard implements PCI{public void open(){System.out.println("SoundCard_open");}public void close(){System.out.println("SoundCard_close");}}class Mainboard{//电脑运行public static void run(){System.out.println("Mainboard_run");}//使用扩展功能public static void usePCI(PCI p)//PCI p = new NetCard()//接口型引用指向自己的子类对象。{if(!(p==null)){p.open();p.close();}}}public class DuoTaiDemo3{public static void main(String[] args) {Mainboard m =new Mainboard();//电脑运行m.run();//电脑上网m.usePCI(new NetCard());//电脑听歌m.usePCI(new SoundCard());}}
运行结果:
二、内部类
内部类的访问规则:
1.内部类可以直接访问外部类的成员,包括私有;
之所以可以直接访问外部类中的成员 ,是因为内部类中有一个 外部类的引用;格式:外部类名.this
2.外部类要访问内部类,必须建立内部类对象;
3.访问格式:
(1).当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。
格式
外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inner in = new outer().new Inner();
(2).当内部类在成员位置上,就可以被成员修饰符所修饰。
比如:private:将内部类在外部类中进行封装。
static:内部类就具备static的特性。
当内部类被static修饰后,只能直接访问外部类中static的成员,出现了访问局限;
在外部其他类中,如何访问内部类非静态成员呢?
new Outer.Inner().function();
在外部其他类中,如何访问内部类静态成员呢?
Outer.Inner().function();
注意:当内部类中定义了静态成员,该内部类必须是静态的;
当外部类中的静态成员访问内部类时,内部类也必须是static的
举例:
package day02;class Outer{int x=2;/** 当内部类中定义了静态成员时,该内部类必须是static的。* 静态方法中不可以出现this,因为静态优先于对象存在* static class Inner{int x=3; static void method(){int x=1;System.out.println(x);}}*/ class Inner{int x=3; void method(){int x=1;System.out.println(x);}}/** 当外部类中的静态方法访问内部类时,内部类也必须是static的。* 静态方法中不可以出现this,因为静态优先于对象存在*/static class Inner2{void show(){System.out.println("inner2 show");}}public static void function(){new Inner2().show();}}public class InnerDemo {public static void main(String[] args) { /*Outer.Inner in=new Outer().new Inner(); in.method();*//*当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。 格式:外部类名.内部类名 变量名 =外部类对象.内部类对象;*/ Outer.Inner in=new Outer().new Inner();in.method();new Outer().function();}}
运行结果:1
inner2 show
2、内部类定义在局部
内部类定义在外部类中的某个方法中,创建了这个类型的对象时,且仅使用了一次,那么可在这个方法中定义局部类。
1)不可以被成员修饰符修饰。如public、private、static等修饰符修饰。它的作用域被限定在了声明这个局部类的代码块中
2)可以直接访问外部类中的成员,因为还持有外部类中的引用。
注意:内部类不可以访问它所在的局部中非最终变量。只能访问被final修饰的局部变量。
举例:
package day02;class Outer3 {int x = 3;void method(final int a) {final int i=2; //内部类定义在局部class Inner {int x = 4;void show() {System.out.println(a);}}//要想访问非静态show必须有对象;new Inner().show();}}public class InnerDemo3 {public static void main(String[] args) {Outer3 out = new Outer3();out.method(7);out.method(9);//方法的参数是局部变量,局部变量存放在栈中,out.method(7)结束时,局部变量出栈,在执行下一句;但是当final局部变量入栈后,是不能操作的,}}
运行结果: 7
9
注意:
方法中的内部类能不能访问方法中的局部变量,为什么?
内部类的生命周期和方法中的局部变量是不一样的,内部类是也是一个类,是存储在堆中,也只有当对该类的引用消失时,内部类才会消亡。而方法的局部变量是存储在堆栈中的,当调用结束时就会退栈,即在内存中这个属性就消失了。也就是说,内部类的生命周期超过了方法中局部变量的生命周期,内部类可能会调用到已经消失的属性,因此内部类不能访问方法中的局部变量。
解决方法就是在局部变量前加修饰符final
编译程序的实现方法:将所有的局部内部类对象要访问的final型局部变量,都拷贝成为该内部类对象中的一个数据成员。这样,即使栈中局部变量(含final)已死亡,但由于它是final,其值永不变,因而局部内部类对象在变量死亡后,照样可以访问final型局部变量。
3.内部类什么么时候定义?
当描述事物时,事物的内部事物还有事物,该事物用内部类描述。
因为内部类事物在使用外部类事物的内容;
4.匿名内部类:
(1).匿名内部类其实就是内部类的简写格式。
如把下面的代码改成匿名内部类
package day02;abstract class AbsDemo{abstract void show();}class Outer4{int x=3;class Inner extends AbsDemo{void show() {System.out.println("show:"+x);}}public void function(){new Inner().show();}}public class InnerDemo5 {public static void main(String[] args) {new Outer4().function();}}
更改成匿名内部类的形式:
package day02;abstract class AbsDemo{abstract void show();}class Outer4{int x=3;public void function(){//new Inner().show();new AbsDemo(){void show(){System.out.println("show:"+x);}}.show();}}public class InnerDemo5 {public static void main(String[] args) {new Outer4().function();}}
(2).定义匿名内部类的前提:
内部类必须是继承一个类或者接口;
内部类还可以抽象,比如人有心脏,心脏想当于内部类,其他动物也有心脏,就把心脏抽象出来
(3).匿名内部类的格式: new 父类或者接口(){定义子类的内容}
(4).其实匿名内部类(简化书写,覆盖方法)就是一个匿名子类对象;而且这个对象有点胖
(就是内部类带创建子类对象)
(5).匿名内部类中定义的方法最好不要超过三个;
面试题
1.补足代码
package day02;interface Inter {void method();}class Test {//补足代码/*分析:Test是类名,类名调用函数,说明function是static, * 调用function的结果又调用一个非静态方法,说明方法返回的是一个 * 对象,而且是Inter类型的对象,因为只有他可以调用method方法*/static Inter function(){return new Inter(){public void method(){System.out.println("method hahha" );}};}}public class InnerDemo4 {public static void main(String[] args) {Test.function().method();}}
2.如果没有写父类或者接口类,能够用匿名内部类吗?
可以,父类可以Object;
- 多态、内部类、匿名内部类
- day10_java多态+内部类+匿名内部类
- javaseday09(多态,内部类,匿名内部类)
- 内部类、匿名内部类
- 内部类、匿名内部类
- 内部类,匿名内部类
- 内部类(匿名内部类)
- 内部类 ---匿名内部类
- 内部类,匿名内部类
- 匿名类、内部类、匿名内部类
- 匿名类、内部类、匿名内部类
- 匿名类、内部类、匿名内部类
- 匿名类,内部类,匿名内部类
- 匿名内部类,回调...
- 关于匿名内部类
- 匿名内部类
- JAVA匿名内部类
- 返回匿名内部类
- C,C++,VC判断当前操作系统是那种语言 GetSystemDefaultLangID()
- .net string unicode 转换
- Unable to compile class for JSP JSP不能编译
- Maven3学习总结-环境搭建
- 完整详解GCD系列(一)dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f
- 多态、内部类、匿名内部类
- 多路分发-枚举类型
- 数组指针操作元素
- ping命令TTL的意思
- 坐标系
- 九度oj-剑指offer-题目1510:替换空格
- C++ builder系列之------#pragma详细解释
- 微软VS2015下载:开发Win10/Linux/iOS多平台软件
- 采用ajax提交POST数据的例子