No_16_0229 Java基础学习第九天

文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.02.29 lutianfei none

[TOC]


final 关键字

  • final关键字,可以修饰成员变量成员方法

  • 特点:

    • 修饰的,类不能被继承
    • 修饰的变量,变量就变成了常量,只能被赋值一次
    • 修饰的方法,方法不能被重写
  • final关键字面试题

  • Eg1: final修饰局部变量

    • 在方法内部,该变量不可以被改变
    • 在方法声明上,分为基本类型引用类型作为参数的情况
      • 基本类型,是值不能被改变
      • 引用类型,是地址值不能被改变,但是该对象堆内存的值可以改变。
  • Eg2: final修饰变量的初始化时机

    • 对象构造完毕前即可
class Student {
    int age = 10;
}

class FinalTest {
    public static void main(String[] args) {
        //局部变量是基本数据类型
        int x = 10;
        x = 100;
        System.out.println(x);
        final int y = 10;
        //无法为最终变量y分配值
        //y = 100;
        System.out.println(y);
        System.out.println("--------------");
        
        //局部变量是引用数据类型
        Student s = new Student();
        System.out.println(s.age);
        s.age = 100;
        System.out.println(s.age);
        System.out.println("--------------");
        
        final Student ss = new Student();
        System.out.println(ss.age);
        ss.age = 100;
        System.out.println(ss.age);
        
        //重新分配内存空间
        //无法为最终变量ss分配值
        ss = new Student();
    }
}

多态

多态概述

  • 某一个事物,在不同时刻表现出来的不同状态。
    • 举例:
      • 猫可以是猫的类型。猫 m = new 猫();
      • 同时猫也是动物的一种,也可以把猫称为动物。
        • 动物 d = new 猫();
      • 再举一个例子:水在不同时刻的状态
  • 多态前提和体现
    • 继承关系
    • 方法重写
    • 父类引用指向子类对象
      • Fu f = new Zi();

多态的分类:

  • 具体类多态:
    • class Fu{}
    • class Zi extends Fu{}
    • Fu f = new Zi();
  • 抽象类多态:
    • abstract class Fu{}
    • class Zi extends Fu{}
    • Fu f = new Zi();
  • 接口多态:
    • interface Fu{}
    • class Zi implements Fu{}
    • Fu f = new Zi();

多态中的成员访问特点:

  • A:成员变量:编译看左边,运行看左边

  • B:构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化

  • C:成员方法: 编译看左边,运行看右边。由于成员方法存在方法重写,所以它运行看右边。

  • D:静态方法:编译看左边,运行看左边。

    • (静态和类相关,算不上重写,所以,访问还是左边的)
/*
    多态:同一个对象(事物),在不同时刻体现出来的不同状态。
    举例:
        猫是猫,猫是动物。
        水(液体,固体,气态)。
        
    多态的前提:
        A:要有继承关系。
        B:要有方法重写。
            其实没有也是可以的,但是如果没有这个就没有意义。
                动物 d = new 猫();
                d.show();
                动物 d = new 狗();
                d.show();
        C:要有父类引用指向子类对象。
            父 f =  new 子();
            
*/
class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }
    
    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }
    
    public static void function() {
        System.out.println("function Zi");
    }
}

class DuoTaiDemo {
    public static void main(String[] args) {
        //要有父类引用指向子类对象。
        //父 f =  new 子();
        Fu f = new Zi();
        System.out.println(f.num);
        //找不到符号
        //System.out.println(f.num2);
        
        f.show();
        //找不到符号
        //f.method();
        f.function();
    }
}

/*
* 运行结果:
100
show Zi
function Fu
*/


多态的优缺点

  • 多态的好处

    • 提高了程序的维护性(由继承保证)
    • 提高了程序的扩展性(由多态保证)
  • 多态的弊端

    • 父类不能访问子类特有功能
  • 如何才能访问子类的特有功能呢?

    • 创建子类对象,调用方法即可。(然而很多时候不合理,且太占内存)
    • 向下转型:把父类的引用强制转换为子类的引用。
      • Zi z = (Zi)f; //要求该f必须是能够转换为Zi的
  • 现象: 子可以当做父使用,父不能当作子使用。

多态中的转型问题

  • 向上转型
    • 从子到父
    • 父类引用指向子类对象
  • 向下转型
    • 从父到子
    • 父类引用转为子类对象
  • 孔子装爹案例
//多态的问题理解:
    class 孔子爹 {
        public int age = 40;
        
        public void teach() {
            System.out.println("讲解JavaSE");
        }
    }
    
    class 孔子 extends 孔子爹 {
        public int age = 20;
        
        public void teach() {
            System.out.println("讲解论语");
        }
        
        public void playGame() {
            System.out.println("英雄联盟");
        }
    }
    
    //Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
    //但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
    //然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹
    //向上转型
    孔子爹 k爹 = new 孔子();
    //到人家那里去了
    System.out.println(k爹.age); //40
    k爹.teach(); //讲解论语
    //k爹.playGame(); //这是儿子才能做的,一做就报错!
    
    
    //讲完了,下班回家了
    //脱下爹的装备,换上自己的装备
    //向下转型
    孔子 k = (孔子) k爹;
    System.out.println(k.age); //20
    k.teach(); //讲解论语
    k.playGame(); //英雄联盟
No_16_0229 Java基础学习第九天_第1张图片
  • 多态中的对象变化内存图


    No_16_0229 Java基础学习第九天_第2张图片


  • 多态练习:猫狗案例
class Animal {
    public void eat(){
        System.out.println("吃饭");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃肉");
    }
    
    public void lookDoor() {
        System.out.println("狗看门");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}

class DuoTaiTest {
    public static void main(String[] args) {
        //定义为狗
        Animal a = new Dog();
        a.eat();
        System.out.println("--------------");
        //还原成狗
        Dog d = (Dog)a;
        d.eat();
        d.lookDoor();
        System.out.println("--------------");
        //变成猫
        a = new Cat();
        a.eat();
        System.out.println("--------------");
        //还原成猫
        Cat c = (Cat)a;
        c.eat();
        c.playGame();
        System.out.println("--------------");
    }
}


  • 不同地方饮食文化不同的案例

class Person {
    public void eat() {
        System.out.println("吃饭");
    }
}

class SouthPerson extends Person {
    public void eat() {
        System.out.println("炒菜,吃米饭");
    }
    
    public void jingShang() {
        System.out.println("经商");
    }
}

class NorthPerson extends Person {
    public void eat() {
        System.out.println("炖菜,吃馒头");
    }
    
    public void yanJiu() {
        System.out.println("研究");
    }
}

class DuoTaiTest2 {
    public static void main(String[] args) {
        //测试
        //南方人
        Person p = new SouthPerson();
        p.eat();
        System.out.println("-------------");
        SouthPerson sp = (SouthPerson)p;
        sp.eat();
        sp.jingShang();
        System.out.println("-------------");
        
        //北方人
        p = new NorthPerson();
        p.eat();
        System.out.println("-------------");
        NorthPerson np = (NorthPerson)p;
        np.eat();
        np.yanJiu();
    }
}

/*
运行结果:

炒菜,吃米饭
-------------
炒菜,吃米饭
经商
-------------
炖菜,吃馒头
-------------
炖菜,吃馒头
研究
*/


多态中继承练习

  • 继承的时候:

    • 子类中有和父类中一样的方法,叫重写
    • 子类中没有父亲中出现过的方法,方法就被继承过来了。
  • Eg:(不太理解)

/*
    多态的成员访问特点:
        方法:编译看左边,运行看右边。
        
    继承的时候:
        子类中有和父类中一样的方法,叫重写。
        子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
class A {
    public void show() {
        show2();
    }
    public void show2() {
        System.out.println("我");
    }
}
class B extends A {
    /*
    public void show() {
        show2();
    }
    */

    public void show2() {
        System.out.println("爱");
    }
}
class C extends B {
    public void show() {
        super.show();
    }

    public void show2() {
        System.out.println("你");
    }
}
public class DuoTaiTest4 {
    public static void main(String[] args) {
        A a = new B();
        a.show();
        
        B b = new C();
        b.show();
    }
}

// 运行结果:
//爱
//你


抽象类

抽象类概述

  • 动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。在Java中,一个没有方法体(连大括号也没有)的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类

抽象类特点

  • 抽象类抽象方法必须用abstract关键字修饰
    • 格式
      • abstract class 类名 {}
      • public abstract void eat();
  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
  • 抽象类不能实例化(抽象类如何实例化呢?)
    • 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
    • 抽象类有构造方法,其作用是为了用于子类访问父类数据的初始化
  • 抽象类的子类
    • 要么是抽象类
    • 要么重写抽象类中的所有抽象方法
//abstract class Animal //抽象类的声明格式
abstract class Animal {
    //抽象方法
    //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
    public abstract void eat();
    
    public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class AbstractDemo {
    public static void main(String[] args) {
        //创建对象
        //Animal是抽象的; 无法实例化
        //Animal a = new Animal();
        //通过多态的方式
        Animal a = new Cat();
        a.eat();
    }
}


抽象类的成员特点

  • 成员变量
    • 可以是变量
    • 也可以是常量
  • 构造方法
    • 有构造方法,但是不能实例化
    • 那么,构造方法的作用是什么呢?
      • 用于子类访问父类数据的初始化
  • 成员方法
    • 可以有抽象方法 作用:限定子类必须完成某些动作
    • 也可以有非抽象方法 提高代码复用性
  • 抽象定义类练习:
//定义抽象的动物类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //定义一个抽象方法
    public abstract void eat();
}

//定义具体的狗类
class Dog extends Animal {
    public Dog() {}
    
    public Dog(String name,int age) {
        super(name,age); //重要知识点!!!
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//定义具体的猫类
class Cat extends Animal {
    public Cat() {}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//测试类
class AbstractTest {
    public static void main(String[] args) {
        //测试狗类
        //具体类用法
        //方式1:
        Dog d = new Dog();
        d.setName("旺财");
        d.setAge(3);
        System.out.println(d.getName()+"---"+d.getAge());
        d.eat();
        //方式2:
        Dog d2 = new Dog("旺财",3);
        System.out.println(d2.getName()+"---"+d2.getAge());
        d2.eat();
        System.out.println("---------------------------");
        
        Animal a = new Dog();
        a.setName("旺财");
        a.setAge(3);
        System.out.println(a.getName()+"---"+a.getAge());
        a.eat();
        
        Animal a2 = new Dog("旺财",3);
        System.out.println(a2.getName()+"---"+a2.getAge());
        a2.eat();
        
        //练习:测试猫类
    }
}


  • 抽象教师类练习:
//定义抽象的老师类
abstract class Teacher {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Teacher() {}
    
    public Teacher(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //抽象方法
    public abstract void teach();
}

//基础班老师类
class BasicTeacher extends Teacher {
    public BasicTeacher(){}
    
    public BasicTeacher(String name,int age) {
        super(name,age);
    }
    
    public void teach() {
        System.out.println("基础班老师讲解JavaSE");
    }
}

//就业班老师类
class WorkTeacher extends Teacher {
    public WorkTeacher(){}
    
    public WorkTeacher(String name,int age) {
        super(name,age);
    }
    
    public void teach() {
        System.out.println("就业班老师讲解JavaEE");
    }
}

class AbstractTest2 {
    public static void main(String[] args) {
        //具体的类测试,自己玩
        
        //测试(多态)
        //基础班老师
        Teacher t = new BasicTeacher();
        t.setName("刘意");
        t.setAge(30);
        System.out.println(t.getName()+"---"+t.getAge());
        t.teach();
        System.out.println("--------------");
        
        t = new BasicTeacher("刘意",30);
        System.out.println(t.getName()+"---"+t.getAge());
        t.teach();
        System.out.println("--------------");
        
        //就业班老师
        t = new WorkTeacher();
        t.setName("林青霞");
        t.setAge(27);
        System.out.println(t.getName()+"---"+t.getAge());
        t.teach();
        System.out.println("--------------");
        
        t = new WorkTeacher("林青霞",27);
        System.out.println(t.getName()+"---"+t.getAge());
        t.teach();
    }
}


抽象类的几个小问题

  • 一个类如果没有抽象方法,可以定义为抽象类?如果可以,有什么意义?
    • 可以
    • 禁止创建对象
  • abstract不能和哪些关键字共存
    • private 冲突
    • final 冲突
    • static 无意义(通过类名直接访问没有内容的方法体)

接口

接口概述

  • 狗一般就是看门,猫一般就是作为宠物。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
    所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。

接口特点

  • 接口用关键字interface表示

    • 格式:interface 接口名 {}
  • 类实现接口用implements表示

    • 格式:class 类名 implements 接口名 {}
  • 接口不能实例化(接口如何实例化呢?)

    • 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
  • 接口的实现类(子类):

    • 抽象类:实现接口,但意义不大
    • 具体类:重写接口中的所有抽象方法
  • 补充:多态的三种形式

    • 具体类多态(几乎没有)
    • 抽象类多态(常用)
    • 接口类多态(最常用 )

接口成员特点

  • 成员变量
    • 只能是常量
    • 默认修饰符 public static final
  • 构造方法
    • 没有,因为接口主要是扩展功能的,而没有具体存在。
    • 所有的类都默认继承自一个类:Object。(类Object 是类层次结构的根类。每个类都使用Object作为超类)
  • 成员方法
    • 只能是抽象方法
    • 默认修饰符 public abstract

类与类,类与接口以及接口与接口的关系

  • 类与类
    • 继承关系,只能单继承,但是可以多层继承
  • 类与接口
    • 实现关系
      • 可以单实现,也可以多实现
      • 还可以在继承一个类的同时实现多个接口。
  • 接口与接口
    • 继承关系,可以单继承,也可以多继承

抽象类和接口的区别

  • 成员区别
    • 抽象类
      • 成员变量:变量,常量;
      • 构造方法:可以有
      • 成员方法:可以是抽象方法,也可以是非抽象方法;
    • 接口
      • 成员变量:只可以是常量;
      • 构造方法:没有
      • 成员方法:只能是抽象方法
  • 关系区别
    • 类与类 继承,单继承
    • 类与接口 实现,单实现,多实现
    • 接口与接口 继承,单继承,多继承
  • 设计理念区别
    • 抽象类 被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能
    • 接口 被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能
  • 跳高猫练习:
/*
    猫狗案例,加入跳高的额外功能
    
    分析:从具体到抽象
        猫:
            姓名,年龄
            吃饭,睡觉
        狗:
            姓名,年龄
            吃饭,睡觉
            
        由于有共性功能,所以,我们抽取出一个父类:
        动物:
            姓名,年龄
            吃饭();
            睡觉(){}
            
        猫:继承自动物
        狗:继承自动物
        
        跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
        接口:
            跳高
            
        部分猫:实现跳高
        部分狗:实现跳高
    实现;
        从抽象到具体
        
    使用:
        使用具体类
*/
//定义跳高接口
interface Jumpping {
    //跳高功能
    public abstract void jump();
}

//定义抽象类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //吃饭();
    public abstract void eat();
    
    //睡觉(){}
    public void sleep() {
        System.out.println("睡觉觉了");
    }
}

//具体猫类
class Cat extends Animal {
    public Cat(){}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//具体狗类
class Dog extends Animal {
    public Dog(){}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
    public JumpCat() {}
    
    public JumpCat(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高猫");
    }
}

//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
    public JumpDog() {}
    
    public JumpDog(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高狗");
    }
}

class InterfaceTest {
    public static void main(String[] args) {
        //定义跳高猫并测试
        JumpCat jc = new JumpCat();
        jc.setName("哆啦A梦");
        jc.setAge(3);
        System.out.println(jc.getName()+"---"+jc.getAge());
        jc.eat();
        jc.sleep();
        jc.jump();
        System.out.println("-----------------");
        
        JumpCat jc2 = new JumpCat("加菲猫",2);
        System.out.println(jc2.getName()+"---"+jc2.getAge());
        jc2.eat();
        jc2.sleep();
        jc2.jump();
        
        //定义跳高狗并进行测试的事情自己完成。
    }
}
  • 运行结果


    No_16_0229 Java基础学习第九天_第3张图片

你可能感兴趣的:(No_16_0229 Java基础学习第九天)