努力,拼搏,奋发,有为

——积累,传递,分享,进步!

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

6.7 抽象类

6.8 接口


6.7 抽象类

6.7.1 抽象类概述

(1)抽象定义

       •抽象就是从多个事物中将共性的本质的内容抽取出来。

       •例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。

(2)抽象类:

       •Java中可以定义没有方法体方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法就是抽象类

(3)抽象方法的由来

       •多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法

      •例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

abstract class Demo //抽象类
{
    //从多个事物中将共性的,本质的内容抽取出来。
    abstract void show(); //没有方法体,方法体由继承的子类实现,即:只有功能声明,没有功能主体的方法
}

class DemoA extends Demo
{
    void show()
    {
        System.out.println("demoa showA");
    }
}

class DemoB extends Demo
{
    void show()
    {
        System.out.println("demoa showB");
    }
}

class AbstractDemo 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello World!");
    }
}

6.7.2 抽象类的特点

(1)抽象类抽象方法必须用abstract关键字来修饰。

(2)抽象方法只有方法声明没有方法体,定义在抽象类中。

       •格式:修饰符 abstract 返回值类型 函数名(参数列表) ;

(3)抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:

       •抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。

       •而且抽象类即使创建了对象,调用抽象方法也没有意义。

(4)抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类

 

6.7.3 抽象类相关问题

(1)抽象类一定是个父类吗?

class A
{

}
abstract class B extends A //是C的父类,所以是父类!
{
         abstract void show();
}
class C extends B
{

}

(2)抽象类中是否有构造方法?

         有的,用于给子类对象初始化.

         抽象类和一般类:

         相同点:都是在描述事物,里面都可以定义属性和行为。

         不同点: 抽象类里面可以定义抽象方法,一般类不可以。

                         抽象类不能被实例化,一般类可以。

abstract class Demo //抽象类
{
    
    abstract void show(); 
}

class DemoA extends Demo
{
    DemoA()
    {
         super();//隐式的存在构造方法
    }
    void show()
    {
        System.out.println("demoa showA");
    }
}

class DemoB extends Demo
{
    void show()
    {
        System.out.println("demoa showB");
    }
}

(3)抽象关键字abstract不可以和哪些关键字共存?

       final 、private 、static

(4)抽象类中可不可以不定义抽象方法?

       可以。存在的意义:不让该类实例化。

 

6.7.4 抽象类举例代码讲解

(1)雇员示例:

       •需求:公司中程序员有姓名,工号,薪水,工作内容。

       •项目经理除了有姓名,工号,薪水,还有奖金,工作内容。

       •对给出需求进行数据建模。

abstract class Employee //抽象类
{
    private String name;
    private String id;
    private double pay;
    public Programmer(String name,String id,double pay)
    {
        this.name = name;
        this.id = id;
        this.pay = pay;

    }
    public abstract void work();
}

class Programmer extends Employee
{
    

    public Programmer(String name,String id,double pay)
    {
        //super();//error,父类中没有空参数的构造函数。
        super(name,id,pay);//传入参数初始化
    }
    public void work()
    {
        System.out.println("code...");
    }
}

class Manager extends Employee
{
    
    private double bonus;

    public Programmer(String name,String id,double pay,double bonus)
    {
        super(name,id,pay);//共性
        this.bonus = bonus; //个性

    }
    public void work()
    {
        System.out.println("code...");
    }
}

class AbstractDemo 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello World!");
    }
}

6.8 接口

(1)格式:  interface 接口名{}

(2)接口中的成员修饰符是固定的。

         •成员常量:public static final

         •成员函数:public abstract

         •发现接口中的成员都是public的。

/*
abstract class Demo
{
    abstract void show();
    abstract void show2();
}*/
/*1. 当抽象类中的抽象方法都是抽象时,这时候可以用另一种表现形式:接口。其实:接口就是一个特殊的抽象类。
  2. 接口中最常见成员:全局常量、抽象方法。
  3. 接口中的成员都是公共的。
  4. 如何使用接口? 需要子类覆盖接口中的抽象方法,该类才可以实例化,否则该类还是一个抽象类。
  5. 类与类是继承关系、类与接口是实现关系。
6. 接口中没有构造函数
*/
interface Demo
{
    //接口中最常见成员
    public static final int NUM =3; //全局常量
    public abstract void show(); //抽象方法
    //接口中的成员都是公共的。
}
class SubDemo implements Demo
{
    public void show(){}
}

class InterfaceDemo 
{
    public static void main(String[] args) 
    {
        Subdemo d = new SubDemo();
        System.out.println(d.NUM);
        System.out.println(SubDemo.NUM);
        System.out.println(Demo.NUM); //都可以访问
    }
}

  (3)接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。

/*
接口的好处:它可以解决多继承的问题,它将多继承改良成了多实现.
因为父类中的方法有主体,接口中的方法没有主体,不会发生调用不确定性的情况。
一个类可以实现多个接口
*/
interface A
{
    //void show1();
    void show();
}
interface B
{
    //void show2();
    void show();
}
class C implements A,B //多实现,扩展了C类的功能
{
    //public void show1(){}
    //public void show2(){}
    public void show(){}
}
/*
一个类在继承一个类的同时可以实现多个接口
接口的出现避免了单继承的局限性。
*/
class Fu
{
    public void show(){}
}
interface Inter
{
    public void method();
}
class Zi extends Fu implements Inter//在继承的基础上,扩展子类功能
{
    public void method(){}//实现接口

}
class InterfaceDemo 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello word");
    }
}

/*
1. 接口与接口的关系是继承
2. 接口之间存在着多继承
*/
interface A 
{
}
interface B extends A 
{
}
interface c extends A, B //多继承
{
}

6.8.1 接口的思想(特点)

(1)接口是对外暴露的规则

(2)接口是程序的功能扩展

(3)接口的出现降低耦合性

(4)接口可以用来多实现

(5)接口之间是实现关系,而且可以继承一个的同时实现多个接口

(6)接口接口之间可以有继承关系

 

6.8.2 接口与抽象类

共 性:

都是不断抽取出来的抽象的概念

区别 1:

抽象类体现继承关系,一个类只能单继承

接口体现实现关系,一个类可以多实现

区别 2

抽象类是继承,是 "is a "关系

接口是实现,是 "like a"关系

区别 3:

抽象类中可以定义非抽象方法,供子类直接使用

接口的方法都是抽象,接口中的成员都有固定修饰符

开发时,是定义抽象类好呢?还是定义接口好呢!?

要根据不同的问题领域进行分析 

//犬按功能分类:导盲犬、搜爆犬
//抽象类:定义了一类事物的基本功能
//接口:定义了事物的扩展功能

abstract class 犬
{
    abstract void 训练();
}
interface class 搜爆able
{
    abstract void 搜爆();
}
class 搜爆犬 extendsimplements 搜爆able
{
    public void 训练()
    {

    }
    public void 搜爆()
    {

    }
}

 

6.9 多态

(1)定义:某一类事物的多种存在形态。

          •例:动物中猫,狗。

(2)猫这个对象对应的类型是猫类型

          •猫 x = new 猫();

(3)同时猫也是动物中的一种,也可以把猫称为动物。

          •动物 y = new 猫();

          •动物是猫和狗具体事物中抽取出来的父类型。

          •父类型引用指向了子类对象。

 

6.9.1 程序中体现

 父类或者接口引用指向或者接收自己的子类对象

(1)好处和作用:  多态的存在提高了程序的扩展性后期可维护性

(2)前提:  •需要存在继承或者实现关系

                   •要有覆盖操作

/*
对象的多态性
class 动物
{

}
class 猫
{
}
class 狗
{
}
猫 X = new 猫();

动物 X = new 猫();对象多态性
猫这类事物具备猫的形态,又具备动物的形态,这就是对象的多态性。

在代码中的体现:父类或者接口的引用指向其子类的对象。
多态的好处;多态的存在提高了程序的扩展性和后期可维护性,前期定义的代码可以使用后期的内容
多态的弊端:前期定义的内容不能使用(调用)后期子类的特有内容
多态的前提:1.必须有关系:继承、实现。
            2.要有覆盖
*/
abstract class Animal
{
    abstract void eat();
}
class Dog extends Animal
{
    void eat()
    {
         System.out.println("啃骨头");
    }
    void lookHome()
    {
         System.out.println("看家");
    }
}
class Cat extends Animal
{
    void eat()
    {
         System.out.println("吃鱼");
    }
    void CatchMouse()
    {
         System.out.println("抓老鼠");
    }
}
class  DouTaiDemo
{
    public static void main(String[] args)
    {
        //Cat c = new Cat();
        //method(c);
        method(new Cat());//统一调用
          method(new Dog());
    }

    public static void method(Animal a) //多态,提高代码复用性。Animal父类作为引用
    {
       if(a instanceof Cat)//instanceof  用于判断对象的类型
    {
       a.CatchMouse();
    } 
    a.eat();
    }
}

 

//转型
class 毕姥爷
{
    void 讲课()
    {
        System.out.println("管理");
    }
    void 钓鱼()
    {
        System.out.println("钓鱼");
    }
}
class 毕老师
{
    void 讲课()
    {
        System.out.println("Java");
    }
    void 看电影()
    {
        System.out.println("看电影");
    }
}
class  DuoTaiDemo
{
    public static void main(String[] args) 
    {
        //毕老师 X= new 毕老师();
        //x.讲课();
        //x.看电影();
        
        //向上转型,限制对特有功能的访问
        毕姥爷 x= new 毕老师(); 
        x.讲课();// JAVA,重载了父类
        x.钓鱼();// 继承了父类
        x.看电影;//不可以

        //向下转型,目的是为了使用子类中的特有方法。
        毕老师 a = (毕老师)x;
        a.看电影;//可以
        
        //注意:对于转型,自始至终都是子类对象在做着类型的变化
        //Animal al = new Dog(); 错误
        //Cat cl = (Cat)al;
    }
}

6.9.2 多态的特点

(1)成员函数

        •编译时:要查看引用变量所属的类中是否有所调用的成员。

        •在运行时:要查看对象所属的类中是否有所调用的成员。

(2)成员变量

        •只看引用变量所属的类。

 

Java中的上帝:Object

开发中经常需要重写的有:equals()、getClass()、hashCode()、toString()

/*
JAVA 中的上帝:Object类
1. Object 初始化
2. Object 比较 equals()
3. getClass(); 获取类文件,返回Class对象
4. hashCode()
5. toString()
   既然Object中有提供对象转成字符串的方式,
   直接沿用使用即可,但是Person类中想定义自己对应的字符串内容
   使用覆盖。
*/
class Person // extends Object
{
    //1. Object 初始化
    Person()//隐式存在
    {
        super();
    }

    //2. Object 比较 equals()
    private int age;
    Person(int age)
    {
        this.age = age;
    }
    //比较同龄人的方法
    //比较对象是否相同的功能父类中已经定义
    //子类中要使用,但是想要按照自己的内容来完成判断是否相同的依据。就可以使用覆盖操作
    //覆盖父类中的equals方法。建立Person类自己的比较多些是否相同的依据。
    public boolean equals(Object obj) 
    {
        return this.age = p.age //直接这样比较,错误,p已经向上转型,p已经为Object类型

        if(!(obj instanceof Person))
        {
            return false;//太菜鸟
            throw new ClassCastException("类型错误");//专业的写法
        }else{
            Person p = (Person)obj;
            return this.age = obj.age;
        }
    }

    /*5. 既然Object中有提供对象转成字符串的方式,
   直接沿用使用即可,但是Person类中想定义自己对应的字符串内容
   使用覆盖。*/
   public String toString(){
       return "Persong[age="+age+"]";
   }


}
class ObjectDemo
{
    public static void main(String[] args)
    {
        Person p1 = new Person();
        Person p2 = new Person();
        System.out.println(p1==p2);//false
        System.out.println(p1.equals(p2));//false

        Person p3=p1;
        System.out.println(p1==p3);//true
        System.out.println(p1.equals(p3));//true

        Person p4 = new Person(21);
        Person p5 = new Person(23);
        System.out.println(p4==p5);//false
        System.out.println(p4.equals(p5));//true

        //3. getClass(); 获取类文件,返回Class对象
        Class c1 = p4.getClass();//获取p4对象所属的字节码文件对象
        Class c2 = p5.getClass();//在内存中,字节码只有一份,对象有多个

        System.out.println(c1.equals(c2));//true
        System.out.println(c1.getName());//Person

        //4. hashCode()
        System.out.println(p1.hashCode());//3753023
        //toString(); 将对象转成字符串

        //toString()实现方式:getClass().getName() + '@' + Integer.toHexString(hashCode())
        System.out.println(p1.toString());//Person@39443f; 在println内自动加上toString()
        System.out.println(p1);//Person@39443f
        System.out.println(p1.getClass().getName()+"#"+Integer.toHexString(p1.hashCode()));//Person@39443f

        Person p = p1.toString();//类型不匹配

    }
}

 

6.9.3 内部类

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

(2)访问特点:

       •内部类可以直接访问外部类中的成员,包括私有成员。

       •而外部类要访问内部类中的成员必须要建立内部类的对象。

/*
内部类。
    定义在类的内部,也叫内置类,嵌套类。

访问方式:
    内部类可以直接访问外部类中的成员。
    外部类需要创建内部类的对象访问内部类中的成员。

在描述事物时,内部还有具体的事物需要被描述。这时就可以用内部类来描述。
因为该内部事物访问到了外部事物的内容。

*/
class Outer
{
    static int num = 4;
    /*static*/ class Inner//内部类
    {
        //static final int x= 4;
        /*static*/ void show()//静态方法只能定义在静态的内部类中。
        {
            System.out.println("Inner show run..."+num);
        }
    }
    
    public void method()
    {
        //创建内部类的对象。访问内部类中的成员。
        Inner in = new Inner();
        in.show();
    }

}

class InnerClassDemo 
{
    public static void main(String[] args) 
    {
//        Outer out = new Outer();

        //直接创建内部类对象。
//        Outer.Inner in = new Outer().new Inner();
//        in.show();
        
        //当内部类是静态时。
//        Outer.Inner in = new Outer.Inner();
//        in.show();

        //当内部类静态,访问其中的静态方法时。
//        Outer.Inner.show();

    }
}

 

/*
内部类为什么就可以直接访问外部类中的成员呢?

内部类持有了一个外部类的引用 外部类名.this 
*/


class Outer
{
    private int num = 7;
    class Inner
    {
        //int num = 8;

        void show()
        {
            //int num = 9;
            System.out.println(num);
        }
    }
    public void method()
    {
        new Inner().show();
    }
}
class InnerClassDemo2 
{
    public static void main(String[] args) 
    {
//        new Outer().method();
        InnerClassDemo2.Inner in = new InnerClassDemo2().new Inner();
        in.function();
    }

    class Inner
    {
        void function()
        {
            System.out.println("function run");
        }
    }
}

 

6.9.4 内部类的位置

(1)内部类定义在成员位置上

        •可以被private static成员修饰符修饰。

        •被static修饰的内部类只能访问外部类中的静态成员。

(2)内部类定义在局部位置上

        •也可以直接访问外部类中的成员。

        •同时可以访问所在局部中的局部变量,但必须是被final修饰的。

class Outer
{
    private int num = 5;
    private Object obj;
    public void method(int x)
    {
        final int y = 4;

        class Inner extends Object//内部类定义在了局部位置上。只能访问局部中被final修饰的局部变量。
        {
            void show()
            {
                System.out.println("Inner show .."+y);
            }
            public String toString()
            {
                return "inner..."+y;
            }
        }

//        Inner in = new Inner();
//        in.show();

        obj = new Inner();
    }
    public void func()
    {
        System.out.println(obj.toString());
    }
}
class InnerClassDemo3 
{
    public static void main(String[] args) 
    {
        Outer out = new  Outer();
        out.method(2);
        out.func();
    }
}

6.9.5 匿名内部类

(1)就是内部类的简化写法。

(2)前提:     •内部类可以继承或实现一个外部类或者接口。

(3)格式为:  •new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}

(4)简单理解: •就是建立一个带内容的外部类或者接口的子类匿名对象。

/*
匿名内部类:内部类简化形式。
    前提:内部类必须继承类或者实现接口。

格式;
new 父类或者接口()
*/

abstract class Demo
{
    abstract void show();
    abstract void show2();
}

class Outer
{
    int num =9;
    /*
    class Inner extends Demo
    {
        void show()
        {
            System.out.println("inner show .."+num);
        }
    }
    */
    
    public void function()
    {
        //new Inner().show();
        Demo d = new Demo()//匿名内部类:就是一个Demo类的匿名子类对象。
        {
            void show()
            {
                System.out.println("inner show .."+num);
            }
            void show2()
            {
                System.out.println("inner show2 .."+num);
            }
        };
        d.show();
        d.show2();    
    }
}

class InnerClassDemo4 
{
    public static void main(String[] args) 
    {
        Outer out = new Outer();
        out.function();
    }
}
class Outer
{
    void method()
    {
        new Object()
        {
            void show()
            {
                System.out.println("show ");
            }
        }.show();

        Object obj = new Object()
        {
            void show()
            {
                System.out.println("show ");
            }
        };
//        obj.show();//error.
    }
}

interface Inter
{
    void show();
}

class Test
{
    //中的代码补足,使用匿名内部类的方式。
    static Inter method()
    {
        return new Inter()
        {
            public void show(){}
        };
    }
}

class InnerClassDemo5 
{
    public static void main(String[] args) 
    {
//        Outer out = new Outer();
//        out.method();
        Test.method().show();

        /*
        Test.method():Test类中有一个名为method的方法,而且是静态的。
        Test.method().show():调用了method()方法后,还能调用show,说明method()方法运行完返回一个对象。
        而且该对象是Inter类型。
        */


    }
}
posted on 2013-09-26 21:24  孤剑独行  阅读(289)  评论(0)    收藏  举报