• Java基础之:OOP——抽象类


    Java基础之:OOP——抽象类

    当父类的某一些方法并不知道具体实现内容,但需要继承给子类让其在子类中实现时,就可以将这些方法声明为抽象方法,而有抽象方法的类就叫做抽象类。使用abstract来声明。

    简单案例

    package com.atguigu.abstract_;
    ​
    public class AbstractTest01 {
    ​
        public static void main(String[] args) {
            
            Cat cat = new Cat("小花猫");
            cat.eat();
        }
    ​
    }
    ​
    abstract class Animal { //抽象类
        private String name;
    ​
        public Animal(String name) {
            super();
            this.name = name;
        }
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
        
        //eat , 抽象方法
        public abstract void eat();
    }
    ​
    //解读
    //1. 当一个类继承了抽象类,就要把抽象类的所有抽象方法实现
    //2. 所谓方法实现,指的是 把方法体写出, 方法体是空,也可以.
    class Cat extends Animal { 
        public Cat(String name) {
            super(name);
            // TODO Auto-generated constructor stub
        }
        
        public void eat() {
            System.out.println(getName() +  " 爱吃 <・)))><<");
        }
    }

     

    语法说明

    抽象类:

       访问修饰符 abstract class 类名{}

    抽象方法:(抽象方法没有方法体!)

       访问修饰符 abstract 返回类型 方法名(参数列表);

     

    抽象类使用细节

    1. 抽象类不可以被实例化

    2. 抽象类不一定必须包含abstract方法,即抽象类不一定有抽象方法

    3. 一旦包含了抽象方法,则这个类必须声明为abstract抽象类

    4. abstract只能修饰类与方法,不可以修饰其他内容

    5. 抽象类可以有任意成员(因为抽象类还是类),比如:非抽象方法、构造器、静态属性等等

    6. 抽象方法不能有主体,即不能实现

    7. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

    8. 抽象方法不能使用privatefinalstatic来修饰,因为这些关键字都是和重写相违背的。

    package class_abstract;
    public class Abstract_Test {
    ​
        public static void main(String[] args) {
            //细节1:对于抽象类而言,不可以声明实例
    //      A a = new A(); //报错:Cannot instantiate the type A
            
            //细节5.但当抽象类的子类,创建了实例之后,仍然可以使用A类中满足访问权限的所有东西。(继承的特点)
            B b = new B();
            b.setName("小范");
            b.getName();
        }
    }
    ​
    ​
    abstract class A{   //细节3:由于A类中的hi()方法是被abstract修饰的(即抽象方法),所以A类也必须声明为抽象的
        
        private String name;    //细节5:抽象类中也可以有非抽象的东西,抽象类本质也是一个类
        
        public String getName() {   
            return name;
        }
        public void setName(String name) {  
            this.name = name;
        }
    ​
        public abstract void hi();  //细节6:对于抽象类而言,不可以有{},即方法体
        
        public abstract void hello();
    }
    ​
    class B extends A{
        //细节7:只要继承抽象类,则必须实现抽象类中所有的抽象方法。否则编译器报错:
        //The type B must implement the inherited abstract method A.hi()....
        
        @Override
        public void hi() {
            System.out.println("B----hi");
        }
        
        @Override
        public void hello() {
            System.out.println("B-----hello");
        }
    }
    ​
    abstract class C extends A{
        /*  细节7:
         * 若继承了抽象类,但子类本身也是一个抽象类,那么可以不用实现抽象类中的抽象方法
         * 因为对于抽象子类C而言,是允许抽象方法存在的。
         * 一旦有非抽象子类D,继承了子类C,那么D同样需要实现抽象子类C中的所有抽象方法
         */
    ​
    //  private abstract int age; //abstract 只能修饰方法与类,不可以修饰属性和其他的
        
        /*  细节8:
         * 对于抽象方法而言,不可以使用 private 或 final 修饰
         * 因为,抽象的本质就规范化父类的东西,让子类去实现父类已经写好的抽象方法
         * 而用private与final修饰的方法都不可以被子类继承,这就与抽象的作用冲突了
         */
    //  private abstract void m1();
        
        /*  细节8:
         * 对于抽象方法而言,也不可以使用 static 修饰
         * 因为,static修饰之后,方法不再是成员方法了,而是类方法。
         * 而子类是无法继承类方法的,所以static与abstract的作用也是产生冲突了。
         */
    //  public static abstract void m2();
    }
    ​
    class D extends C{
        @Override
        public void hi() {
            System.out.println("D-----hi");
        }
    ​
        @Override
        public void hello() {
            System.out.println("D-----hello");
        }
    }

     

    多态在抽象类中的实现

    简单案例

    package class_abstract;
    ​
    public class AbstractPolyArray {
    ​
        public static void main(String[] args) {
            //抽象类不可以实例化,但可以使用多态数组
            Animal[] animal = new Animal[2];
            
            animal[0] = new Dog("小黑狗");
            animal[1] = new Cat("小花猫");
            
            //多态数组的使用
            for (int i = 0; i < animal.length; i++) {
                show(animal[i]);
            }
        }
        
        //这里不用担心会传入一个Animal类型的实例,因为Animal不能实例化
        //编译器不会通过,所以只会传入Animal的子类实例
        public static void show(Animal a) {
            a.eat();    //多态的使用
            
            if(a instanceof Dog) {
                ((Dog)a).watch();
            }else if(a instanceof Cat) {
                ((Cat)a).catchMouse();
            }
        }
    }
    ​
    abstract class Animal{
        private String name;
    ​
        public Animal(String name) {
            super();
            this.name = name;
        }
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
        
        //动物都有eat的动作,但我们并不知道每一个动物具体怎么样eat
        //所以这里通过抽象提供了eat方法,需要子类来实现
        public abstract void eat();
    }
    ​
    class Dog extends Animal{
        public Dog(String name) {
            super(name);
        }
    ​
        @Override
        public void eat() {
            System.out.println(getName() + "啃骨头......");
        }
        
        public void watch() {
            System.out.println(getName() + "守家.....");
        }
    }
    ​
    class Cat extends Animal{
        public Cat(String name) {
            super(name);
        }
    ​
        @Override
        public void eat() {
            System.out.println(getName() + "吃鱼......");
        }
        
        public void catchMouse(){
            System.out.println(getName() + "抓老鼠.....");
        }
    }

    程序输出

    小黑狗啃骨头......

    小黑狗守家.....

    小花猫吃鱼......

    小花猫抓老鼠.....

     

    抽象类简单应用案例

    编写一个Employee类,声明为抽象类,包含如下三个属性:name,id,salary。

    • 提供必要的构造器和抽象方法:work()。

    • 请使用继承的思想,设计CommonEmployee类和Manager类,

    • 对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。

    • 要求类中提供必要的方法进行属性访问,实现work(),提示 "经理/普通员工 名字 工作中...."

    package class_abstract;
    public class Abstract_ClassWork {
        public static void main(String[] args) {
            Employee[] em = new Employee[2];
            em[0] = new Manager("小黄", 1001, 5000, 1120);
            em[1] = new CommonEmployee("小范", 1002, 3000);
            
            System.out.println(em[0].toString());
            em[0].work();
            
            System.out.println(em[1].toString());
            em[1].work();
        }
    }
    ​
    abstract class Employee{
        private String name;
        private int id;
        private double salary;
        public Employee(String name, int id, double salary) {
            this.name = name;
            this.id = id;
            this.salary = salary;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public double getSalary() {
            return salary;
        }
        public void setSalary(double salary) {
            this.salary = salary;
        }
        
        public abstract void work();
        @Override
        public String toString() {
            return "name=" + name + ", id=" + id + ", salary=" + salary;
        }
    }
    ​
    //对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。
    class Manager extends Employee{
        private double bonus;
        
        public Manager(String name, int id, double salary, double bonus) {
            super(name, id, salary);
            this.bonus = bonus;
        }
    ​
        public double getBonus() {
            return bonus;
        }
    ​
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
    ​
        //"经理/普通员工 名字 工作中...."  
        @Override
        public void work() {
            System.out.println("经理" + getName() + "工作中......");
        }
        
        @Override
        public String toString() {
            return super.toString() + ",bonus =" + bonus;
        }
    }
    ​
    class CommonEmployee extends Employee{
        public CommonEmployee(String name, int id, double salary) {
            super(name, id, salary);
            // TODO Auto-generated constructor stub
        }
    ​
        //"经理/普通员工 名字 工作中...."  
        @Override
        public void work() {
            System.out.println("普通员工" + getName() + "工作中......");
        }
    }

    程序输出

    name=小黄, id=1001, salary=5000.0,bonus =1120.0

    经理小黄工作中......

    name=小范, id=1002, salary=3000.0

    普通员工小范工作中......

     

    抽象类最佳实践-模板设计模式

    抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

    1) 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

    2) 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式

    简单案例

    1) 设计一个抽象类(Template),能完成如下功能:

    2) 编写方法caleTime() ,可以计算某段代码的耗时时间

    3) 编写抽象方法code()

    4) 编写一个子类Sub,继承抽象类Template,并实现code方法。

    package class_abstract;
    public class Abstract_Template {
        public static void main(String[] args) {
            Template sub = new Sub();
            sub.caleTimes(); //实际是调用了Template中的caleTimes方法
            
            Template subStringB = new SubStringB();
            subStringB.caleTimes();
            
            //这里可以看到 StringBuffer在拼接字符串时,远远优于String拼接的效率
        }
    }
    ​
    abstract class Template{ //抽象类
        public abstract void code(); //抽象方法
        public void caleTimes(){ //  统计耗时多久是确定 
            //统计当前时间距离 1970-1-1 0:0:0 的时间差,单位ms
            long start = System.currentTimeMillis();
            code(); //这里的code在调用时,就是指向子类中已经重写实现了的code
            long end = System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
        }
    }
    ​
    class Sub extends Template{
        
        @Override
        public void code() {
            String x = "";
            for(int i = 0;i < 10000 ; i++) {    //拼接1W个hello 看处理时间
                x += "hello" + i;
            }
        }
    }
    ​
    class SubStringB extends Template{
        @Override
        public void code() {
            StringBuffer stringBuffer = new StringBuffer();
            for(int i = 0;i < 10000 ; i++) {    //拼接1W个hello 看处理时间
                stringBuffer.append("hello" + i);
            }
        }
    }

    程序输出

    耗时:606

    耗时:2

     

     

     

     

  • 相关阅读:
    图片自动播放
    选项卡切换
    jquery实现全选、反选、不选
    JQuery $()后面的括号里的内容什么时候加引号,什么时候不加
    ajax跨域jsonp
    加班与效率
    提问的智慧
    程序员要勇于说不
    编程从业五年的十四条经验,句句朴实
    成为高效程序员的7个重要习惯
  • 原文地址:https://www.cnblogs.com/SongHai/p/14140516.html
Copyright © 2020-2023  润新知