UI界面重绘系列(下):接口和构造器的探讨

我们在UI界面重绘系列(上)中,探讨了类与对象、继承的关系、方法重写;今天我们来看看接口和构造器在重绘中的使用。并探讨它们的相关知识,更重要的是,我们会去补充一些之前未聊到的内容。

首先,我们来认识接口。

接口是什么?

接口不是类,它是一种抽象类型。接口中只能有抽象方法,被隐式的指定为 public abstract,接口中还可以有变量,这些变量会被隐式的指定为 public static final 变量。
接口声明的语法格式如下:

[可见度] interface 接口名称 [extends 其他的接口名] {
        // 声明变量
        // 抽象方法
}

我们可以看到,一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。接下来,我们继续聊聊它和类有哪些异同。

类与接口的异同

相同之处

1、Java中类与接口都保存在 .java 结尾的文件中,文件名使用相同的类名或是接口名。
2、一个类或接口都可以有多个方法。

不同之处

普通类接口
方法构造方法抽象方法
成员变量任意指定只被static和final修饰
实例化对象
声明关键字classinterface
继承关键字extendsimplements(类继承接口时)
抽象类接口
方法体
抽象形式abstract修饰隐式:public abstract方法和public static final变量
静态代码块和静态方法可以含有不能含有

除此之外:
1、一个类只能继承一个抽象类,而一个类却能同时实现多个接口。
例如:之前我们的监听类实现了鼠标和动作监听器接口。

public class DrawListener implements MouseListener,ActionListener{

但需要注意的是,类的多继承是不合法的,只有接口可以被多继承。多继承指的是,一个类分别继承了多个其他类,这里我们要区分extends和implements。类只能多重继承,即一个类被很多类所继承。

2、 一个接口又可以被多个接口所继承。
例如:鼠标、键盘、动作监听器接口都继承于事件监听器接口

public interface MouseListener extends EventListener{
public interface ActionListener extends EventListener{
public interface KeyListener extends EventListener{

3、一个实现接口的类,必须实现接口内所描述的所有方法,否则必须声明为抽象类。但如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
例如

public class DrawListener implements MouseListener{
 public void mousePressed(MouseEvent e){}
 public void mouseReleased(MouseEvent e){}
 public void mouseClicked(MouseEvent e) {}
 public void mouseEntered(MouseEvent e) {}
 public void mouseExited(MouseEvent e) {}
}

4、标记接口是没有任何方法和属性的接口,它仅仅表明它的类属于一个特定的类型。供其他代码来测试允许做一些事情。
例如

package java.util;
public interface EventListener {
}

标记接口目的有二:
一是建立一个公共的父接口,当一个接口去继承父接口时,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
二是向一个类添加数据类型,实现标记接口的类不需要定义任何接口方法,但是该类通过多态性变成一个接口类型。

接口的使用

我们来创建一个公共的父类接口

import java.awt.Graphics;
public interface ShapeInfo {
 public void draw(Graphics g);
}

并让其他接口或类去继承它,这里我们让Shape类去继承这个接口

public class Shape implements ShapeInfo{

声明好的ShapeInfo作为底层的基本接口,将不被修改,我们只需通过增补代码,即继承和实现来完成我们想要的功能

下面,我们来谈谈构造器。

为什么要有构造器?

Java中引入构造器,是确保每一个对象都得到初始化,Java在有能力操作对象之前,系统会自动调用相应的构造器,或是用new关键字调用构造器,保证初始化的进行。调用构造器是编译器的责任,所以必须让编译器知道调用的是哪一个方法。所以Java采取了与类同名的方法命名构造器。

实际上用new调用构造器时,系统会为该对象分配内存空间,并为这个对象执行默认初始化。如果这个对象已经产生了,那么这些操作在执行构造器之前就已经完成了。所以当系统开始构造器的执行体之前,系统已经创建了一个对象,只是这个对象还不能被外界程序访问,只能够在构造器中通过this来引用。当执行结束后,这个对象作为构造器的返回值被返回,通过赋值给另一个引用类型的变量,从而让外部程序访问。
例如

Shape s=new Shape();

如果我们写一个没有构造器的类,编译的时候,系统会默认创建一个无参构造器,我们可以自定义一个构造器去改变系统的默认初始化。

构造器的应用

this的使用

之前我们提到过这两个关键字。构造器和方法使用关键字this有很大的区别。
1、方法引用this指向正在执行方法的类的实例。静态方法不能使用this关键字,因为静态方法不属于类的实例,所以this也就没有什么东西去指向。
2、构造器的this指向同一个类中,不同参数列表的另外一个构造器。

super的使用

构造器和方法,都用关键字super指向超类,但是用的方法不一样。
1、方法用这个关键字去执行被重载的超类中的方法。
2、构造器使用super去调用超类中的构造器。
和this一样,在构造器中使用关键字super,它必须被放在第一行,否则会编译报错。
例如:我们在重写绘制方法paint时,代码如下:

public void paint(Graphics g){
  //引用父类的绘制方法
  super.paint(g);
  //重写绘制方法
  for(int i=0;i<data.length;i++){
   Shape s=data[i];
   s.draw(g);
  }
 }

如果将super.paint(g);放在for循环语句执行完,那么编译则无法引用到父类的绘制方法。执行程序,变动窗体时,将会出现下面这种绘制不完全的情况:
在这里插入图片描述

自定义Shape构造器

之前在实现重绘功能时,在监听器中初始化了Shape类的对象s,源代码如下:

Shape s=new Shape();
  s.color=Color.BLACK;
  s.shape=ShapeStr;
  s.x1=x1;
  s.y1=y1;
  s.x2=x2;
  s.y2=y2;

现在我们将Shape类中的默认无参构造器如下:

public Shape(int x1,int x2,int y1,int y2,Color color,String shape){
  this.x1=x1;
  this.x2=x2;
  this.y1=y1;
  this.y2=y2;
  this.color=color;
  this.shape=shape;
 }

并在监听器中直接创建对象,并完成成员变量的初始化:

Shape s=new Shape(x1,x2,y1,y2,Color.BLACK,ShapeStr);

其他补充

问题一:Add default serial version ID警告

DFrame extends JFrame时会有Add default serial version ID的提示,按要求添加,会多出一行莫名其妙的代码,此时不再提示:

private static final long serialVersionUID = 1L;

在类的继承过程中,如果增改属性或方法,可能会提示我们要显示serialVesionUID的声明。目的是Serializable(序列化)对象版本的控制,避免有关版本Deserialize(反序列化)时不兼容的情况发生。如果不声明,JVM就会为我们自动产生一个值,这个值和编译器的实现相关,并不稳定;可能在不同JVM环境下出现Deserialize时报InvalidClassException异常。
实现机理大致如下:当serialVersionUID相同时,它就会将不一样的field以type的预设值Deserialize,即可避开不兼容性的问题.

问题二:java.lang.NullPointerException报错

这是空指针报错信息,我们增添 if 语句,避免指针指向Null的情况。

//重写绘制方法
  for(int i=0;i<data.length;i++){
   if(data[i]==null)break;
   Shape s=data[i];
   s.draw(g);
  }

同样,当绘制图形数超过Shape数组长度时,会出现如下报错信息:java.lang.ArrayIndexOutOfBoundsException
我们在使用数组时一定要小心数组溢出的现象,这会导致不可预判的情况发生,十分危险。关于数组的内容我们会在今后继续探讨。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值