JAVA_Lesson10(传智播客笔记之多态、内部类)

多态-概述

对象本身也存在着多态性。

Class 动物

{}

Class 猫 extends 动物

{}

Class 狗 extends 动物

{}

猫 x=new 猫();

动物 x=new 猫();//猫是动物就可以这样写 (一个对象,两种形态,类似王者荣耀的花木兰)

    猫这类事物即具备猫的形态,又具备着动物的形态。父类创建的对象指向了子类对象。一个对象具备2种形态。多态在代码中的体现,也即是父类或者接口的引用指向子类的对象。

多态的好处


Abstract class Animal
{
   Abstract void eat();
}
Class Dog extends Animal
{
   Void eat()
   {
       Sop(“啃骨头”);
   }
   Void lookhome()
  {
     Sop(“看家”);
   }

}

Class Cat extends Animal
{
   Void eat()
  {
     Sop(“吃鱼”);
   }
   Void catchMouse()
  {
     Sop(“抓老鼠”);
  }

}
Class PolymorphismDemo
{
  Public static void main(String[] args)
 {
   Cat c=new Cat();
   Dog d=new Dog();
   Method(c);//多态后可以这样做
   Method(d);//多态后可以这样做
   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可以不断指向animal的不同的子类对象
{
   a.eat();
}

 多态的出现,提高了代码的可拓展性。前期定义的代码可以使用后期的内容。

  多态的弊端: 前期定义的内容不能调用后期子类的特有内容,(比如动物不能调用抓老鼠,可以调用吃饭)。

多态的前提:

1. 必须有关系,要么就是继承或者是实现。(其实实现就是特殊的继承)

2. 要有覆盖

面向对象(多态—多态转型)

复习一下:byte b=3int x=b;第二条语句把byte类型提升为int类型。

Animal a=new Cat()//自动类型提升,猫对象提升为动物类型。

现在操作a,只能当作动物来对待,甚至都不具备抓老鼠的功能了。不能使用猫的特有方法了。作用:就是限制特有功能的访问。(专业讲:向上转型)

如果还想用具体猫的特有功能,现在可以将该对象进行向下转型(为了使用子类的特有方法)

Cat c=Cata//此时就可以了,a就变成猫类型了。

Animal a=new Animal();

Cat c=(Cat) a;//这样就不行,本来就是动物类型,这样向下转型没法转

当然Animal a=new Dog();

Cat c=(Cat) a;//这样也会出错

注;对于转型,自始至终都是子类对象在做着类型的变化。

转型的目的:向上转型是为了限定功能使用,提高拓展性;向下转型是为了使用子类的特有功能。

Class 毕姥爷
{
  Void 讲课()
  {
    Sop(“管理”);
  }
  Void 钓鱼()
  {
    Sop(“看电影”);
  }
}
Class 毕老师 extends 毕姥爷
{
  Void 讲课()
  {
    Sop(“JAVA”);
  }
  Void 看电影()
  {
    Sop(“看电影”);
  }
}

Class DuoTaiDemo
{
  Public static void main(String[] args)
  {
    毕姥爷 x=new 毕老师();//向上转型了转化为他爹
    X.讲课();  //运行结果为java
    X.钓鱼(); //你压根不会钓鱼啊,哈哈,编译失败,我弄错了。               X.看电影();
//因为找他爹的人压根不知道他有看电影的功能。如果想要看电影,这个时候就用到子类的特有功能。这个时候如下:

    毕老师 y=(毕老师)x;
    毕老师.看电影();//现在这样就可以了。

  }

}
  

转型时要小心:ClassCastException类型转化异常。

 

对于之前如果传的是猫,向上转型为动物,然后再强转为猫,没毛病,但如果是狗的话,就不行。因此需要在此做一个判断(因为向上转型为父类后可以接受的对象种类太多了):

Ifa instanceof Cat//用于判断对象的具体类型。只能用于引用类型数据判断,这样的话程序更加健壮。(通常向下转型前需要判断)

 

多态-成员变量

 

多态的前提就是继承。

多态的成员的特点:

1. 成员变量

 编译时:参考引用型变量所属的类中是否有调用的成员变量,有则编译通过,否则编译失败。

运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。(了解即可,开发很少见,不过面试多见)

也即是编译和运行都参考等号的左边。

2. 成员函数(弄错了,编译时自己以为父类没有show方法可以编译通过,实际上不行   这里就不再举例了

编译时:参考引用型变量所属的类中是否有调用的成员变量,有则编译通过,否则编译失败。

运行时:参考的是对象所属的类中是否有调用的函数。

也即是编译看左边运行看右边

3. 静态函数

类名直接调用即可,跟对象没啥关系。也不涉及什么子类对象的问题。相当于已经绑定在类上面了。(不涉及对象的多态性,直接运行了)

简单说就是:编译和运行都看左边即可。其实对于静态方法,是不需要对象的。直接用类名调用即可。

下面这个示例(成员变量的示例)又做错了:

Class Fu
{
   Int num=3;
}
Class Zi extends Fu
{
   Int num=4;
}
Class DuoTaiDemo3
{
  Public static void main(String[] args)
  {
    Fu f=new Zi();
    Sop(f.num);//打印结果为3,感觉跟之前毕姥爷那个例子不太一样啊?何解
   }              //这里的解释是f指向父类了,直接从父类那里找,如果把父类的那个
//num注释掉的话,那么就会不报错,也不会打印4.
//注意要区分前面那个毕姥爷的例子,那个例子是因为把父类的方法给覆盖了。(这个示例要掌握,覆盖只发生在函数上,变量是没有关系的。)

}

 一出现多态就要知道向上转型。就不能使用子类的特有方法。

 

内部类(嵌套类)

存在的原因:方便访问外部类中的成员。

内部类编译后生成的名称:外部类名&内部类名.class

访问特点:

1. 内部类可以访问外部类中的成员(包括私有变量)。

2. 外部类要访问内部类,必须要建立内部类的对象。

Class Outer
{
   Private int num=3;
   Class Inner
  {
    Void show()
    {
      Sop(“show run”+num);
    }
  }
   Public void method()
  {
     Inner in=new Inner();
     In.show();
  }
}

      一般用于类的设计,分析事物描述中还有事物,而且这个事物还在访问被描述事物的内容。这时就是还有的食物定义成内部类来描述。(人体,心脏在人体内,心脏需要访问人体中的很多其他部位)

内部类-修饰符

 

Class Outer
{
  Private int num=3;
  Class Inner
  {
    Void show()
   {
     Sop(“show run”+num);
   }
  }
  Public void method()
  {
    Inner in=new Inner();
    In.show();
  }
}
 Class InnerClassDemo
{
  Public static void main()
  {
    Outer.Inner in=new Outer().new Inner();
    In.show();//直接访问外部类中的内部类中的成员。但是如果private的话,就不能访问了。如果内部类的修饰符是static的话,相当于是一个外部类,以上2句代码可以直接Outer.Inner in=new Outer.Inner();直接外部类加载进内存了。如果想要直接直接调用内部类中的静态成员(类名调用),该内部类也必须是静态的。
  }
}

内部类细节

Class Outer 
{
  Int num=3;
  Class Inner
  {
     Int num=4;
    Void show()
    {
      Int num=5;
      Sop(this.num);//去除this会打印5,现在打印4.
      Sop(Inner.this.num);//居然会打印4,所以可以借鉴下
      Sop(Outer.this.num);//这样才可以打印3.( 因为内部类持有外部类的引用,所以可以这样做。 )
(实际开发不会这样搞,但是还是要懂)
    }
  }
}
Class InnerClassDemo2
{
  Public static void main(String[] args)
  {
    New Outer().method();
  }
}

内部类-局部内部类

/*

内部类可以存储在局部位置上。

*/

Class Outer
{
  Int num=3;
  Void method()
  {
    Class Inner  
    {
       Void show()
      {
        Sop(“show...”+num);
      }
    }
    Inner in=new Inner();
    In.show();
  }
}
Class InnerClassDemo3
{
  Public static void main(String[] args)
  {
    New Outer().method();
  }
}

上面这个示例可以正常运行。接着看下面:

Class Outer
{
  Int num=3;
  Void method()
  {	
    Int x=9;//需要加final关键字才可以编译通过(固定规则,但是老师阐明了一些原因,但是还没有太听懂) 原理就是:内部类在局部位置上只能访问局部中被final修饰的局部变量。如果没有听懂就记住。
  Class Inner  
  {
    Void show()
    {
       Sop(“show...”+x);
     }
   }
   Inner in=new Inner();
   In.show();
   }
}
Class InnerClassDemo3
{
  Public static void main(String[] args)
  {
    New Outer().method();
  }
}

匿名内部类-概述(之前在匿名对象中遇到过)

就是内部类的简写格式。

必须有前提:内部类必须继承或者实现一个外部类或者接口。所谓匿名也就是:内部类没有名字。

匿名内部类:其实就是一个匿名子类对象。

格式:new父类or接口(){子类内容}

Abstract class Demo
{
  Abstract void show();
}
Class Outer
{
  Int num=4;
}
Public void method()
{
  New Demo()  //其实在这里就是new了一个子类对象。
  {
    Void show()
    {
      Sop(“show...”+num);
    }
    Void haha()
    {
      Sop(“haha”);
    }
  }.show(); //调用了自己子类的方法,当然以上还可以加哈哈方法也行。
}

匿名内部类-应用(未做笔记)

2种等价的形式:

匿名内部类-细节

静态中没有this的。主函数不能直接访问非静态成员。

匿名内部类这个子类对象被向上转型为了object类型,就不能再使用子类的特有方法。(参考之前的编译看哪边,运行看哪边。)

 对象的初始化过程

 图中下部分为打印结果。顺序也已经在图中标注了(红色阿拉伯数字)。

显示初始化动作和构造代码块初始化以及super(无非父类对应的是Object,暂时不用深究)这些操作,父类和子类均有的。父类的那一套东西对应于子类的构造函数中的第一句super();

 


猜你喜欢

转载自blog.csdn.net/wearlee/article/details/80757233