1.接口的定义:

In the Java programming language, an interface is not a class but a set of requirements for classes that want to conform the interface.

说明: 1) Interface 不是class,虽然interface具有class的一些特点,例如能够继承,能够定义相同类型的变量,而且和C++的abstract class非常像,但Java

的interface和class在本质上已经有所区别!

2) Interface 是一组要求。类的接口是类的调用者和被调用者之间的一个契约,这个契约定义了interface实现者所要提供的功能和功能提供的方式,也定义了

interface调用者获取 interface实现者服务的方式。

为了让某个class实现一个接口,只需要以下两个步骤:

1) 声明你所定义的类将实现某个接口;

2) 在你的类中实现接口中所有的方法;

下面的Employee类实现了compareTo接口,那么就可以使用Array的sort方法来对Emplyee对象形成的数组进行排序;


 1 import java.util.Arrays;
 2 
 3 
 4 public class EmployeeSortTest 
 5 {
 6     public static void main(String[] args) 
 7     {
 8         Employee[] staff = new Employee[3];
 9         
         staff[0] = new Employee("Harry Hacker",35000);
         staff[1] = new Employee("Carl Cracker",75000);
         staff[2] = new Employee("Tony Tester",38000);
         
         Arrays.sort(staff);
         
         for(Employee e : staff)
             System.out.println("name = " + e.getName() + ",salary=" + e.getSalary());
     }
 }
 
 class Employee implements Comparable<Employee>
 {
     public Employee(String n,double s)
     {
         name = n;
         salary = s;
     }
     
     public String getName()
     {
         return name;
     }
     
     public double getSalary()
     {
         return salary;
     }
     
     public void raiseSalary(double byPercent)
     {
         double raise = salary * byPercent / 100;
         salary += raise;
     }
     
     /**
      * Compares employees by salary
      */
     public int compareTo(Employee other)
     {
         if(salary < other.salary) return -1;
         if(salary > other.salary) return 1;
         return 0;
     }
     
     private String name;
     private double salary;
 }

接口的一些特性:
1.接口不是类,你无法new出一个接口实例:

2.虽然无法构建出接口实例,但是可以定义接口变量; 并且接口变量只能指向一个实现该接口的类的对象;

Comparable x;

x = new Employee(...);

3.就像使用instanceof判断一个对象是不是一个类的实例一样,你也可以使用instanceof判断一个类的对象是否实现了某个接口。

if(anObject instanceof Comparable) {}

4.就像类的使用一样,接口也可以用来被继承;

5.Java中的类只能继承一个父类,但却可以实现多个接口!这个特性为定义一个类的行为提供的很大的方便。

接口和抽象类:

为什么不使用抽象类来代替接口的概念呢?--Java中不存在多重继承!Java中用接口来实现了C++中复杂的多继承功能!

2. 对象克隆(Object Cloning):

对任何一个对象你需要认清下面几点:
a). 默认的clone函数是否已经足够优秀!

b). Clone一个基类对象时要Clone其成员的每个mutable部分;

c).  Clone是否根本无法实现;

对象型变量实际存储的是对象实例的地址,而不是对象实例本身,这是Java设计的一个遗憾!


1 import java.util.*;

 2 
 3 public class CloneTest 
 4 {
 5     public static void main(String[] args) 
 6     {
 7         try
 8         {
 9             MyEmployee original = new MyEmployee("John Q. Public",50000);
             original.setHireDay(2000, 1, 1);
             MyEmployee copy = original.clone();
             copy.raiseSalary(10);
             copy.setHireDay(2002, 12, 31);
             System.out.println("original="+original);
             System.out.println("Copy="+copy);
         }
         catch(CloneNotSupportedException e)
         {
             e.printStackTrace();
         }
     }
 }
 
 class MyEmployee implements Cloneable
 {
     public MyEmployee(String n,double s)
     {
         name = n;
         salary = s;
         hireDay = new Date();
     }
     
     public MyEmployee clone() throws CloneNotSupportedException
     {
         MyEmployee cloned = (MyEmployee)super.clone();
         
         cloned.hireDay = (Date)hireDay.clone();
         
         return cloned;
     }
     
     public void setHireDay(int year,int month,int day)
     {
         Date newHireDay = new GregorianCalendar(year,month-1,day).getTime();
         hireDay.setTime(newHireDay.getTime());
     }
     
     public void raiseSalary(double byPercent)
     {
         double raise = salary * byPercent / 100;
         salary += raise;
     }
     
     public String toString()
     {
         return "MyEmployee[name="+name+",salary="+salary+"hireDay="+hireDay+"]";
     }
     
     private String name;
     private double salary;
     private Date hireDay;
 }

结果如下:


original=MyEmployee[name=John Q. Public,salary=50000.0hireDay=Sat Jan 01 00:00:00 CST 2000]

Copy=MyEmployee[name=John Q. Public,salary=55000.0hireDay=Tue Dec 31 00:00:00 CST 2002]

3.接口和回调:

一个在编程中常用的模型称为callback(模型),当一个事件发生时要制定处理动作。比如当按钮被按下后执行的特定动作,或者选择了一个

菜单选项之后执行的特定动作!

Java语言利用传递对象来实现这一点,但C++使用传递函数指针来实现这一点的!


1 /**

 2    @version 1.00 2000-04-13
 3    @author Cay Horstmann
 4 */
 5 
 6 import java.awt.*;
 7 import java.awt.event.*;
 8 import java.util.*;
 9 import javax.swing.*;
 import javax.swing.Timer; 
 // to resolve conflict with java.util.Timer
 
 public class TimerTest
 {  
    public static void main(String[] args)
    {  
       ActionListener listener = new TimePrinter();
 
       // construct a timer that calls the listener
       // once every 10 seconds
       Timer t = new Timer(10000, listener);
       t.start();
 
       JOptionPane.showMessageDialog(null, "Quit program?");
       System.exit(0);
    }
 }
 
 class TimePrinter implements ActionListener
 {  
    public void actionPerformed(ActionEvent event)
    {  
       Date now = new Date();
       System.out.println("At the tone, the time is " + now);
       Toolkit.getDefaultToolkit().beep();
    }
 }

4. 内部类:

内部类是一个定义在其他类中的类,为何要使用内部类呢?下面是常见的3种理由:

  • 内部类中的方法可以访问内部类定义处的数据,即使这些数据是private类型的;
  • 内部类对同一个包中的其他类是隐藏的,即包中的其他类是看不到这个内部类的;
  • 匿名内部类在定义回调函数时非常有用;

4.1 使用内部类来访问对象的状态:


 1 import java.awt.*;
 2 import java.awt.event.*;
 3 import java.util.*;
 4 import javax.swing.*;
 5 import javax.swing.Timer;
 6 
 7 public class InnerClassTest
 8 {
 9     public static void main(String[] args)
     {
              TalkingClock clock = new TalkingClock(1000,true);
              clock.start();
 
          //keep program running until user selects "OK"
          JOptionPane.showMessageDialog(null,"Quit program?");
          System.exit(0);
     }
 }
 
 /**
  * A clock that prints the time in regular interval
  */
 class TalkingClock
 {
     /**
      * Constucts a taking clock
      * @param interval the interval between message(in milliseconds)
      * @param beep true if the clock should beep
      */
     public TalkingClock(int interval,boolean beep)
     {
         this.interval = interval;
         this.beep = beep;
     }
 
     /**
      * Starts the clock
      */
     public void start()
     {
         ActionListener listener = new TimePrinter();
         Timer t = new Timer(interval,listener);
         t.start();
     }
 
     private int interval;
     private boolean beep;
 
49     public class TimePrinter implements ActionListener
50     {
51         public void actionPerformed(ActionEvent e)
52         {
53             Date now = new Date();
54             System.out.println("At the tone, the time is "+now);
55             if(beep) 
56                 System.out.println("Beep!");
57         }
58     }
 }

上述红色代码部分定义了一个内部监听器类,用来监听事件的发生并采取相应的动作:

if(beep) 

          System.out.println("Beep!");

表明这个内部类可以直接访问其外部类的private字段!相当于内部类中存在一个对外部类的隐含引用!

这个代码可以改成:

if(TalkingClock.this.beep) 

System.out.println("Beep!");

4.2  内部类的实用性,内部类真的又存在的必要吗? 内部类的安全性如何呢?

Java 引入内部类机制更多的是为了显得优雅有趣,而非实用性!

内部类最好是只和其所在的外部类进行交互: 一方面让内部类只访问其所在的外部类的数据,另一方面,也让内部类只在其所处的外部类的方法中使用。

让内部类只作为其所处的外部类的处理逻辑的一部分。实际开发中尽量少用或不用内部类。

4.3 本地内部类: 将内部类定义在外部类的某个成员函数中,这样,只有这个外部类的成员函数才会去使用这个内部类的对象。


 1 public void start()
 2 {
 3     class TimePrinter implements ActionListener
 5     {
 6         public void actionPerformed(ActionEvent e)
 7         {
 8             Date now = new Date();
 9             System.out.println("At the tone, the time is "+now);
             if(TalkingClock.this.beep) 
                 System.out.println("Beep!");
         }
     }
     ActionListener listener = new TimePrinter();
     Timer t = new Timer(interval,listener);
     t.start();
 }

注意,本地内部类并没有定义一个访问控制符:(public or private),因为本地内部类的有效作用区域只在定义本地内部类的代码块之中。

4.4 匿名内部类:


 1 public void start(int iterval,final boolean beep)
 2     {
 3         ActionListener listener = new Actionlistener()
 4         {
 5     
 6               public void actionPerformed(ActionEvent e)
 7               {
 8                   Date now = new Date();
 9                   System.out.println("At the tone, the time is "+now);
                   if(TalkingClock.this.beep) 
                        System.out.println("Beep!");
               }
          }
         Timer t = new Timer(interval,listener);
         t.start();
     }

只使用上述内部类的一个对象!

上述这段代码的意思是:

1.定义了一个匿名的类,这个匿名的类实现了Actionlistener接口

2.创建了一个匿名类的实例,在本程序中将其赋给变量listener;

匿名内部类的对象的创建规则是:

new SuperType(construction parameters)

{

inner class method and data;

}

在这里,这个SuperType可以是一个接口,比如上面程序中的Actionlistener,或者是一个基类,这样这个内部类就继承了这个基类;

由于匿名内部类是没有名称的,不然也就不叫"匿名"了,所以匿名内部类是没有构造函数的,

a) 当SuperType是一个类的时候,将construction parameters传递给SuperType类的构造函数。

b) 当SuperType是一个接口的时候,new InterfaceType() {methods and data}

4.5 静态内部类(static):

有些时候,你只是希望在一个类中使用内部类,但并不希望用内部类来访问外部类中的对象。你可以将内部类声明为

static来限制这种内部类对外部类的访问。

引入static 内部类的一个重要原因:

static 方法执行时不会有类的实例与之对应,所以,当一个内部类需要在其所在的外部类的static方法中使用时,内部

类就不能获得其所在外部类实例的引用。下面是一个静态内部类的使用实例:


 1 /**
 2    @version 1.00 1998-04-07
 3    @author Cay Horstmann
 4 */
 5 
 6 public class StaticInnerClassTest
 7 {  
 8    public static void main(String[] args)
 9    {  
       double[] d = new double[20];
       for (int i = 0; i < d.length; i++)
          d[i] = 100 * Math.random();
       ArrayAlg.Pair p = ArrayAlg.minmax(d);
       System.out.println("min = " + p.getFirst());
       System.out.println("max = " + p.getSecond());
    }
 }
 
 class ArrayAlg
 {  
    /**
       A pair of floating point numbers
    */
    public static class Pair
    { 
       /** 
           Constructs a pair from two floating point numbers
           @param f the first number
           @param s the second number
       */
       public Pair(double f, double s)
       {  
          first = f;
          second = s;
       }
 
       /**
          Returns the first number of the pair
          @return the first number
       */
       public double getFirst()
       {  
          return first;
       }
 
       /**
          Returns the second number of the pair
          @return the second number
       */
       public double getSecond()
       {  
          return second;
       }
 
       private double first;
       private double second;
    }
 
    /**
       Computes both the minimum and the maximum of an array 
       @param a an array of floating point numbers
       @return a pair whose first element is the minimum and whose
       second element is the maximum
    */
    public static Pair minmax(double[] d)
    {  
       if (d.length == 0) return new Pair(0, 0);
       double min = d[0];
       double max = d[0];
       for (int i = 1; i < d.length; i++)
       {  
          if (min > d[i]) min = d[i];
          if (max < d[i]) max = d[i];
       }
       return new Pair(min, max);
    }
 }

4.6  代理(Proxies):


1 import java.lang.reflect.*;

 2 import java.util.*;
 3 
 4 /**
 5  * An invocation handler that prints out the method name and parameters, then
 6  * invokes the original method
 7  */
 8 class TraceHandler implements InvocationHandler
 9 {
     /**
      * Constructs a TraceHandler
      * @param t the implicit parameter of the method call
      */
     public TraceHandler(Object t)
     {
         target = t;
     }
 
     public Object invoke(Object proxy,Method m,Object[] args) throws Throwable
     {
         //print implicit argument
         System.out.print(target);
 
         //print method name
         System.out.print("."+m.getName()+"(");
 
         //print explicit arguments
         if(args != null)
         {
             for(int i = 0; i < args.length; i++)
             {
                 System.out.print(args[i]);
                 if(i < args.length - 1) System.out.print(", ");
             }
         }
 
         System.out.println(")");
 
         //invoke actual method
         return m.invoke(target,args);
     }
 
     private Object target;
 }
 
 public class ProxyTest
 {
     public static void main(String[] args)
     {
         Object[] elements = new Object[1000];
 
         //fill elements with proxies for the integers 1...1000
         for(int i = 0; i < elements.length; i++)
         {
             Integer value = i+1;
             InvocationHandler handler = new TraceHandler(value);
             Object proxy = Proxy.newProxyInstance(null,new Class[] {Comparable.class},handler);
             elements[i] = proxy;
         }
 
         // construct a random integer
         Integer key = new Random().nextInt(elements.length) + 1;
 
         // search for the key
         int result = Arrays.binarySearch(elements,key);
 
         //print match if found
         if(result >= 0) System.out.println(elements[result]);
     }
 }

代理机制属于模式设计范畴,在以后的博客中会专门开辟一篇探究Java的代理机制。

Java面向对象程序设计--接口和内部类的更多相关文章

  1. Java面向对象程序设计----接口

    接口:接口是一套规范.一个比抽象类更抽象的类. 接口中只能写抽象方法.接口中没有构造函数接口中的变量:public Stratic final接口怎么来使用(implements)实现接口 接口语法: ...

  2. Java面向对象程序设计第9章1-9

    Java面向对象程序设计第9章1-9 1. 线程和进程的联系和区别是什么? 联系: 一个进程可以包括多个线程. 区别: 进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统 ...

  3. 实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

  4. 20145212《Java程序设计》实验报告二 《 Java面向对象程序设计》

    20145212 实验二< Java面向对象程序设计> 实验内容 单元测试 三种代码 伪代码 百分制转五分制: 如果成绩小于60,转成"不及格" 如果成绩在60与70之 ...

  5. 20145213《Java程序设计》实验二Java面向对象程序设计实验报告

    20145213<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装,继承,多态 初步掌握UML建模 熟悉S.O. ...

  6. 20145206《Java程序设计》实验二Java面向对象程序设计实验报告

    20145206<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O. ...

  7. 20145308刘昊阳 《Java程序设计》实验二 Java面向对象程序设计 实验报告

    20145308刘昊阳 <Java程序设计>实验二 Java面向对象程序设计 实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面相对象三要素:封 ...

  8. 20145113 实验二 Java面向对象程序设计

    20145113 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 1.初 ...

  9. JAVA课程实验报告 实验二 Java面向对象程序设计

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计  班级:1353  姓名:韩玉琪  学号:20135317 成绩:             指导教师:娄嘉 ...

随机推荐

  1. Web---文件上传-用apache的工具处理、打散目录、简单文件上传进度

    我们需要先准备好2个apache的类: 上一个博客文章只讲了最简单的入门,现在来开始慢慢加深. 先过渡一下:只上传一个file项 index.jsp: <h2>用apache的工具处理文件 ...

  2. Shell if else语句

    if 语句通过关系运算符判断表达式的真假来决定执行哪个分支.Shell 有三种 if ... else 语句: if ... fi 语句: if ... else ... fi 语句: if ... ...

  3. redis 手册

    一.概述: 在该系列的前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命 令都具有一个共同点,即所有的操作都是针对与 ...

  4. ios 游戏《魂斗罗》 AL文件素材破解

    1.破解原理非常简单就是找png的8字节的前缀(baidu png 文件编码格式). 2.破解就图就可以看见了 3.这样一个个个的改是不是非常麻烦,所有我专门写了个py脚本在干这事!一步搞定! 源码如 ...

  5. DevExpress 用户控件 分页(中)

    说明: 1)具体调用请关注 看DevExpress 用户控件 分页(下) datanavi_ButtonClick 是DataNavigator的ButtonClikc事件 视图设计器: 分页用户控件 ...

  6. LINUX下解决netstat查看TIME_WAIT状态过多问题

     来源:多3度热爱 的BLOG   查看连接某服务端口最多的的IP地址 netstat -nat |awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c ...

  7. 《Linux内核设计与实现》学习笔记之“Linux进程管理机制”

    一.进程(或者称为“任务”)简介 进程是OS最基本的抽象之一,通常进程包括“可执行程序代码”,“其他资源”(如:打开的文件,挂起的信号,内核内部数据,处理器状态,地址空间,一个或多个执行线程等) 二. ...

  8. 部分 CM11 系统 Android 平板执行植物大战僵尸 2 黑屏的解决的方法

    原文 http://forum.xda-developers.com/showthread.php?t=2755197 部分 CM11 系统的 Android 平板(比如三星 GT-P5110 )执行 ...

  9. [TypeScript] Using Lodash in TypeScript with Typings and SystemJS

    One of the most confusing parts of getting started with TypeScript is figuring out how to use all th ...

  10. TabHost 两种使用方法 直接让一个Activity 继承TabActivity 和 利用findViwById()方法取得TagHost组件

    第一种,TabActivity 解决方案 下面建立的布局文件,它包含多个标签的显示组件 <?xml version="1.0" encoding="utf-8&qu ...