面向对象学习(4)

多态的体现:

     多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。


代码:
<span style="font-size:18px;"> public class DuoTaiDemo {
 
  public static void main(String[] args) {
   function(new Cat());
   function(new Dog());
   function(new Pig());     
  }
  private static void function(Animal a) {// 传递的是父类引用
   a.eat();
   if (a instanceof Cat) {
    Cat c = (Cat) a;
    c.catchMouse();
   }
   else if(a instanceof Dog){
    Dog d = (Dog) a;
    d.kanJia();
   }
   else if(a instanceof Pig){
    Pig g = (Pig) a;
    g.sleep();
   }
  }
 }
 
 abstract class Animal{
  public abstract void eat();
 }
 
 class Cat extends Animal{
  @Override
  public void eat() {
   System.out.println("吃鱼");
  }
  
  public void catchMouse(){
   System.out.println("抓老鼠");
  }
 }
 
 class Dog extends Animal{
  @Override
  public void eat() {
   System.out.println("啃骨头");  
  }
  public void kanJia(){
   System.out.println("看家");
  }
 }
 
 class Pig extends Animal{
  @Override
  public void eat() {
   System.out.println("饲料");
  } 
  public void sleep(){
   System.out.println("睡觉");
  }
 }</span>


多态的前提、好处和弊端:

多态的前提
必须是类与类之间有关系。要么继承,要么实现。通常还有一个前提:存在覆盖。


多态的好处
多态的出现大大的提高程序的扩展性。


多态的弊端:
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员。
 
三、在多态中成员的特点:
1、在多态中成员函数(非静态)的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。


2、在多态中,成员变量的特点:
 无论编译和运行,都参考左边(引用型变量所属的类型)。


3、在多态中,静态成员函数的特点:
无论编译和运行,都参考做左边(引用型变量所属的类型)。
 
4、父子实例的内存控制:
<span style="font-size:18px;">Zi z = new Zi();
Fu f = z;</span>
   f和z都指向同一个Zi对象,不管声明他们是用什么类型,当通过这些变量调用方法是,方法的行为总是表现出它们的实际类型的行为:但如果通过这些变量来访问他们所指对象的实例变量,这些实例变量总是表现出声明这些变量所用类型的行为。由此可见,java继承在处理成员变量和方法时是有区别的。
代码示例:
<span style="font-size:18px;">public class DuoTaiDemo4 {
  public static void main(String[] args) {
   // 多态中成员函数(非静态的)的特点:编译看左边,运行看右边(动态绑定)
   Fu f = new Zi();
   f.method1();// zi....method1
   f.method2();// fu....method2
   // f.method3();编译看左边,运行看右边(动态绑定)
   // 多态中成员变量(包括静态成员)的特点:无论编译还是运行都看左边(静态绑定)
   System.out.println(f.num);// 1
   System.out.println(f.age);//2
   // 多态中的静态函数与成员变量相同:无论编译还是运行都看左边(静态绑定)
   f.method4();// fu....method4
  }
 }
 class Fu {
  int num = 1;
  static int age = 2;
 
  void method1() {
   System.out.println("fu....method1");
  }
 
  void method2() {
   System.out.println("fu....method2");
  }
 
  static void method4() {
   System.out.println("fu....method4");
  }
 }
 
 class Zi extends Fu {
  int num = 10;
  static int age = 20;
  void method1() {
   System.out.println("zi....method1");
  }
 
  void method3() {
   System.out.println("zi....method3");
  }
 
  static void method4() {
   System.out.println("zi....method4");
  }
 }</span>


多态的应用:

  需求:
    电脑运行实例,
    电脑运行基于主板。

<span style="font-size:18px;">public class DuoTaiDemo5 {
  
  public static void main(String[] args) {
   MainBoard mb = new MainBoard();
   mb.run();
   mb.usePCI(null);
   mb.usePCI(new VideoCard());
   mb.usePCI(new NetCard()); 
  }
 }
 
 interface PCI{
  public abstract void open();
  public abstract void close();
 }
 
 class MainBoard{
  public void run(){
   System.out.println("mainboard ........run");
  }
  public void usePCI(PCI p){
   if(p != null){
    p.open();
    p.close();
   }
  }
 }
 
 class VideoCard implements PCI{
 
  @Override
  public void open() {
   System.out.println("videocard..........run"); 
  }
 
  @Override
  public void close() {
   System.out.println("videocard..........close"); 
  } 
 }
 
 class NetCard implements PCI{
  @Override
  public void open() {
   System.out.println("NetCard..........run");  
  }
  
  @Override
  public void close() {
   System.out.println("NetCard..........close");  
  } 
 }</span>



复写Object类中的equals方法和toString方法

Object:是所有对象的直接后者间接父类,传说中的上帝。该类中定义的肯定是所有对象都具备的功能。
 Object类中已经提供了对对象是否相同的比较方法。(equals方法)
 如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。

<span style="font-size:18px;">public class ObjectDemo {
  
  public static void main(String[] args) {
  
   Demo d1 = new Demo(5);
   Demo d2 = new Demo(5);
   System.out.println(d1.equals(d2));
   
  }
 }
 
 class Demo{
  private int num;
  Demo(int num){
   this.num = num;
  }
  
  public boolean equals(Object obj){
   if(!(obj instanceof Demo))
    return false;
   Demo d = (Demo) obj;
   return this.num == d.num;
  }
  
  public String toString() {
   return "demo:" + num;
  }
 }
 </span>

"=="和equals方法究竟有什么区别?
       ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。  
       如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
       equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码: 

<span style="font-size:18px;">String a=new String("foo");
 String b=new String("foo");</span>

       两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。
       在实际开发中,我们经常要比较传递进行来的字符串内容是否等,例如,String input=.....;
input.equals(“quit”),许多人稍不注意就使用==进行比较了,这是错误的,随便从网上找几个项目实战的教学视频看看,里面就有大量这样的错误。记住,字符串的比较基本上都是使用equals方法。
       如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下: 

<span style="font-size:18px;">boolean equals(Object o){
        return this==o;  
   } </span></span>

  这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。

</pre><pre>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值