Java学习日记(五)多态、内部类

一、多态

定义:某一类事物的多种存在形态

◆例:动物中猫、狗

◆猫这个对象对应的类型是猫类型

       猫 c=new 猫();

◆同时猫也是动物中的一种,也可以把猫称为动物。

       动物 y=new 猫();

       动物是猫和狗具体事物中抽取出来的父类型

       父类型引用了子类对象。

体现:

       父类或者接口的引用指向自己的子类对象或者接收自己的子类对象

作用:

       多态的存在提高了程序的扩展性和后期可维护性

弊端:

       只能使用父类的引用访问父类中的成员

前提:

       ·需要存在继承或者实现关系

       ·需要覆盖操作

特点:

       成员函数:

              编译时:要查看引用变量所属的类中是否有所调用的成员

              在运行时:要查看对象所属的类中是否有所调用的成员

       成员变量:

              只看引用变量所属的类

示例1:(使用子类都有的方法)

abstract class Animal{
       abstrac tvoid 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(“拱地”);
      }
}

class DuoTaiDemo{
       public static void main(String[] args){
              function(newCat());
              function(newDog());
              function(newPig());
       }

       public static void function(Animal a){
              a.eat();
       }
}

运行结果:

吃鱼

吃骨头

吃饲料

示例2:(使用子类特有方法)

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("拱地");
       }
}

class DuoTaiDemo{
       public static void main(String[] args){
              function(newCat());
              function(newDog());
              function(newPig());
       }
       public 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{
                     Pig p=(Pig)a;
                     p.gongDi();
              }
       }
}

运行结果:

吃鱼

抓老鼠

吃骨头

看家

饲料

拱地

附注:

类型提升(向上转型)

Anaimal a=new Cat();

a.eat();

如果要调用猫的特有方法,就要强制将父类转成子类类型的话(向下转型)

Cat c=(Cat)a;

c.catchMouse();

我们能转换的是父类应用指向自己的子类对象,该应用可以被提升,也可以被强制转换,多态自始自终都是子类对象在做着变化

Animal a=new Animal();是不允许出现的。

instanceof用于判断对象的类型,格式:对象 instanceof类型(类类型接口类型)

练习1:需求:基础班学生(学习、睡觉)、高级班学生(学习、睡觉)

代码实现:

abstract class Student{
       public abstract void study();
       public void sleep(){
              System.out.println("sleep");
       }
}

class DoStudent{
       public void doSome(Student stu){
              stu.study();
              stu.sleep();
      }    
}

class BaseStudent extends Student{
       public void study(){
              System.out.println("base study");
       }
       //覆盖父类sleep功能
       public void sleep(){
               System.out.println("base sleep");
       }
}

class AdvStudent extends Student{
       public void study(){
              System.out.println("adv study");
       }
}

class DuoTaiDemo{
       public static void main(String[] args){
              DoStudent ds = new DoStudent();
              ds.doSome(newBaseStudent());
              ds.doSome(newAdvStudent());
       }
}

运行结果:

base study

base sleep

adv study

sleep

练习2:调用时的细节

class Fu{
       static int num = 5;
       void method1(){
              System.out.println("fumethod_1");
       }
       void method2(){
              System.out.println("fumethod_2");
       }
       static void method4(){
              System.out.println("fumethod_4");
       }
}
class Zi extends Fu{
       static int num = 8;
       void method1(){
              System.out.println("zimethod_1");
       }
       void method3(){
              System.out.println("zimethod_3");
       }
       static void method4(){
              System.out.println("zimethod_4");
       }
}

class DuoTaiDemo{
       public static void main(String[] args) {
              Fu f = new Zi();
              System.out.println(f.num);          
              f.method1();
              f.method2();
              f.method3();         
              Zi z = new Zi();
              System.out.println(z.num);
              z.method1();
              z.method2();
              z.method3();
       }
}

运行结果:

5

zi method_1

zi method_2

fu method_3

8

zi method_1

zi method_2

zi method_3

总结:

1.在多态中成员函数的特点:

·在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。

·在运行时期:参阅对象所属的类中是否有调用的方法。

成员函数在多态调用时,编译看左边,运行看右边。

 

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

 

3.在多态中,静态成员函数的特点:无论编译和运行,都参考做左边。

练习3:(电脑运行实例——电脑运行基于主板)

代码实现:

interface PCI{
       public void open();
       public 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{
       publicvoid run(){
              System.out.println("mainboardrun ");
       }
       //PCI p = new NetCard()//接口型引用指向自己的子类对象
       public void usePCI(PCI p){
              p.open();
              if(p!=null){
                     p.close();
              }
       }
}

class DuoTaiDemo{
       publicstatic void main(String[] args){
              MainBoardmb=new MainBoard();
              mb.run();
              mb.usePCI(newNetCard());
              mb.usePCI(newSoundCard());
       }
}

运行结果:

mainboard run

netcard open

netcard close

SoundCard open

SoundCard close

 

二、内部类

将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类、嵌套类)

访问特点:

       ·内部类可以直接访问外部类中的成员,包括私有成员。(之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式外部类名.this

       ·而外部类要访问内部类中的成员必须要建立内部类的对象。

示例:

class Outer{
       private int x=3;
       class Inner{
              int x=4;
              void function(){
                     int x=6;
                     System.out.println("inner:"+Outer.this.x);
                     System.out.println("inner:"+this.x);
                     System.out.println("inner:"+x);
              }
       }
       void method(){
              Inner in=new Inner();
              in.function();
       }
}

class InnerClassDemo {
       public static void main(String[] args) {
              Outer out = new Outer();
              out.method();
              System.out.println("----------");
              //直接访问内部类中的成员
              Outer.Innerin=new Outer().new Inner();
              in.function();
       }
}

运行结果:

inner:3

inner:4

inner:6

----------

inner:3

inner:4

inner:6

访问格式(内部类的位置):

◆内部类定义在成员位置上:

1. 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。

       格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;

       示例:Outer.Inner in=new Outer().newInner();

2.当内部类在成员位置上,就可以被成员修饰符所修饰

       private:将内部类在外部类中进行封装

       static:内部类就具备static的特性,当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。

       问:在外部其他类中,如何直接访问static内部类的非静态成员呢?

       答:new Outer.Inner().function();

       问:在外部其他类中,如何直接访问static内部类的静态成员呢?

       答:Outer.Inner.function();

附注:当内部类中定义了静态成员,该内部类必须是static的,当外部类中的静态方法访问内部类时,内部类也必须是static

示例:

class Outer{
       private static int x=3;
       static class Inner{
              static void function(){
                     System.out.println("inner:"+x);
              }    
       }
       static class Inner2{
               void show(){
                     System.out.println("inner2show");
              }
       }
       public static void method(){
              Inner.function();
              newInner2().show();
       }
}

class InnerClassDemo {
       public static void main(String[] args) {
              Outer.method();
              System.out.println("---------");
              //访问内部类的静态成员
              Outer.Inner.function();
              System.out.println("---------");
              //访问内部静态类的非静态成员
              newOuter.Inner2().show();
       }
}

运行结果:

inner:3

inner2 show

---------

inner:3

---------

inner2 show

◆内部类定义在局部位置上:

1.不可以被成员修饰符修饰

2.可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

示例:

class Outer{
       int x = 3;
       void method(final int a){
              final int y = 4;
              class Inner{
                     void function(){
                            System.out.println(a);
                            //直接访问外部类中的成员
                            show();
                   }
              }
              new Inner().function(); 
       }
       void show(){
              System.out.println("Outershow");
       }
}

class InnerClassDemo{
       public static void main(String[] args) {
              Outer out = new Outer();
              out.method(7);
              out.method(9);
       }
}

运行结果:

7

Outer show

9

Outer show

★匿名内部类:

就是内部类的简化写法

前提:

       内部类可以继承或实现一个外部类或者接口

格式:

       new外部类名或者接口名(){覆盖类或者接口中的代码(也可以自定义内容)}

简单理解:

       就是建立一个带内容的外部类或者接口的子类匿名对象。

示例:

abstract class AbsDemo {
       abstract void show();
}

class Outer {
       int x = 3;
       class Inner extends AbsDemo {
              int num = 90;
              void show() {
                     System.out.println("show:" + num);
              }
              void abc() {
                     System.out.println("hehe");
              }
       }

       public void function() {
              Inner in = new Inner();
              in.show();
              in.abc();
              AbsDemo d = new AbsDemo() {
                     int num = 9;
                     void show() {
                            System.out.println("num==="+ num);
                     }
                     void abc() {
                            System.out.println("haha");
                     }
              };
              d.show();
              //d.abc();//编译出错,因为AbsDemo类中没有abc方法
       }
}

class InnerClassDemo {
       public static void main(String[] args) {
              newOuter().function();
       }
}

运行结果:

show :90

hehe

num===9

练习:通过匿名内部类补足代码

interface Inter {
       void method();
}

class Test {
       // 补足代码(通过匿名内部类)
       // static class Inner implements Inter{
       //    public voidmethod(){
       //      System.out.println("methodrun");
       //    }
       // }

 

       static Inter function() {
              return new Inter() {
                     public void method() {
                            System.out.println("methodrun");
                     }
              };
       }
}

class InnerClassDemo {
       public static void main(String[] args) {
              //Test.function():Test类中有一个静态的方法function.method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象,
              //因为只有是Inter类型的对象,才可以调用method方法
              Test.function().method();
              show(newInter() {
              public void method() {
                     System.out.println("methodshow run");
                     }
              });  
       }
       public static void show(Inter in) {
              in.method();
       }
}

运行结果:

method run

method show run

你可能感兴趣的:(Java)