Java基础(面向对象三——多态、内部类)

来源:互联网 发布:java 打印map 键值对 编辑:程序博客网 时间:2024/05/11 17:05


一、多态

定义:事物存在的多种表现形式

例如:动物中猫和狗

猫这个对象对应的类型是猫类型      猫 m = new 猫();

而猫是动物中的一种,所以也可以把猫称为动物,也就是说让父类引用指向子类对象   动物  d = new 猫();

多态的表现形式:

  1. 父类的引用指向了子类对象
  2. 父类的引用也可以接收该父类类型的对象

多态的前提:

  1. 必须类与类之间存在关系,要么继承要么实现
  2. 要存在覆盖(复写)

多态的好处:

多态的出现大大的提高了程序的扩展性

多态的弊端:

多态虽然提高了程序的扩展性,但是只能使用父类的引用访问父类的成员

多态的应用:

多态的出现代码中的特点:

在多态中成员函数的特点(非静态)

在编译时期:参阅引用型变量是否有调用的方法,如果有,则编译通过
在运行时期,参阅对象所在的类中是否有调用的方法

简单一句话:编译看左边,运行看右边

白话:就是当父类引用指向子类对象时,如果调用的方法父类中有,就编译通过,没有就报错,如果有再看子类中是否重写该方法,如果重写,不言而喻肯定运行的是子类中的内容

在多态中成员变量的特点:无论编译还是运行,都参考左边

在使用多态调用成员变量时,如果父类和子类中拥有相同名称的成员变量时,左边为父类,那么调用的就是父类中的成员变量,如果左边为子类,那么就调用子类中的成员变量

在多态中静态成员的特点:无论编译还是运行都参考左边

一样道理,静态只要类一加载就存在了,是不需要使用对象的,所以谁调用就运行谁

多态的表现形式:

abstract class Animal{    //定义为抽象方法,要求子类必须实现,因为只要是动物,都具备吃的行为    public 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 kanHome(){        System.out.println("狗看家");    }}class  DuoTaiDemo{    public static void main(String[] args)     {        /*        Cat c = new Cat();        c.eat();        Dog d = new Dog();        d.eat();        */        /*        发现这样写会比较麻烦,因为每出现一种动物想要调用该动物的eat()方法都要建立该动物对象,有没有简单一点的方法呢?        因为不管是猫还是狗都是动物,都具备eat()方法,那我能不能直接让动物指向自己的子类呢?因为子类复写了父类中的方法,当使用父类引用指向子类对象调用父类方法时,调用的还是子类的方法        */        function(new Cat());        function(new Dog());        public void function(Animal a){        //Adimal a = new Cat();  向上转型            a.eat();        }        /*            但是发现这样写完之后发现没法调用子类特有的方法了,因为动物中是没有子类特有的行为的,怎么办呢?            因为动物不具备猫和狗特有的行为,那么我们能不能使用子类去调用自己特有的方法呢?                        向下转型:            public 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.kanHome();                }            }        */    }}

二、内部类

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

内部类访问规则:

1、内部类可以直接访问外部类的成员,包括私有化成员

2、外部类要访问内部类必须要创建内部类对象

访问格式:

1、当内部类定义在外部类的成员位置上时,并且非私有化,

注:当内部类定义在外部类的成员位置上时,是可以被private static成员修饰符修饰的,被static修饰的内部类只能访问外部类中的静态成员

1.1、在本类内部访问内部类

class Demo{//外部类成员变量int num = 5;//内部类class Inner{//内部类成员函数public void show(){System.out.println("调用内部类show方法");}}//外部类成员函数public void function(){//创建内部类对象调用内部类方法Inner in = new Inner();in.show();}}

注:如果内部类中有同名称的变量,在内部类中调用外部类成员变量时,则运行的是内部类中成员变量的值(其实就是省略了this),而当要访问外部类成员变量时,则需要标识,格式:外部类.this.要调用的变量名

1.2、在外部其他类中访问内部类

//在外部其他类中访问内部类class Outer{int x = 5;//内部类class Inner{public void show(){System.out.println("调用内部类方法");}}public void function(){System.out.println("Outer的方法");}}class  Demo{public static void main(String[] args) {//在其他类中直接访问内部类/*因为不确定到底有几个Inner类,所以创建内部类对象时要指明要创建的内部类格式 外部类.内部类 变量名 = new 外部类类名().new 内部类类名();*/Outer.Inner in = new Outer().new Inner();}}
注:如果内部类中有同名称的变量,在其他外部类中调用内部类成员变量时,如果内部类中有该变量并没有私有化,则运行的是内部类中成员变量的值,如果没有,则运行该内部类所在的外部类中的没有私有化的成员变量的值

2、当内部类定义在成员位置上并被private或static所修饰时

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

2.1、在外部其他类中,直接访问static内部类的非静态成员


class Outer{int x = 5;//静态内部类static class Inner{//内部类中的非静态成员方法public void show(){System.out.println("调用内部类方法");}}public void function(){System.out.println("Outer的方法");}}class  Demo{public static void main(String[] args) {//在其他类中直接访问静态内部类中的非静态方法new Outer.Inner().show();}}
2.2、在外部其他类中,直接访问static内部类的静态成员

class Outer{int x = 5;//静态内部类static class Inner{//内部类中的静态成员方法public static void show(){System.out.println("调用内部类方法");}}public void function(){System.out.println("Outer的方法");}}class  Demo{public static void main(String[] args) {//在其他类中直接访问静态内部类中的静态方法Outer.Inner().show();}}

3、当内部类定义在局部位置上时

1、不可以被成员的修饰符所修饰

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

class Outer{int num = 5;//外部类成员函数public void function(){int x = 3;/*内部类定义在局部位置上,不可以被static、private所修饰,此时可以访问成员变量num,但是不可以访问局部变量x,因为x没有被 final 所修饰如果代码改为:public void function(final int x){class Inner{public void show(){System.out.println("调用内部类方法");}}}就可以访问了,这样写有一个特点,就是调用function并传参后x的值就固定了,不可以在进行赋值操作了*/class Inner{public void show(){System.out.println("调用内部类方法");}}}}


什么时候使用内部类呢?

当描述事物,而事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容

三、匿名内部类

定义:其实就是内部类的简写格式

定义匿名内部类的前提:内部类必须是继承一个类或者实现接口

匿名内部类的格式:new 父类或者接口(){定义子类的内容}

注:1、其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。    可以理解为带内容的对象

        2、匿名内部类中定义的方法最好不要超过3个

interface AbsDemo{public void show();}class Outer{//有名内部类/*class Inner implements AbsDemo{public void show(){System.out.println("有名内部类");}}public void function(){AbsDemo ab = new Inner();ab.show();}*///匿名内部类public void function(){new AbsDemo(){public void show(){System.out.println("匿名内部类");}}.show();/*因为是匿名内部类,所以是没有名字的,只能通过创捷父类或接口来建立子类对象,完成复写*/}}class  {public static void main(String[] args) {System.out.println("Hello World!");}}
小练习:

//根据已有代码补全程序,要求使用匿名函数/*已有代码:interface Inner{public abstract void method();}class Test{public static  function(){}}class  Demo{public static void main(String[] args) {Test.function().method();}}*/class  Demo{public static void main(String[] args) {//Test.function():Test类中有一个静态的方法function。//.method():function这个方法运算后的结果是一个对象。而且是一个Inter类型的对象。//因为只有是Inter类型的对象,才可以调用method方法。Test.function().method();}}//使用匿名对象interface Inner{public abstract void method();}class Test{public static Inner  function(){return new Inner(){public void method(){System.out.println("重写了方法");};}}}/*不使用匿名对象interface Inner{public abstract void method();}class Test{class Util implements Inner{public void method(){System.out.println("重写了方法");}}public static Inner  function(){return new Util();}}}*/

0 0