抽象类

  在面向对象的概念中,所有的对象都是通过类来表述的,但并不是所有的类都能够完整的描绘对象,如果一个类中没有包含足够的信息来描绘一类具体的对象,这样的类就是抽象类.抽象类往往用来表征对问题领域进行分析,设计中的出的抽象概念.  是对一系列看上去不同,但本质上相同的具体概念的抽象.例如:定义一个平面图形Shape . 任何平面图形都有周长和面积,在Shape类中定义两个方法用于计算图形的面积和周长

  

public class Shape{
//计算圆的面积
public void callArea(){}
//计算圆的周长
public void callPerimeter(){}
}

  通过分析,可以发现平面图形领域存在着园,三角形,长方形等这样一些具体的图形,计算它们的面积和周长是不同的,因此在Shape类中无法统一定义callArea()和callPerimeter()方法 , 但是它们都属于平面领域,都需要这两个方法.

  有事定义类的"骨架",对其共同行为提供规范,但并不实现,具体的实现将放在它的子类来完成.这种骨架类在java中叫做 抽象类,通过abstract关键字来描述

[访问符] abstract class 类名{
[访问符] abstract <返回类型> 方法名([参数列表]);
}

  定义抽象类需要注意一下几点:

  1、abstract放在class前面,指明该类是抽象类;

  2、abstract放在方法声明中,则该方法是抽象方法,抽象方法没有方法体,即未实现;

  3、一个抽象类可以含有多个抽象方法,也可以含有已经实现的方法;

  例子:抽象类的定义与使用

package 抽象类;
//定义图形抽象类
public abstract class Shape {
double dim;
public Shape(double dim) {
this.dim = dim;
}
//抽象方法,获得面积
public abstract double callArea();
//抽象方法,获得周长
public abstract double callPerimeter();
}

  上面的例子是定义了一个抽象类Shape,并且声明了两个抽象方法callArea()和callPerimeter(),这两个抽象方法没有方法体.在这里需要注意,抽象方法是没有方法体,它和空方法是两个不同的概念

    public abstract void callAreas(); //抽象方法,没有 {}括起来的方法体
public void callArea() {}; //空方法,有{}括起来的方法体,但方法体中没有任何语句

  抽象类还可以包含具体数据和具体方法,也可以包括构造方法,定义抽象类的目的是提供可由其子类共享的一般形式,子类可以根据自身需要扩展抽象类

  例子:定义Shape抽象类的一个子类Circle来演示抽象类的使用

package 抽象类;

public class Circle extends Shape{
public Circle(double dim) {
super(dim);
}
//实现抽象方法callArea();
public double callArea() {
//返回圆的面积
return 3.14 * dim * dim;
}
public double callPerimeter() {
//返回圆的周长
return 2 * 3.14 * dim;
}
public static void main(String args[]) {
//声明一个Shape对象,指向实现它的子类对象
Shape shape = new Circle(10);
//调用callArea()求出圆的面积并输出
System.out.println("圆的面积为:" + shape.callArea());
//调用callPerimeter()求出圆的周长并输出
System.out.println("圆的周长为:" + shape.callPerimeter());
}
}

  执行结果:

圆的面积为:314.0
圆的周长为:62.800000000000004

  从执行的结果来看,当调用Shape类型的变量shape时,实际上是调用了Circle类型对象的方法,即通过基类调用派生类的方法,这也是一种多态的体现  

  一个类在继承抽象类时,如果没有实现所有抽象类方法,那么该类也必须声明为抽象类:

  例子:

  

package 抽象类;

public abstract class Square extends Shape{
public Square(double dim) {
super(dim);
}
//实现抽象方法callArea()
public double callArea() {
return dim * dim;
}
//没有实现抽象方法callPerimeter(),Square类中仍然包含抽象方法,所以Square依然是抽象类
}

  注意:1、抽象类不能实例化,既不能直接new一个抽象类,但可以指向一个实现它的子类对象

     2、抽象方法没有方法体,抽象类提供了子类的规范模板,抽象方法必须在子类中给出具体实现。

     3、abstract不能与final同时修饰一个类,abstract不能和static、private、final或者native并列修饰同一方法。

接口

  java只支持单一继承,不支持多重继承,即一个类只能继承另一个类,不能继承两个或两个以上的类。单一继承限制了类的多重体现,为了弥补这一缺陷,模仿C++中的多重继承,java语言的设计者提出了一种折中的解决办法,即使用接口:一个类可以实现多个接口。接口的引入,使java拥有了强大的面向对象编程能力,为面向接口编程提供了广泛的扩展空间 。

定义接口

<访问符> interface 接口名{
[访问符] <返回类型> 方法名([参数列表])
......
}

  1、interface是定义接口的关键字;

  2、接口是一种特殊的抽象类型,是对抽象类的进一步强化,是方法声明和常量的定义集合,因此接口中的方法都没有方法体,即接口中的方法都是未实现的方法,且不需要abstract关键字进行指明

  例子:演示接口的定义和使用

package 接口;

public interface MyInterface {
public void add(int x, int y);
public void volume(int x, int y, int z);
}

  上述代码定义了一个接口MyInterface,在接口 中声明了两个方法,但这两个方法都没有实现,与抽象类中的抽象方法类似,接口中的方法没有方法体,当然也可以定义既包含常量也包含方法的接口

package 接口;

public interface MultiInterface {
//在接口中定义一个静态常量PI
public static final double PI = 3.1415926;
public void callArea();
}

  在定义接口的时候,接口中的所有方法和常量自动定义为public,可以省略public关键字.

实现接口

   实现接口的语法格式如下:

<访问符> class 类名 implements 接口名[接口列表]{
}

  1、implement关键字可以实现多个接口,接口之间用逗号隔开。

  2、一个类实现接口时,必须实现接口中定义的所有方法,除非将该类定义为抽象类。

  例子:定义一个类Myclass实现MyInterface接口,演示接口的实现过程

package 接口;

public class MyClass implements MyInterface{
//实现接口中的add()方法
public void add(int x, int y) {
System.out.println("x + y = " +(x+y));
}
//实现接口中的volume()方法
public void volume(int x, int y, int z) {
System.out.println("X * y * z = " + (x*y*z));
} public static void main(String args[]) {
//声明一个MyInterface对象,指向MyClass类的对象
MyInterface mi = new MyClass();
//调用add方法,传递两个参数
mi.add(1, 2);
//调用volume()方法,传递三个参数
mi.volume(1, 2, 3);
}
}

  执行结果为:

x + y = 3
X * y * z = 6

  上面代码中Myclass类实现MyInterface接口 ,并实现该接口中定义的add()和volume()方法.在main()方法中,先声明一个MyInterface接口类型的变量mi  ,  new一个实现该接口的Myclass类的对象,并将其引用赋值给mi  ,最后通过mi调用方法.

  与抽象类一样,接口是一种更加虚拟的类结构,因此不能对接口实例化

  接口与抽象类有很多相似之处,但要注意这几点区别:

  1、抽象类中可以有已经实现的方法,而接口不能有

  2、接口中定义的变量默认为public static final 型,且必须赋初值,其实现类中不能重新定义,也不能改变其值,即接口中定义的变量都是最终的静态常量;而抽象类中定义的变量 和普通类一样,默认是friendly,其实现类合一重新定义,也可以根据需要改变其值

  3、接口中定义的方法默认都是public修饰,也只能是public,而抽象类则是缺省的friendly

instanceof运算符

  java的多态性机制导致了引用变量的声明类型和其实际类型引用的类型可能不一致,在结合动态方法调度到机制可以得出以下结论:声明为同种类型的两个引用变量调用同一个方法时也有可能会有不同的行为.为了更准确的鉴别一个对象的真正类型,java语言引入了instanceof操作符.其实使用的格式如下:

<引用类型变量> instanceof <引用类型>

   该表达式为boolean类型的表达式,当instanceof左侧的引用类型变量所引用对象的实际类型是其右侧给出的类型或其子类类型时,整个表达式的结果为true,否则为false

  举例:演示instanceof的用法

package instanceof运算符;

//定义IBase接口
public interface IBase {
public void print();
}
package instanceof运算符;

//定义类Derive类实现IBase接口
public class Derive implements IBase{
int b;
public Derive (int b) {
this.b = b;
}
public void print() {
System.out.println("In Derive!");
}
}
package instanceof运算符;

//定义Derive的子类Derive1
public class Derive1 extends Derive{
int c;
public Derive1(int b, int c) {
super(b);
this.c = c;
}
public void print() {
System.out.println("In Derive1!");
}
}
package instanceof运算符;

public class InstanceofDemo {
//判断对象类型
public static void typeof(Object obj) {
if(obj instanceof Derive) {
Derive derive = (Derive) obj;
derive.print();
}else if(obj instanceof Derive1) {
Derive1 derive1 = (Derive1) obj;
derive1.print();
}
}
public static void main(String[] args) {
IBase b1 = new Derive(4);
IBase b2 = new Derive1(4,5);
System.out.print("b1 is:");
//调用typeof()判断b1
typeof(b1);
System.out.print("b2 is:");
//调用typeof()判断b2
typeof(b2);
}
}

  执行结果:

b1 is:In Derive!
b2 is:In Derive1!

  上述代码中定义了一个IBase接口,Derive类实现IBase接口,Derive1是Derive的子类.在InstanceofDemo类中定义了一个静态方法typeof(),该方法使用instanceof来判断对象的类型,并调用其相应的方法,main()方法中定义了两个Base类型的对象分别是b1和b2所引用的实际对象类型.

  从结果不难看出,instanceof运算符能够鉴别出实际对象类型,并实现相应方法的调用,此种方法模拟了方法的动态调用机制.但这种做法被认为没有很好的利用面向对象中的多态性而是采用了结构化编程模式

  注意:在大多数情况下不推荐使用此用算符,应当利用累的多态.

对象转换

  在基本数据类型之间进行相互转换的过程中,有些转换可以自行完成,而有些转换必须通过强制转换,对于引用类型,也从在相互转换机制,也分为自动转换和强制转换

    自动转换:子类转换成为父类,或者实现类转换接口,转换自动完成

    强制转换:父类转换成为子类,或者接口转换成实现类,必须使用强制转换.

Person p = new Teacher(); //创建一个Teacher对象,把引用赋予Person类型变量p
Teacher t = (Teacher) p; //把变量p强制转换成Teacher类型变量

  注意:无论自动转换还是强制转换,都只能用在有继承关系的对象之间.并不是任意类型都可以转换,只有多态的情况下,原本就是子类类型的对象被声明为父类的类型,才可以通过造型恢复其"真实面目",否则将编译失败.

java抽象类,接口(接口定义,实现接口,instanceof运算符,对象转换)的更多相关文章

  1. IEnumerator<TItem>和IEnumerator Java 抽象类和普通类、接口的区别——看完你就顿悟了

    IEnumerable 其原型至少可以说有15年历史,或者更长,它是通过 IEnumerator 来定义的,而后者中使用装箱的 object 方式来定义,也就是弱类型的.弱类型不但会有性能问题,最主要 ...

  2. java中接口的定义和接口的实现

    1.接口的定义 使用interface来定义一个接口.接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成.定义接口的基本格式如下: [修饰符] interfa ...

  3. java 子接口中定义与父接口相同的方法

    今天碰到一个很有意思的问题,在java中如果子接口中定义了与父接口中已经有的方法会发生什么事情呢?比如: interface IRunnable extends Runnable{ void run( ...

  4. 【Java学习笔记之二十三】instanceof运算符的用法小结

    instanceof运算符用法 运算符是双目运算符,左面的操作元是一个对象,右面是一个类.当左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false 说明: (1)一个类的实例 ...

  5. Java -- 封装访问控制级别,包, instanceof 运算符, 初始化块

    1. 可以用 package name1.name2; 显式的定义包名, *.class文件位置应该对应包 name1 name2 的目录下. 2. instanceof 运算符 Object obj ...

  6. Java——抽象类、接口

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  7. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  8. 【48】java抽象类和接口的定义和区别

    首先看看他们的区别: 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是Java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力. ...

  9. Java 基础 面向对象: 接口(interface )概念 以及接口之练习3 -定义一个接口用来实现两个对象的比较并 判断instanceof是否为同类

    接口(interface )概念概念笔记 及测试代码: /** 面向对象: 接口(interface ) 是与类并行的一个概念: * 1.接口可以看成一个特殊的抽象类,它是常量与抽象方法的一个集合 * ...

随机推荐

  1. 『题解』洛谷P1083 借教室

    更好的阅读体验 Portal Portal1: Luogu Portal2: LibreOJ Portal3: Vijos Description 在大学期间,经常需要租借教室.大到院系举办活动,小到 ...

  2. 你了解MySQL中的日志吗?

    MySQL中有两类非常重要的日志,一类是redo log(重做日志),一类是bin log(归档日志) redo log 重做日志利用的,是MySQL中,常见的WAL技术,WAL技术的全程是:Writ ...

  3. linux日志查找方法

    grep "xxxx" *201812* | grep "xxx" | awk -F, '{if(substr($1,1,10)=="2018-12- ...

  4. mysql select自增变量(包括读取当前第几行)

    mysql select自增变量(包括读取当前第几行) SET @rownum =0;select id,@rownum := @rownum +1 as i from ceshi order by ...

  5. ValueError: zero-size array to reduction operation maximum which has no identity

    数据打印到第530行之后出现以下异常,求解!

  6. 【Swift】UNNotificationServiceExtension

    一.简介 An object that modifies the content of a remote notification before it's delivered to the user. ...

  7. thinkphp volist标签中加if判断的写法

    <if condition="$vo['devstatus'] eq 1">在线<else /> 离线</if> IF标签用法 <if c ...

  8. 问题:做EsayUI分页报错 $(...).pagination is not a function之后我把<jsp:include page="top.jsp"/>去掉就好了,有大神知道为什么吗?另外分页按键放在那里好些,我放到form表单下,就开始显示,点一下后就没有了

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...

  9. suseoj 1208: 排列问题 (STL, next_permutation(A.begin(), A.end()))

    1208: 排列问题 时间限制: 1 Sec  内存限制: 128 MB提交: 2  解决: 2[提交][状态][讨论版][命题人:liyuansong] 题目描述 全排列的生成就是对于给定的字符集或 ...

  10. opencv 4 图像处理(漫水填充,图像金字塔与图片尺寸缩放,阈(yu)值化)

    漫水填充 实现漫水填充算法:floodFill函数 简单调用范例 #include <opencv2/opencv.hpp> #include <opencv2/imgproc/im ...