黑马程序员--java基础复习之多态与Object及匿名内部类
2015-03-19 22:01
597 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多态
定义:某一类事物的多种存在形态
例如:动物中的猫、狗。猫这个对象对应的类型是猫类型,如:猫 x = new猫(); 同时猫也是动物中的一种,也可以把猫称为动物。
动物 y = new 猫(); 那么动物就是猫和狗具体事物中抽取出来的父类型。父类型引用指向了子类对象。
多态:可以理解为事物存在的多种体现形态
1、多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2、多态的前提
必须是类与类之间有关系。要么继承,多么实现
通常还有一个前提:存在覆盖
3、多态的好处
多态的出现大大的提高程序的扩展性
4、多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员
如下代码:
这代码就是多态的体现,假设子类Cat中有特有的抓老鼠功能,父类型的 a就不能直接调用。这上面的代码中,可以理解为Cat类型提升了,向上转型。如:
注:如果父类可以创建对象,如:Animal a = new Animal(); 此时,就不能向下转型了,Cat c = (Cat)a; 这样的代码就变得不容许,编译时会报错。所以千万不能出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。多态至始至终都是子类对象在做着变化。
看一个例子:
下面也是一个多态的小应用,其分为三个部分
1、定义好工具类,即将共同行为封装在一个类中。
2、对类型进行抽取,---->多态的产生。
3、操作同一父类型,对其中的子类型均可操作
如下:
1、在多态中成员函数(非静态)的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
如下:
简单总结:成员函数在多态调用时,编译看左边,运行看右边
2、在多态中成员变量的特点:无论编译或运行,都参考左边(引用型变量所属的类)
如下面代码:
3、在多态中,静态成员函数的特点(在开发中很少见,因为很少会去复写静态方法)
无论编译和运行,都参考左边 如下:
Object类
类Object是类层次结构的根类。每个类都使用Object作为超
类。
Object :是所有对象的直接或者间接父类,传说中的上帝
该类中定义的肯定是所有对象都具备的功能。
下面讲的就是Object中的常用的方法
equals
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。(其实比较的就是对象在内存中的地址值)
参数类型是Object ,这里也是用到了多态。
如下代码:
Object类中已经提供了对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义,只要沿袭父类Object中的功能,建立自己特有的比较内容即可。这就是覆
盖。如下:
结果:
内部类
内部类:将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)
访问特点:
A、内部类可以直接访问外部类中的成员,包括私有成员
之所以可以直接访问外部类中的成员,是因为外部类中持有了一个外部内的引用,格式 外部类名.this
B、而外部类要访问内部类中的成员必须要建立内部类的对象
如下代码:
再看下面一段代码:
结果:
从上述代码中可以得出:之所以可以直接访问外部类中的成员,是因为外部类中持有了一个外部内的引用,格式 外部类名.this
从上面的代码中可以看到内部类的访问格式
访问格式:
1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类对象。
格式:外部类名.内部类名 变量名=外部类对象.内部类对象
如 Outer.Inner in=new Outer().new Inner();
2、当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装
静态内部类
static:内部类就具备static 的特性。
当内部类被static 修饰后,只能直接访问外部类中的static成员。出现了访问局限。
如下代码片段:
因为内部类用static修饰后,就具备了static的特性。所以静态不能直接访问非静态
注意:当内部类中定义了静态成员,该内部类必须是静态的n
当外部类中的静态方法访问内部类时,内部类也必须是static的
如下代码段:
3、内部类定义在局部时:
1、不可以被成员修饰符修饰(static private)
2、可以直接访问外部类中的成员,因为还持有外部类中的引用。
但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量
用如下代码说明:
匿名内部类
1、匿名内部类其实就是内部类的简写格式。
2、定义匿名内部类的前提:内部类必须是继承一个类或者实现接口
3、匿名内部类的格式:new 父类或者接口(){定义子类的内容}
4、其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。
5、匿名内部类中定义的方法最好不要等于或超过3个
用一个例子来说明:
下面来看一个匿名内部类的题目:
再看另一个匿名内部类的题目:
完成:因为没有定义父类或接口,所以想到Object是所有类的直接或间接父类。
多态
定义:某一类事物的多种存在形态
例如:动物中的猫、狗。猫这个对象对应的类型是猫类型,如:猫 x = new猫(); 同时猫也是动物中的一种,也可以把猫称为动物。
动物 y = new 猫(); 那么动物就是猫和狗具体事物中抽取出来的父类型。父类型引用指向了子类对象。
多态:可以理解为事物存在的多种体现形态
1、多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2、多态的前提
必须是类与类之间有关系。要么继承,多么实现
通常还有一个前提:存在覆盖
3、多态的好处
多态的出现大大的提高程序的扩展性
4、多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员
如下代码:
abstract class Animal { abstract void eat(); //定义一个eat()的抽象方法,所以这个类也是一个抽象类 //其子类调用此类的时候,要对其抽象方法全部重写 } interface Catch { abstract void catchMou(); } //继承动物这个类 class Cat extends Animal implements Catch { void eat() { System.out.println("我是猫,我吃鱼"); } public void catchMou() //重写(覆盖)接口中的抽象类 { System.out.println("接口:抓老鼠抓老鼠抓老鼠抓老鼠"); } void CatchMouse() //子类的独有方法 { System.out.println("我是猫,这是我的独有功能:抓老鼠"); } } class Dog extends Animal //继承动物这个类 { void eat() //重写eat()这个方法 { System.out.println("我是狗,吃骨头"); } void kanJia() //Dog类的独有方法 { System.out.println("我是狗,这是我的独有功能:看家"); } } class Pig extends Animal //继承动物这个类 { void eat() { System.out.println("我是猪,吃饲料"); } void GongDi() { System.out.println("我是猪,这是我的独有功能:拱地"); } } class DuoTaiDemo { public static void main(String[] args) { System.out.println("*****************使用多态前******************"); /*****************前期做法******************/ function(new Cat()); //调用猫的eat()方法 function(new Dog()); //调用狗的eat()方法 function(new Pig()); //调用猪的eat()方法 /*******************************************/ System.out.println("*****************使用多态******************"); /*****************使用多态******************/ functionDuoTai(new Cat()); functionDuoTai(new Dog()); functionDuoTai(new Pig()); /*******************************************/ /*******************************************/ } /*****************前期做法******************/ //以下为以往做法,代码重复冗余 public static void function(Cat c) { c.eat(); c.catchMou(); } public static void function(Dog d) { d.eat(); } public static void function(Pig p) { p.eat(); } /*******************************************/ /*****************使用多态******************/ public static void functionDuoTai(Animal a) { //运行动物的独有功能 //多态的类型转换 if (a instanceof Cat) //如果Animal是猫 { Cat c=(Cat)a; //将动物向下转换成猫 c.CatchMouse(); //猫的特有功能 } else if(a instanceof Dog) { Dog d=(Dog)a; //将动物向下转换成狗 d.kanJia(); } else if(a instanceof Pig) { Pig p=(Pig)a; p.GongDi(); } } /*******************************************/ }结果:
这代码就是多态的体现,假设子类Cat中有特有的抓老鼠功能,父类型的 a就不能直接调用。这上面的代码中,可以理解为Cat类型提升了,向上转型。如:
Animal a=new Cat();//类型提升,向上转型 //如果想要调用猫的特有方法时,得强制将父类的引用,转成子类类型 Cat c=(Cat)a;如果此时父类的引用想要调用Cat中特有的方法,就需要强制将父类的引用,转成子类类型,向下转型。如:Catc = (Cat)a;
注:如果父类可以创建对象,如:Animal a = new Animal(); 此时,就不能向下转型了,Cat c = (Cat)a; 这样的代码就变得不容许,编译时会报错。所以千万不能出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。多态至始至终都是子类对象在做着变化。
看一个例子:
/* 基础班学生:学习,睡觉 高级班学生:学习,睡觉 可以将这两类事物进行抽取 */ abstract class Student { //定义一个抽象方法 public abstract void study(); //这个方法可以继承(子类对象可以直接使用),也可以复写 void sleep() { System.out.println("躺着睡"); } } //基础班学生 class BaseStudent extends Student { //复写父类的study方法 public void study() { System.out.println("基础学习"); } //复写父类的sleep方法 void sleep() { System.out.println("坐着睡"); } } class AdvStudent extends Student { //复写父类的study方法 public void study() { System.out.println("高级学习"); } } class DoStudent { //多态的使用 void DoSome(Student s) { s.study(); s.sleep(); } } class DuoTaiDemo { public static void main(String[] args) { DoStudent ds=new DoStudent(); ds.DoSome(new BaseStudent()); ds.DoSome(new AdvStudent()); } }上述代码是定义了一个中间的类,将基础班学生和高级班学生的共同行为封装在一个类中,使用其父类作为参数传递,也是用到了多态。
下面也是一个多态的小应用,其分为三个部分
1、定义好工具类,即将共同行为封装在一个类中。
2、对类型进行抽取,---->多态的产生。
3、操作同一父类型,对其中的子类型均可操作
如下:
/* 多态的应用 需求: 电脑运行实例,电脑运行是基本于主板的。 假设主板只是提供电脑运行,但是没有上网,听歌等功能。 而上网、听歌需要硬件的支持。而现在主板上没有网卡和声卡,这时可以定义一个规则,叫PCI, 只要符合这个规则的网卡和声卡都可以在主板上使用,这样就降低了主板和网卡、声卡之间的耦合性。 用程序体现。 */ //创建一个主板类 class MainBoard { public void run() { System.out.println("主板运行"); } public void usePCI(PCI p) //PCI p=new NetCard();接口型引用指向自己的子类对象 { if(p!=null) //当使用设备时 { p.open(); p.close(); } } } //创建一个接口 PCI interface PCI { void open(); void close(); } //网卡实现PCI接口 class NetCard implements PCI { public void open() { System.out.println("网卡运行"); } public void close() { System.out.println("网卡停止"); } } //声卡实现PCI接口 class SoundCard implements PCI { public void open() { System.out.println("声卡运行"); } public void close() { System.out.println("声卡停止"); } } class DuoTaiDemo5 { public static void main(String[] args) { //运行主板 MainBoard mb=new MainBoard(); mb.run(); //主板通过PCI接口操作设备 mb.usePCI(null); mb.usePCI(new SoundCard()); mb.usePCI(new NetCard()); } }
1、在多态中成员函数(非静态)的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
如下:
class Fu { void method1() { System.out.println("Fu Method1"); } void method2() { System.out.println("Fu Method2"); } } class Zi extends Fu { void method1() { System.out.println("Zi Method1"); } void method3() { System.out.println("Zi Method2"); } } class DuoTaiDemo3 { public static void main(String[] args) { Fu z=new Zi(); z.method1(); z.method2(); //z.method3(); //编译失败 } }结果:
简单总结:成员函数在多态调用时,编译看左边,运行看右边
2、在多态中成员变量的特点:无论编译或运行,都参考左边(引用型变量所属的类)
如下面代码:
class Fu { int num=5; } class Zi extends Fu { int num=8; } class DuoTaiDemo4 { public static void main(String[] args) { Fu f=new Zi(); System.out.println(f.num); Zi z=new Zi(); System.out.println(z.num); } }运行结果:
3、在多态中,静态成员函数的特点(在开发中很少见,因为很少会去复写静态方法)
无论编译和运行,都参考左边 如下:
class Fu { int num=5; static void method() { System.out.println("Fu method"); } } class Zi extends Fu { int num=8; static void method() { System.out.println("Zi method"); } } class DuoTaiDemo4 { public static void main(String[] args) { Fu f=new Zi(); f.method(); Zi z=new Zi(); z.method(); } }结果:
Object类
类Object是类层次结构的根类。每个类都使用Object作为超
类。
Object :是所有对象的直接或者间接父类,传说中的上帝
该类中定义的肯定是所有对象都具备的功能。
下面讲的就是Object中的常用的方法
equals
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。(其实比较的就是对象在内存中的地址值)
参数类型是Object ,这里也是用到了多态。
如下代码:
class Demo { } class ObjectDemo { public static void main(String[] args) { Demo d1=new Demo(); Demo d2=new Demo(); Demo d3=d1; System.out.println(d1.equals(d2)); //d1和 d2分别指向不同的对象,地址值自然不同 false System.out.println(d1==d2); //在比较对象时,==和equals 效果一样 false System.out.println(d1.equals(d3)); //d1和d3均指向同一个对象,所以地址值自然一样 true System.out.println(d1==d3); //同上 } }结果:
Object类中已经提供了对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义,只要沿袭父类Object中的功能,建立自己特有的比较内容即可。这就是覆
盖。如下:
class Demo { private int num; Demo(int num) { this.num=num; } //复写父类Object中的equals方法 public boolean equals(Object obj) { if(obj instanceof Demo) //判断是否是Demo类型的对象 { Demo d=(Demo)obj; return this.num==d.num; } return false; } } class ObjectDemo { public static void main(String[] args) { Demo d1=new Demo(5); Demo d2=new Demo(5); System.out.println(d1.equals(d2)); } }
结果:
内部类
内部类:将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)
访问特点:
A、内部类可以直接访问外部类中的成员,包括私有成员
之所以可以直接访问外部类中的成员,是因为外部类中持有了一个外部内的引用,格式 外部类名.this
B、而外部类要访问内部类中的成员必须要建立内部类的对象
如下代码:
//外部类 class Outer { private int x=3; //内部类 class Inner { void function() { //访问外部类中的成员,包括私有成员 System.out.println("Inner:"+x); } } void method() { //外部类要访问内部类中的成员必须要建立内部类的对象 Inner in=new Inner(); in.function(); } } class InnerClassDemo { public static void main(String[] args) { Outer ou=new Outer(); ou.method(); /*********在其他类中直接访问内部类中的成员************/ //当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类对象。 Outer.Inner in=new Outer().new Inner(); in.function(); } }
再看下面一段代码:
class Outer { private int x=3; private int y=6; class Inner { int x=4; void function() { int x=5; System.out.println("Inner:"+x); //访问本类中的局部变量x System.out.println("Inner:"+this.x); //访问本类中的x,所以用this System.out.println("Inner:"+Outer.this.x);//访问外部类中的本类变量x,所以加上Outer.this System.out.println("Inner:"+y); //这里因为没有同名变量,所以省略了Outer.this } } void method() { Inner in=new Inner(); in.function(); } } class InnerClassDemo0 { public static void main(String[] args) { Outer ou=new Outer(); ou.method(); } }
结果:
从上述代码中可以得出:之所以可以直接访问外部类中的成员,是因为外部类中持有了一个外部内的引用,格式 外部类名.this
从上面的代码中可以看到内部类的访问格式
访问格式:
1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类对象。
格式:外部类名.内部类名 变量名=外部类对象.内部类对象
如 Outer.Inner in=new Outer().new Inner();
2、当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装
静态内部类
static:内部类就具备static 的特性。
当内部类被static 修饰后,只能直接访问外部类中的static成员。出现了访问局限。
如下代码片段:
class Outer { private int x=3; //静态内部类 static class Inner { void function() { System.out.println("Inner:"+x); } } }结果:
因为内部类用static修饰后,就具备了static的特性。所以静态不能直接访问非静态
注意:当内部类中定义了静态成员,该内部类必须是静态的n
当外部类中的静态方法访问内部类时,内部类也必须是static的
如下代码段:
class Outer { private int x=3; //静态内部类(当内部类中有静态成员时,该内部类必须是静态的) static class Inner { static void function() { System.out.println("Inner:"+x); } } }
3、内部类定义在局部时:
1、不可以被成员修饰符修饰(static private)
2、可以直接访问外部类中的成员,因为还持有外部类中的引用。
但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量
用如下代码说明:
<span style="color:#666666;">class Outer { int x=3; void method() { final int y=4; //局部内部类 class Inner { void function() { System.out.println("局部内部类:"+x); //如果y没有用final修饰,则访问y时编译器会提示:从内部类中访问局部变量y; //需要被声明为最终类型 System.out.println(y); } } //要想访问非静态,必须通过对象 new Inner().function(); } } class InnerClassDemo1 { public static void main(String[] args) { new Outer().method(); } }</span>
匿名内部类
1、匿名内部类其实就是内部类的简写格式。
2、定义匿名内部类的前提:内部类必须是继承一个类或者实现接口
3、匿名内部类的格式:new 父类或者接口(){定义子类的内容}
4、其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。
5、匿名内部类中定义的方法最好不要等于或超过3个
用一个例子来说明:
//定义一个抽象类,作为匿名内部类的父类 abstract class AbsDemo { abstract void show(); } //外部类 class Outer { int x=8; void method() { //new Inner().function(); /**********使用匿名内部类1***********/ new AbsDemo() { //复写父类的抽象方法 void show() { System.out.println("我是匿名内部类:"+x); } }.show(); /**********使用匿名内部类2***********/ new AbsDemo() { //复写父类的抽象方法 void show() { System.out.println("我是匿名内部类:"+x); } void haha() { System.out.println("haha"); } }.haha(); /**********使用匿名内部类2***********/ //这个是加载中的向上提升 AbsDemo ad= new AbsDemo() { //复写父类的抽象方法 void show() { System.out.println("我是匿名内部类:"+x); } //这个方法其实没什么意义 void haha() { System.out.println("haha"); } }; ad.show(); //ad.haha();//这句会编译失败,因为父类中根本没有haha这个方法 } } class InnerClassDemo3 { public static void main(String[] args) { new Outer().method(); } }
下面来看一个匿名内部类的题目:
interface Inter { void method(); } class Test { //补足代码。通过匿名内部类 } class InnerClassTest { public static void main(String[] args) { Test.function().method(); } }代码及思路如下:
//这个接口是作为内部类的父类存在的(注:接口中全部都是public 类型的抽象方法) interface Inter { void method(); } class Test { //补足代码。通过匿名内部类 static Inter function() { return new Inter() { public void method() { System.out.println("这是一个匿名内部类的小题目"); } }; } } class InnerClassTest { public static void main(String[] args) { Test.function().method(); //思路: //Test.function():Test类中有一个静态的方法 function. //.method():function这个方法运算后的结果是一个对象。 //因为只有是Inter类型的对象,才可以调用method方法。 } }
再看另一个匿名内部类的题目:
/*补全下面的代码,想使用一个function方法。要求使用匿名内部类的方式完成*/ class InnerTest { public static void main(String[] args) { //补足代码。通过匿名内部类 } }
完成:因为没有定义父类或接口,所以想到Object是所有类的直接或间接父类。
class InnerTest { public static void main(String[] args) { //补足代码。通过匿名内部类 new Object() { void function() { System.out.println("Hello world"); } }.function(); } }
相关文章推荐
- 黑马程序员--java基础--对象的多态、内部类、匿名内部类、异常处理机制
- 黑马程序员_Java基础_抽象类,模板设计模式,接口,内部类,多态
- 黑马程序员——JAVA基础之多态与Object
- 黑马程序员 Java基础<二>---> 继承、内部类与多态,包
- 黑马程序员 java基础复习三之对象初始化,多态和异常等
- 黑马程序员——Java基础---多态、内部类、
- 黑马程序员——Java基础---多态、内部类、异常、包
- 黑马程序员java基础匿名内部类
- Java基础---多态、内部类、包 (黑马程序员)
- 黑马程序员_java的面向对象(对第八课多态..内部类..匿名内部类的总结)
- 黑马程序员--Java学习笔记之面向对象思想(多态、内部类、匿名内部类、异常类)
- 黑马程序员——Java基础---多态、内部类、异常、包
- 黑马程序员——JAVA基础之内部类,匿名内部类
- 黑马程序员_JAVA基础_内部类,匿名内部类,异常
- 黑马程序员_Java基础[17]_Object、内部类
- 黑马程序员_Java基础_面向对象(多态、Object类相关方法)
- 黑马程序员_JavaSE基础10 之 多态 内部类 匿名内部类
- 黑马程序员——java基础:内部类与匿名内部类
- 黑马程序员——Java基础之多态、内部类
- 黑马程序员——Java基础---多态、内部类、异常、包