Java day8

来源:互联网 发布:判断微信浏览器 js 编辑:程序博客网 时间:2024/06/15 19:33

一、多态

1.多态:一个事物在不同时刻体现出来的不同状态。

例:Animal a = new Cat();      

2.对于多态的三个前提条件:

(1)条件1:必须有继承关系(如果没有继承关系,谈不上多态)

(2)条件2:必须有方法重写

     子类出现了父类一样的方法声明。

(3)有父类引用指向子类对象:向上转型

     Fu f= new Zi();

     注:多态的三个条件缺一不可。

3.多态的成员访问特点:

     成员变量:

         编译看左边,运行看左边

     成员方法(非静态的成员方法):

         编译看左,运行看右;由于存在方法重写,所以就运行最终的就是子类的成员方法

 静态成员方法:(静态方法算不上方法重写,静态直接跟类有关系)

         编译看左,运行看左

     构造方法:还是对象进行初始化,由于是一种继承关系,还是分层初始化。

     分层初始化:父类先初始化,然后子类初始化。

步骤:

在测试类中创建父类的对象:多态的形式

由父类引用指向子类对象:向上转型

Fu f = new Zi();

访问成变量

调用成员方法:show()

f.show();

例:创建对象

       多态版(实际开发中:多态使用最广泛:接口多态是经常使用的!)

       Animal a = new Cat() ;

       a.eat();

       a.sleep();

       a = new Dog();

       a.eat();

       a.sleep();

4. 多态的好处(特点):      

(1)提高代码的维护性(由继承保证)

(2)提高代码的扩展性(由多态保证)

注:java的开发原则:低耦合,高内聚。

例:

父类为:Animal 子类为:猫类  狗类  猪类

猫类 狗类 猪类都有自已的功能

再写一个动物的工具类

先将将类中无参构造私有化:目的是为了不让外界创建对象。

形式参数为一个父类

在测试类实现功能;

1.  可以直接创建对象调用

   Cat c1 = new Cat();

   c1.eat();

2.  优化改进:将猫的吃和睡的方法封装成独立的功能

public static void useDog(Dog d){

d.eat();

d.sleep() ;

在测试类调用

Dog d1 = new Dog();

Dog d2 = new Dog();

Dog d3 = new Dog();

     调用狗的功能

     useDog(d1);

     useDog(d2);

     useDog(d3);

3.最终版代码

先创建AnimalTool对象

     AnimalTool at = newAnimalTool();

     形式参数:Animal a = new Cat();

      a.useAnimal(c1);

      at.useAnimal(c2);

      at.useAnimal(c3);

5. 多态的弊端:

不能访问子类的特有功能。

多态的弊端是不能访问子类的特有功能:如何解决?

注:异常:OOM异常:严重:OutOfMemory:内存溢出

解决方案:

 (1)创建子类的具体对象,来访问自己的特有功能;虽然可以解决多态的弊端,但是从内存角度考虑,需要创建子类对象,那么必须在堆内存开辟空间。

弊端: 耗费内存,浪费空间。

 (2)既然多态的第三个前提条件:父类引用指向子类对象,那么可不可以将子类的引用指向父类对象呢?

      可以的:向下转型:将父类的引用强制转换为子类的引用:前提必须有父类的引用存在。

      注:向下转型必须依赖于向上转型。

例:在测试中

父类引用指向子类对象

Animal3 a = new Cat3(); //向上转型

a.show();

此处不能访问子类特有功能:playGame()

a.playGame();

访问方案:

1.创建子类具体对象

    Cat c = new Cat();

    c.playGame() ;

2.父类的引用强制转换为子类的引用。

    Cat c = (Cat) a ;

    c.playGame() ;

注:一般情况下:向下转型使用不当会造成一个异常:

Throwable:

error:严重问题

Exception:编译时期异常:

运行时期异常:RuntimeException

运行时期异常:

ClassCastException:类转换异常:…… cannot be cast to ……

例:在测试类中

内存是狗

     Animal a = new Dog() ;

     //向下转型:还原成狗

     Dog d = (Dog)a ;

     //内存是猫

     a = new Cat() ;

     //还原成猫

     Cat c = (Cat) a ;

     //编译通过了

     Dog dd = (Dog)a ; //不能将内存猫转换为狗

二、抽象类

1.抽象类的概念:每一个动物的吃和睡的功能不一样,不应该把动物类定义为

一个具体类,而是给出一个声明(abstract)。

注:当一个类中如果有抽象功能(抽象方法)的时候,那么这个类一定要定义为抽象类。

问题:一个抽象类中可以有非抽象方法吗?

一个抽象类中可以抽象,也可以有非抽象的(判断题)

抽象类不能实例化:抽象类不能创建对象

一个抽象类如何进行实例化:

通过抽象类多态形式:父类的引用指向子类对象,通过子类进行初始化。

2.抽象类的子类的特点:

(1)抽象类的子类是抽象类,那么没有意义。子类一定是具体类。

最终使用的就是通过子类进行对象初始化的,如果子类都被抽象修饰了,那么也不能创建对象,所以没意义。

抽象类多态:

抽象类的类名 对象名= new 子类名() ;

强制子类必须重写当前抽象的父类中所有的抽象方法,还可以提高代码的维护性(里面继承关系保证)。

抽象方法:没有方法体的一个方法。

public abstract void eat() ;

注:异常:Cannot instantiatethe type Animal:抽象类不能实例化:instaceof

问题:

一个类中如果没有抽象方法,那么这个类可不可以定义为一个抽象类呢?

可以!为什么?不能让其创建对象。

3.abstract不能和哪些关键字共同使用?

    private和abstract不能共同使用

    final和abstract不能共同使用

    static和abstract不能共同使用

注:实际开发中:public 公共访问权限。

4.抽象类的成员特点

  成员变量:

      可以是变量也可以是自定义常量

      构造方法:

      抽象类可以有构造方法:包括有参构造和无参构造

      作用:通过抽象类多态的形式:让子类进行数据的初始化

  成员方法:

      可以有抽象方法,也可以有非抽象方法

5.抽象类的成员方法特性:

      抽象方法:强制子类必须要做到一件事情:方法重写(覆盖)。

      非抽象方法:由继承保证可以去提高代码的复用性。

三、 接口

1.接口的概念:

接口体现的是一种:扩展功能:比如:猫可以跳高(并不是所有的猫都具有跳高功能)。

如何表示接口:

    interface接口名{

              }

    接口里面的方法可以是非抽象方法吗?

    不可以,只能是抽象方法

    接口中不能有构造方法

2.接口的特点:不能实例化(不能直接创建对象)

接口如何实例化:

接口的子实现类:

    (1)接口的子实现类是抽象类,没有意义,子类都不能创建对象了;实际开发中用的就是子类的对象进行初始化。

    (2)接口的子实现类是非抽象类

       接口的实例化:就是通过子实现类对数据进行初始化

接口的子实现类和接口的关系:implements:

格式:

       class子实现类名   implments(实现) 接口名{

       }

3.接口成员的特点:

成员变量:

      只能是常量:存下默认修饰符:public static final (永远建议自己给出默认修饰符)

构造方法:

      接口是没有构造方法的

成员方法:

      接口中的成员方法默认修饰符:public abstract(永远建议自己给出默认修饰符)

4.类与类的关系:

继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承。

  类与接口的关系

实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口

       (class 子实现类名  enxtends Object implements 接口名1,接口名2…)

  接口与接口的关系

继承关系:extends,可以支持单继承,也可以多继承。

5.接口和抽象类的区别?

 (1)成员的区别:

成员变量:

抽象类:成员变量可以是常量,也可以是变量

接口:成员变量只能是一常量:存在默认修饰符:public static final

构造方法:

抽象类:可以有无参构造,有参构造方法

作用:通过子类进行数据初始化(通过子类创建对象)

接口:没有构造方法的

         成员方法的区别:

抽象类:可以有抽象方法,也可以有非抽象方法

接口:只能是抽象方法:存在默认修饰符:public abstract

 (2)关系的区别:

类与类的关系:

继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承。

类与接口的关系:

实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口。

(class 子实现类名  enxtends Object implements 接口名1,接口名2…)

接口与接口的关系

继承关系:extends,可以支持单继承,也可以多继承。

 (3)设计理念的区别:

抽象类:

体现的是一种"is a"的关系,存在继承关系!(抽象类多态)。

接口:

体现的是一种"like a"的关系,由于接口的一种扩展功能。

 

举例:

假如我们在开发一个系统时需要对员工类进行设计,程序员包含3个属性:姓名、工号(String)以及工资。(salary)

经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。(bonus)

请使用继承的思想设计出程序员类和经理类。要求类中提供必要的方法进行属性访问。

分析:

具体到抽象

程序员类:Programmer

成员变量:姓名,工号,工资

构造:有参,无参

成员方法:

setXXX()/getXXX(),work()

经理类:Manager

成员变量:姓名,工号,工资

额外的属性:奖金

构造:有参,无参

成员方法:

setXXX()/getXXX(),work()

抽取共性内容:独立的类:Employee(抽象类)      

普通员工和经理做的事情不一样,work();抽象方法

测试类:

代码的实现:从抽象到具体

员工类(抽象类)

普通员工(程序员类)

经理类

部分经理和程序员会游泳:

接口:  Swim

        游泳的抽象功能

 

package day8;

public abstract class Employee {

    private String name ;

    private String empId ;

    private int salary ;

    public Employee() {//Alt+Shift+s+c

        super();

    }

    public Employee(String name, String empId, int salary) {//Alt+Shift+s+o

        super();

        this.name = name;

        this.empId = empId;

        this.salary = salary;

    }

    public String getName() {//Alt+Shift+s+r

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public String getEmpId() {

        return empId;

    }

    public void setEmpId(String empId) {

        this.empId = empId;

    }

    public int getSalary() {

        return salary;

    }

    public void setSalary(int salary) {

        this.salary = salary;

    }

    public abstract void work() ;//抽象的功能   

}

 

 

package day8;

public class ProgrammerSwim extends Programmer implements Swimming {

    public ProgrammerSwim() {

        super();

        // TODO自动生成的构造函数存根

    }

    public ProgrammerSwim(String name, String empId, int salary) {

        super(name, empId, salary);

        // TODO自动生成的构造函数存根

    }

    @Override

    public void swim() {

        // TODO自动生成的方法存根

        System.out.println("程序员会游泳!");

    }

}

 

 

package day8;

public class Manager extends Employee {

    //奖金属性

    private int bonus;

    public Manager() {

        super();

        // TODO自动生成的构造函数存根

    }

    public Manager(String name, String empId, int salary,int bonus) {

        super(name, empId, salary);

        // TODO自动生成的构造函数存根

        this.bonus=bonus;

    }

    public int getBonus() {

        return bonus;

    }

    public void setBonus(int bonus) {

        this.bonus = bonus;

    }

    @Override

    public void work() {

        // TODO自动生成的方法存根

          System.out.println("经理类和客户谈需求!");

    }

}

 

 

package day8;

 //游泳接口

public interface Swimming {

    //抽象功能

        public abstract void swim();

}

 

 

package day8;

public class ProgrammerSwim extends Programmer implements Swimming {

    public ProgrammerSwim() {

        super();

        // TODO自动生成的构造函数存根

    }

    public ProgrammerSwim(String name, String empId, int salary) {

        super(name, empId, salary);

        // TODO自动生成的构造函数存根

    }

    @Override

    public void swim() {

        // TODO自动生成的方法存根

        System.out.println("程序员会游泳!");

    }

}

 

 

package day8;

public class ManagerSwim extends Manager implements Swimming {

    public ManagerSwim() {

        super();

        // TODO自动生成的构造函数存根

    }

    public ManagerSwim(String name, String empId, int salary, int bonus) {

        super(name, empId, salary, bonus);

        // TODO自动生成的构造函数存根

    }

    @Override

    public void swim() {

        // TODO自动生成的方法存根

        System.out.println("经理会游泳!");

    }

}

 

 

package day8;

public class Work {

    public static void main(String[] args){

        //测试程序员类

        Employee e = new Programmer();

        e.setName("Tom");

        e.setEmpId("abc123");

        e.setSalary(10000) ;

        System.out.println(e.getName()+" "+e.getEmpId()+"  "+e.getSalary());

        e.work();

        System.out.println("----------------------------");

        //方式2:构造方法进行赋值

        e= new Programmer("Ammy","abc1235",10000) ;

        System.out.println(e.getName()+" "+e.getEmpId()+"  "+e.getSalary());

        e.work();

        System.out.println("----------------------------");

        //测试经理类

        Employee e1 = new Manager("Jone", "abc12345", 20000, 5000);

        //System.out.println(e.getName()+"  "+e.getEmpId()+"  "+e.getSalary()+"  "+m.getBonus());无法解析m.getBonus()

        System.out.println(e.getName()+" "+e.getEmpId()+"  "+e.getSalary());

        e1.work();

        System.out.println("----------------------------");

        //如果一个类有特有属性:

        //创建经理类对象

        Manager m = new Manager() ;

        m.setName("Jone") ;

        m.setEmpId("abc12345");

        m.setSalary(20000);

        m.setBonus(5000);

        System.out.println(m.getName()+" "+m.getEmpId()+"  "+m.getSalary()+" "+m.getBonus());

        m.work();

        System.out.println("----------------------------");

        //实现接口的类是最具体的类,创建该类对象

                //经理游泳

               ManagerSwim ms = new ManagerSwim();

               ms.setName("Jone") ;

                ms.setEmpId("abc12345");

                ms.setSalary(20000);

                ms.setBonus(5000);

                System.out.println(m.getName()+" "+m.getEmpId()+"  "+m.getSalary()+" "+m.getBonus());

                m.work();

                ms.swim() ;

        System.out.println("----------------------------");

                //通过有参构造进行数据初始化

                ms = new ManagerSwim("Tom","abc12345", 20000, 5000) ;

                System.out.println(m.getName()+" "+m.getEmpId()+"  "+m.getSalary()+" "+m.getBonus());

                ms.work();

                ms.swim() ;

}

}