java学习基础课之面向对象继承(渡一教育)(七)多态和内部类

Java面向对象的四大特性
继承 封装 多态 (抽象)

一 多态

同一个对象, 体现出来的多种不同形态(身份) , 将一种行为表现出不同的效果。
要想实现多态的效果 ,需要现有继承关系
体现:

  1. 父类类型的引用 指向 子类的对象
    Person p = new Teacher();

  2. 该引用只能调用父类中定义的属性或方法

  3. 如果子类中将父类的方法重写,那么调取方法后执行的结果是子类重写之后的那个结果。

    如果父类与子类有同名的属性---------执行父类的属性
    如果父类与子类有同名的方法(重写)----执行子类重写之后的方法

  4. 若想要调用子类独有的成员
    (强制类型转化) 造型 铸型 (向上/向下转型)
    Teacher tt = (Teacher)p;

  5. 造型时(强制向下转型时) 可能会出现一个运行时异常
    ClassCastException 造型 铸型 异常
    可能因为同级别强制类型转换,就会异常,只有父类和子类才可以造型强制类型转换。
    如果想要避免造型的异常,可以用instance of关键字来进行判断
    对象 instanceof 类

if(o instanceof Person){//对象是否属于后面类型
            System.out.println("类型匹配  可以造型");
            Student s = (Student)o;//运行时异常 ClassCastException
            s.study();
        }else{
            System.out.println("对不起 类型不匹配 不帮您造型啦 否则会出问题");
        }

多态例子:
Person类:

public class Person {
    public String name = "person的name属性";

    public void eat(){
        System.out.println("person的吃饭方法");
    }
    public void sleep(){
        System.out.println("人类的睡觉方法");
    }
    public void talk(){
        System.out.println("人类的说话方法");
    }
}

Teacher类:

public class Teacher extends Person {
    public String name = "teacher的name属性";
    public void eat(){  // 重写
        System.out.println("做老师的通常不按时吃饭");
    }

    public void teach(){  // 独有方法
        System.out.println("做老师的独有方法 一般人不会讲课 我会");
    }
}

主方法:

public class Test {
    public static void main(String[] args){
        // Teacher 对象
        Teacher t=new Teacher();
        t.sleep();
        t.talk();
        t.eat(); //重写的方法
        t.teach(); //独有的方法
        System.out.println("----------------------------");
        /*
        人类的睡觉方法
		人类的说话方法
		做老师的通常不按时吃饭
		做老师的独有方法 一般人不会讲课 我会
		----------------------------
		*/

        // 多态,让老师作为另一种身份-------人类的方法
        Person p = new Teacher();  //此时,这个老师体现的是一个人的身份,不能使用老师的重写和独有方法了
        p.talk();
        p.sleep();
        p.eat();  // 做老师的通常不按时吃饭
        // 如果子类中将父类的方法重写,那么调取方法后执行的结果是子类重写之后的那个结果
        //p.teach();  //报错,不能使用,老师独有的方法了
        System.out.println(p.name);
        //如果父类与子类有同名的属性-----执行父类的属性
        System.out.println("----------------------------");
        /*
        人类的说话方法
		人类的睡觉方法
		做老师的通常不按时吃饭
		person的name属性
		----------------------------
        */

        //如果想要调用子类独有的属性或方法
        //需要将类型还原会真实类型    强制类型转化  造型  向上转型  向下转型
        Teacher tt = (Teacher)p;  //这次还是那个人,只不过,现在体现的是老师的身份
        tt.teach();
        System.out.println(tt.name);
        /*
        做老师的独有方法 一般人不会讲课 我会
		teacher的name属性
        */
    }
}

输出结果:

人类的睡觉方法
人类的说话方法
做老师的通常不按时吃饭
做老师的独有方法 一般人不会讲课 我会
----------------------------
人类的说话方法
人类的睡觉方法
做老师的通常不按时吃饭
person的name属性
----------------------------
做老师的独有方法 一般人不会讲课 我会
teacher的name属性

多态实例:

银行Bank
		设计一个方法 等待用户来办理业务
		profession(需要一个人)
			叫一个号码-->排队
			去窗口办理-->办理
			办理完毕离开->离开
	老人   年轻   土豪

首先分析两者之间的关系,

  • A is-a B 继承
  • A has-a B 包含, 整体和部分的关系。通过一个类的对象当做另一个类的属性来存储。一个类当中有另一个类作为属性。车有轮子。
  • A use-a B 依赖,不是整体和部分的关系。某一件事情产生了关系;临时组合在一起,这件事情一旦做完关系即解散。某一种方法使用另一个类的对象。农夫养猪。

银行处理业务的方法,需要人来介入其中,所以是某种方法将他们组合在了一起,是一种依赖关系
先根据依赖关系写一下各个类以及方法:

  • OldMan的类:
package Bank;

public class OldMan {
    private String name;
    //两个构造方法
    public OldMan(){}
    public OldMan(String name){
        this.name=name;
    }
    public void setName(){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }

    //1.进银行 叫一个号码 排队
    public void callNumber(){
        System.out.println("年事已高 不知道在哪儿叫号 请求大堂经理的帮忙");
    }
    //2.去窗口办理
    public void transact(){
        System.out.println("到窗口 掏出手绢儿 拿出存折 取钱");
    }
    //3.办理完毕离开啦
    public void leave(){
        System.out.println("办理完毕 慢慢的离开啦");
    }
}

Bank类:

package Bank;

public class Bank {
    //开门 等待用户进来办理业务
    public void profession(OldMan om) {  //某一个方法使用了另一个类的对象
        System.out.println(om.getName() + "客户进入银行啦");
        om.callNumber();
        om.transact();
        om.leave();
    }
}
  • 主方法测试一下:
package Bank;

public class Test {
    public static void main(String[] args){
        Bank bank = new Bank();
        OldMan om = new OldMan("长者");
        bank.profession(om);//银行欢迎长者进来办理业务
    }
}

  • 结果
长者客户进入银行啦
年事已高 不知道在哪儿叫号 请求大堂经理的帮忙
到窗口 掏出手绢儿 拿出存折 取钱
办理完毕 慢慢的离开啦

所以年轻人和土豪也同样是这三个方法,只不过具体里面可能有所不同。

  • YounMan类会变为:
package Bank;

public class YoungMan {
    private String name;
    //两个构造方法
    public YoungMan(){}
    public YoungMan(String name){
        this.name=name;
    }
    public void setName(){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }

    //1.进银行 叫一个号码 排队
    public void callNumber(){
        System.out.println("自己知道在门口按按钮 拿到号码小票");
    }
    //2.去窗口办理
    public void transact(){
        System.out.println("去窗口 汇款");
    }
    //3.办理完毕离开啦
    public void leave(){
        System.out.println("办理完迅速离开啦");
    }
}

  • 同样,Bank类也要添加新的方法:
// 为年轻人添加的方法
public void profession(YoungMan ym) {
        System.out.println(ym.getName() + "客户进入银行啦");
        ym.callNumber();
        ym.transact();
        ym.leave();
    }
  • 主方法测试一下
package Bank;

public class Test {
    public static void main(String[] args){
        Bank bank = new Bank();

        OldMan om = new OldMan("长者");
        bank.profession(om);//银行欢迎长者进来办理业务


        YoungMan ym = new YoungMan("年轻");
        bank.profession(ym);//银行欢迎长者进来办理业务
    }
}

结果

长者客户进入银行啦
年事已高 不知道在哪儿叫号 请求大堂经理的帮忙
到窗口 掏出手绢儿 拿出存折 取钱
办理完毕 慢慢的离开啦
年轻客户进入银行啦
自己知道在门口按按钮 拿到号码小票
去窗口 汇款
办理完迅速离开啦

土豪同理。不在赘述。
按照刚才的设计可能的问题:
1.三个不同的人类方法名不一致(可以)
2.银行办理业务的方法写了三个
解决如上所述的问题,可以在三个人类之上创建一个父类
可以解决的问题:
1.解决三个人类中的相同代码 比如name属性 比如get方法之类的
2.父类定义的三个方法可以是抽象,解决了子类命名不一致的问题 子类执行也不一致。
3.父类可以作为参数传入银行,然后通过多态调用,执行子类中重写的方法。

  • Person基类的代码:
package Bank;

public abstract class Person {
    protected String name;

    public void setName(){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }

    // 三个抽象的方法,子类可以去重写
    //1.进银行 叫一个号码 排队
    public abstract void callNumber();
    //2.去窗口办理
    public abstract void transact();
    //3.办理完毕离开啦
    public abstract void leave();
}

  • OldMan子类的代码:
package Bank;

public class OldMan extends Person{

    public OldMan(){}
    public OldMan(String name){
        this.name=name;
    }
    //1.进银行 叫一个号码 排队
    public void callNumber(){
        System.out.println("年事已高 不知道在哪儿叫号 请求大堂经理的帮忙");
    }
    //2.去窗口办理
    public void transact(){
        System.out.println("到窗口 掏出手绢儿 拿出存折 取钱");
    }
    //3.办理完毕离开啦
    public void leave(){
        System.out.println("办理完毕 慢慢的离开啦");
    }

}

YoungMan

package Bank;

public class YoungMan extends Person {
    public YoungMan(){}
    public YoungMan(String name){
        this.name=name;
    }
    //1.进银行 叫一个号码 排队
    public void callNumber(){
        System.out.println("自己知道在门口按按钮 拿到号码小票");
    }
    //2.去窗口办理
    public void transact(){
        System.out.println("去窗口 汇款");
    }
    //3.办理完毕离开啦
    public void leave(){
        System.out.println("办理完迅速离开啦");
    }
}

  • 主方法测试一下
package Bank;

public class Test {
    public static void main(String[] args){
        Bank bank = new Bank();
        Person p = new OldMan("长者");  
        //多态的使用,父类的引用指向一个子类的使用,
        //表示这个Person的身份现在是他的子类,老人这一个具体的类别
        //调用方法的时候是看父类中是如何定义的,四个方法定义了,就能调得到,但是执行的结果是看方法有没有被重写
        //执行重写之后的结果
        bank.profession(p);//银行欢迎长者进来办理业务
    }
}

  • 结果:
长者客户进入银行啦
年事已高 不知道在哪儿叫号 请求大堂经理的帮忙
到窗口 掏出手绢儿 拿出存折 取钱
办理完毕 慢慢的离开啦

调用一个方法 名字一样 传递参数却不同
1.利用方法重载—静态加载
2.利用多态效果—动态加载

二 内部类

指的是在Java中可以将一个类定义在另一个类的内部

  • 内部类可以定义在 ,类的内部 (与类成员层次一致)
  • 内部类可以定义在 ,方法/块内部 (与类成员相差一个层次 方法的局部变量一个层次)

1.成员内部类
2.局部内部类
3.匿名内部类
4.静态内部类

  1. 成员内部类
  • 将一个类直接定义在类的里面,作为成员,与属性或方法层次一致
  • 成员内部类可以与正常类一样 使用不同的修饰符来修饰
  • 好处1.省略了一个.java文件
    好处2.成员内部类中可以访问外部类的所有成员 包括私有的
  • 若想要在内部类中通过对象.调用外部类成员 外部类.this.外部类成员;
    Demo类
package innerclass;

public class Demo {
    private String name = "这是正常类中的属性";
    public void testDemo(){
        System.out.println("这是正常类中的方法");
    }

    //成员内部类
    public class InnerDemo{
        private String name="我是内部类的属性";
        public void testInnerDemo(){
            System.out.println("我是成员内部类的方法:"+this.name);  //this.是自己
            System.out.println("我是成员内部类的方法:"+Demo.this.name);  //Demo.this是外部
            Demo.this.testDemo();
            //testDemo();  //或者写这个,
            //this.testDemo();  //但是不能写这个,因为InnerDemo类中的对象只能是InnerDemo的对象,然而InnerDemo类中没有testDemo这个函数
        }
    }
}

主方法测试:

package innerclass;
import innerclass.Demo.InnerDemo;

public class TestMain {
    public static void main(String[] args){
        //内部类属于外部类的(相当于是一个成员) 需要外部类对象才能操作
        //创建内部类的对象---调用内部类的方法
        Demo demo = new Demo();
        InnerDemo innerDemo = demo.new InnerDemo();
        //调用内部类的方法
        innerDemo.testInnerDemo();

    }
}

结果:

我是成员内部类的方法:我是内部类的属性
我是成员内部类的方法:这是正常类中的属性
这是正常类中的方法
  1. 局部内部类【不常用】
  • 将一个类定义在方法/块里面,作为成员的内部结构,与临时的局部变量一个层次。
  • 局部内部类像是一个局部的变量一样,不能用public protected private及static,他们是修饰成员的
  • 只能用abstract或final
  1. 匿名内部类
    成员匿名内部类
    局部匿名内部类
public interfase Test{
			public void test();
		}
		Test t = new Test(){
			public void test(){
			}
		};
  • 通常接口或抽象类的具体子类这样写
  • 开发中为了省略一个类文件 上述写法比较常见
  • 匿名内部类很特殊 只有类体 没有类的所有结构( 修饰符 名字 继承 实现)
  • 不能用任何修饰符来修饰 匿名内部类也没有构造方法
  1. 静态内部类
    成员静态内部类
    不需要外部类对象,通过正常的方式直接创建内部类
    静态元素不能访问非静态成员(自己类和外部类)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值