Java 抽象类与oop三大特征

  面向对象主要有三大特性:继承和多态、封装

 一、抽象类

  在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:

abstract void fun();

  抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。抽象类的声明格式如下:

public  abstract class ClassName {
    abstract void fun();
}

  下面要注意一个问题:在《JAVA编程思想》一书中,将抽象类定义为“包含抽象方法的类”,但是后面发现如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。个人觉得这个属于钻牛角尖的问题吧,因为如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

  在面向对象领域由于抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能实例化的。同时,抽象类体现了数据抽象的思想,是实现多态的一种机制。它定义了一组抽象的方法,至于这组抽象方法的具体表现形式由派生类来实现。同时抽象类提供了继承的概念,它的出发点就是为了继承,否则它没有存在的任何意义。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

  使用抽象类时应注意一下几点:

  1、包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法

  2、如果一个非抽象类继承了抽象类,则非抽象类必须实现抽象父类的所有抽象方法

   3、子类中的抽象方法不能与父类的抽象方法同名

   4、抽象类不能创建实体,因为抽象类存在抽象方法,而抽象方法没有实体,创建对象后,抽象对象调用抽象方法是没有意义的

  5、抽象类中一定有构造函数。主要为了初始化抽象类中的属性。通常由子类实现

  6、final和abstract是否可以同时修饰一个方法,因为用final修饰后,修饰类代表不可以继承,修饰方法不可重写,abstract修饰类就是用来被继承的,修饰方法就是用来被重写的

    abstract不能与private修饰同一个方法,因为privte成员对外是不可见的,只能在本类中使用,这样子类就无法重写抽象方法

    abstract不能与static修饰同一个方法,static修饰的方法可以用类名调用,而对于abstract修饰的方法没有具体的方法实现,所有不能直接调用

  

  抽象类与接口

  接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象,而没有具体的实现,接口本身不是类。同时实现该接口的实现类必须要实现该接口的所有方法,通过使用implements关键字,他表示该类在遵循某个或某组特定的接口,同时也表示着“interface只是它的外貌,但是现在需要声明它是如何工作的”。

接口是抽象类的延伸,java为了了保证数据安全是不能多重继承的,也就是说继承只能存在一个父类,但是接口不同,一个类可以同时实现多个接口,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多重继承的缺陷,但是推荐继承和接口共同使用,因为这样既可以保证数据安全性又可以实现多重继承。接口声明形式如下:

public  interface InterfaceName {

}

  在使用接口过程中需要注意如下几个问题:

  1、一个Interface的方所有法访问权限自动被声明为public。确切的说只能为public,当然你可以显示的声明为protected、private,但是编译会出错!

2、接口中定义的所有变量默认是public static final的,即静态常量既然是常量,那么定义的时候必须赋值,可以通过接口名直接访问:ImplementClass.name。

3、接口中定义的方法不能有方法体。接口中定义的方法默认添加public abstract

   4、有抽象函数的不一定是抽象类,也可以是接口类。

   5、由于接口中的方法默认都是抽象的,所以接口不能被实例化。

   6、类实现接口通过implements实现,实现接口的非抽象类必须要实现该接口的所有方法,抽象类可以不用实现。

   7、如果实现类要访问接口中的成员,不能使用super关键字。因为两者之间没有显示的继承关系,况且接口中的成员成员属性是静态的

   8、接口没有构造方法。

9、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。

    例如:if(anObject instanceof Comparable){}。

10、在实现多接口的时候一定要避免方法名的重复。

  抽象类和接口的区别

  1、语法层面上的区别

    1)抽象类可以提供成员方法的实现细节(即普通方法),而接口中只能存在public abstract 方法;

    2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

    3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

    4)一个类只能继承一个抽象类,而一个类却可以实现多个接口,Java是单继承,多实现。

  2、设计层面上的区别

    1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

    2)抽象类所体现的是一种继承关系,而继承是一个 "is-a"的关系,而 接口 实现则是 "has-a"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系。比如:将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),对于不同种类的鸟直接继承Bird类即可,而鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

    3)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

二、继承

  继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。

  继承的特点:

  1、子类拥有父类非private的属性和方法

2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展

3、子类可以用自己的方式实现父类的方法(方法重写)

   4、构造函数不能被继承

   5、继承使用extends关键字实现

  重写overriding

  1. 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖;
  2. 若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。那么子类的对象如果调用该函数,一定调用的是重写过后的函数。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类;
  3. 子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类,不能返回比父类更大的数据类型;
  4. 子类函数的访问修饰权限不能少于父类的;
  5. 子类无法重写父类的private方法

 子类对象查找属性或方法时的原则:就近原则。

  如果子类的对象调用方法,默认先使用this进行查找,如果当前对象没有找到属性或方法,找当前对象中维护的super关键字指向的对象,如果还没有找到编译报错,找到直接调用。

重载 overloading

  1. 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载是一个类中多态性的一种表现;
  2. Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性;
  3. 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准;
  4. 所有的重载函数必须在同一个类中

三、多态

  1. 多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
  2. 实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
  3. 多态的作用:消除类型之间的耦合关系。
  4. 现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。

  多态存在的三个必要条件

    1. 要有继承或实现,即父类引用变量指向了子类的对象或父类引用接受自己的子类对象;
    2. 要有重写;
    3. 父类引用指向子类对象。

  多态弊端: 提高扩展性,但是只能使用父类引用指向父类成员。

  注意:

  在多态的情况下,字符类存在同名的成员(成员变量和成员函数)时,访问的是父类的成员,只有是同名的非静态成员函数时,才访问子类的成员函数;

  多态用于形参类型时,可以接受多个类型的数据;

  多态用于返回类型时,可以返回多个类型的数据,使用了多态的方法,定义的变量类型要与返回的类型一致。

以下面例子来分析多态

public class A {
    public String show(D obj) {
        return ("A and D");
    }  

    public String show(A obj) {
        return ("A and A");
    }   

}  

public class B extends A{
    public String show(B obj){
        return ("B and B");
    }  

    public String show(A obj){
        return ("B and A");
    }
}  

public class C extends B{  

}  

public class D extends B{  

}  

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();  

        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));
    }
}  

输出结果为:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D  

首先我们先看一句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被调用的方法必须是被子类重写的方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

  对于前半句的意思就是:当父类变量引用子类对象时,在调用成员函数时,应该调用向子类的成员函数,但前提是此函数时被子类重写的函数。

A B C D的继承关系如下:

分析:

  对于1和2,B和C属于A的子类,调用a1.show(b),a1.show(b),可以找到A.show(A boj),因为多态情况下,父类做形参时,可以接受其子类的实参。

  对于3,直接就可以找到A.show(D odj)。

  对于4,本来由于a2引用的是其子类B的一个对象,因此调用的成员函数应为B.show(B obj),但是由于B.show(B obj)不是重写的函数,因此不会调用B.show(B obj)。故将按照优先级,先看this.show(O),而类A里面没有找到show(B obj)方法,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,且B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(A obj),输出为"B and A”。

  对于5,同样将按照优先级,先看this.show(O),而类A里面没有找到show(C obj)方法,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为C,由于A是C的超类,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,且B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(A obj),输出为"B and A”。

  对于6,同样将按照优先级,先看this.show(O),而类A里面刚好找到了show(D obj)方法,输出为"D and A”.

  对于7,可以直接调用this.show(O)。

  对于8,同样将按照优先级,先看this.show(O),而类B里面没有找到show(C obj)方法,于是到B的super(超类)找,而类A里面没有找到show(C obj)方法,因此转到第三优先级this.show((super)O),this仍然是b,这里O为C,由于B是C的超类,因此它到类B里面找show(B obj)的方法,因此输出为"B and B”。

   对于9,同样将按照优先级,先看this.show(O),而类B里面没有找到show(D obj)方法,于是到B的super(超类)找,而类A里面找到了show(D obj)方法,因此输出为"A and D”。

四、封装

  封装是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节(当然也无从知道),但可以通过该对象对外的提供的接口来访问该对象。

  使用封装有四大好处:

1、良好的封装能够减少耦合。

2、类内部的结构可以自由修改。

3、可以对成员进行更精确的控制。

4、隐藏信息,实现细节。

时间: 2024-08-07 03:43:30

Java 抽象类与oop三大特征的相关文章

core java 5~6(OOP & 高级语言特征)

MODULE 5 OOP 面向对象程序设计--------------------------------------------------------Object Oriented Programming 缩写 Class类/Object对象--------------------万物皆对象 类:具有相同属性和行为的一组对象的组合 class 类名{ 属性 构造器 方法 }对象:类的一个实例 new 类名 OOP三大特性1.封装Encapsulation 封装的目的:实现信息的隐藏 1)实现

Java面向对象编程三大特征 - 多态

Java面向对象编程三大特征 - 多态 本文关键字:Java.面向对象.三大特征.多态多态是面向对象编程的三大特征之一,是面向对象思想的终极体现之一.在理解多态之前需要先掌握继承.重写.父类引用指向子类对象的相关概念,对继承还没有完全明白的同学可进传送门:Java面向对象编程三大特征 - 继承. 一.抽象类 在继承中,我们已经了解了子父类的关系以及如何对子父类进行设计,如果已经存在多个实体类,再去定义父类其实是不断的抽取公共重合部分的过程,如果有需要将会产生多重继承关系.在抽取整理的过程中,除了

Java面向对象编程三大特征 - 封装

Java面向对象编程三大特征 - 封装 本文关键字:Java.面向对象.三大特征.封装封装是面向对象编程中的三大特征之一,在对封装性进行解释时我们有必要先了解一些面向对象的思想,以及相关的概念.当我们想要去描述一系列的关系时我们要用到的最基本结构就是类,其中存在着成员变量和方法,用于记录属性和表达行为,相关知识请进传送门:Java中的基本操作单元 - 类和对象. 一.名词解读 为了解释封装的概念和作用,需要先来了解一下几个相关的概念,这有助于我们接下来的理解. 1. 权限修饰符 当我们在一个类中

聊一聊面向对象的三大特征

学习Java语言程序设计也有一段时间了.现在我想对封装.继承和多态,在Java中面向对象的三大特征,总结一下我的理解,不妥当的地方望大家包涵.  封装.给我的感觉封装就是一个包装,一个代码是否健壮,与用不用封装有很大的关系,封装就像是包裹一个礼物,不仅让礼物看起来更加精美,而且还完善了内容.请看代码: class Person {     private String name;     private int age;     public void say() {         Syste

JAVA的三大特征 封装继承多态- 简单总结

简单总结一下 封装-即从很多类的抽取相同的代码 写在一个类里. 好处是 代码的重用,安全. 继承-减少代码的书写. 其好处也是 代码的重用. 多态- 把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化. 总的来说还是接口的重用. 那么总结一下,JAVA的三大特征 其好处 就是代码与接口的重用. 封装可以隐藏实现细节,使得代码模块化: 继承可以扩展已存在的代码模块(类): 它们的目的都是为了——代码重用. 而多态则是为了实现另一个目

Java面向对象的三大特征

Java面向对象的三大特征: 封装.继承.多态 封装和继承几乎都是为多态而准备的 一.      封装 首先,属性能够描述事物的特征,方法能够描述事物的动作.封装就是把同一类事物的共性(包括属性和方法)归到同一类中,方便使用. 封装:封装也称信息隐藏,是指利用抽象数据类型把数据和基于数据的操作封装起来,使其成为一个不可分割的整体,数据隐藏在抽象数据内部,尽可能的隐藏数据细节,只保留一些接口使其与外界发生联系.也就是说用户无需知道内部的数据和方法的具体实现细节,只需根据留在外部的接口进行操作就行.

Java三大特征之继承(二)

在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句话中最引人注目的是“复用代码”,尽可能的复用代码使我们程序员一直在追求的,现在我来介绍一种复用代码的方式,也是java三大特性之一---继承. 在讲解之前先看一个例子:这个例子还是上一篇博文[Java三大特征之封装(一)]中的. 从这里我们可以看出,Wife.Husband两个类除了各自的husband.wi

Java面向对象的三大特征和五大原则

Java面向对象的三大特征 封装 封装(Encapsulation)是指属性私有化,根据需要提供setter和getter方法来访问属性.即隐藏具体属性和实现细节,仅对外开放接口,控制程序中属性的访问级别. 封装目的:增强数据安全性,不能让其他用户随意访问和修改数据,和简化编程,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员. 继承 继承(Extend)是指将多个相同的属性和方法提取出来,新建一个父类Java中一个类只能继承一个父类,且只能继承访问权限非private的属性和方法

面向对象三大特征之封装与static——(Java学习笔记四)

面向对象     编程本质:以类的方式组织代码,以对象的方式组织(封装)数据 对象:具体的事物,某个类的对象(实例) 类:是对对象的抽象,用于描述同一类型的对象的一个抽象概念 对象和类的关系:特殊到一般,具体到抽象 三大特征: 封装 继承 多态 构造器:又叫构造方法(constructor),用于构造类的实例 格式:修饰符 类名(形参列表){ //语句 } 构造器的方法名与类名一致 通过new关键字调用 当没有定义构造方法时,系统会自定义一个无参构造函数 构造方法可以重载 作用:构造该类的对象,