代码改变世界

抽象类与接口

2013-05-12 10:09  JavaSw  阅读(301)  评论(0)    收藏  举报

抽象类 abstract

抽象类是重构的结果

 

抽象类抽象方法的UML图中都为斜体。

抽象类的构造函数为protected 访问权限。

抽象方法只有声明没有实现且只能包含在抽象类中。

抽象方法是非静态的。

即使子类的父类是具体的,该子类也可以为抽象类。

子类可以覆盖父类的方法并将它定义为abstract。

抽象类可以作为一种数据类型:

GeometriObject[ ] objects = new  GeometriObject[10];

objects[0]  = new Cicle;  //注:Cicle是GeometriObject的子类

 

1  如果将一个类声明为abstract,此类不能创建实例象,只能被继承使用。 

2  抽象方法必须存在于抽象类中。

3  抽象类中可以有一般的变量和一般的方法。

4 子类继承抽象类必须实现其中抽象方法,除非子类为抽象类。 
   private void print(){};此语句表示方法的空实现。 
   abstract void print(); 此语句表示方法的抽象,无实现。

使用:

public abstract class  GeometriObject

{

           public abstract double getArea();

}

 

  public class Circle extends GeometriObject

{

              Public double getArea()

{

}

}

 

Public class Test

{

       Public static void main(String[] args)

{

       GeometriObject geoObject = new Circle();

geoObject.getArea();

}

      

}

 

 

 

接口和抽象类的区别

1 接口只能包含抽象方法,抽象类可以包含普通方法。 
2 接口只能定义静态常量属性,抽象类既可以定义普通属性,也可以定义静态常量属性。 
3 接口不包含构造方法,抽象类里可以包含构造方法。     

  抽象类不能被实例化,但不代表它不可以有构造函数,抽象类可以有构造函数,备继承类扩充

何时使用接口和抽象类:

抽象类(父子关系): 强关系

接口 :弱关系(类属关系)

为什么接口要规定成员变量必须是public static final的呢?

答:

首先接口是一种高度抽象的"模版",,而接口中的属性也就是’模版’的成员,就应当是所有实现"模版"的实现类的共有特性,所以它是public static的 ,是所有实现类共有的 .假如可以是非static的话,因一个类可以继承多个接口,出现重名的变量,如何区分呢?

 其次,接口中如果可能定义非final的变量的话,而方法又都是abstract的,这就自相矛盾了,有可变成员变量但对应的方法却无法操作这些变量,虽然可以直接修改这些静态成员变量的值,但所有实现类对应的值都被修改了,这跟抽象类有何区别? 又接口是一种更高层面的抽象,是一种规范、功能定义的声明,所有可变的东西都应该归属到实现类中,这样接口才能起到标准化、规范化的作用。所以接口中的属性必然是final的。

最后,接口只是对事物的属性和行为更高层次的抽象 。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则(Open-Closed Principle )的一种体现。

 

 

 

 

 

 

接口 interface:表明对象拥有某种属性

接口是设计的结果

 

Intanceof : 判断其左边对象是否为其右边类的实例,返回boolean类型的数据。可以用在继承中的子类的实例是否为父类的实现。

接口可以作为一种数据类型:

GeometriObject[ ] objects = new  GeometriObject[10];

objects[0]  = new Cicle;  //注: GeometriObject是Cicle的接口

或者

Object[] objects = { new Tiger() , new Apple() };

调用函数时候:(父类)objects.函数名();

 

1 因为java不支持多重继承,所以有了接口,一个类只能继承一个父类,但可以实现多个接口,接口本身也可以继承多个接口(子接口)。

2 接口里面的成员变量默认都是public static final类型的。必须被显示的初始化。

3 接口里面的方法默认都是public abstract类型的。隐式声明。

4 接口没有构造方法,不能被实例化。

5 接口不能实现另一个接口,但可以继承多个接口。

6 类如果实现了一个接口,那么必须实现接口里面的所有抽象方法,否则类要被定义为抽象类。

 7 接口都被编译为独立的字节码文件。

 

使用:

public interface Edible

{

       public abstract String howToEat();

}

 

public class Animal  implements Edible

{

       public String howToEat()

{

       Return “ Chicken : Fry it “;

}

}

 

public class Apple  implements Edible

{

       public String howToEat()

{

       Return “ Apple: Make apple cider “;

}

}

 

Object[] objects = { new Animial() , new Apple() };

for(int I = 0 ; i<object. Length ; i++)

       if (objects[i] intanceof Edible )

              object[i].howToEat();

 

接口的三种使用: 可食用、可比较 、可克隆

 

可食用:

public interface Edible

{

       public abstract String howToEat();

}

 

public class Animal  implements Edible

{

       public String howToEat()

{

       Return “ Chicken : Fry it “;

}

}

 

public class Apple  implements Edible

{

       public String howToEat()

{

       Return “ Apple: Make apple cider “;

}

}

 

Object[] objects = { new Animial() , new Apple() };

for(int I = 0 ; i<object. Length ; i++)

       if (objects[i] intanceof Edible )

              object[i].howToEat();

 

可比较(Comparable接口):

Java为此目的提供了Comparable接口:

package java.lang;

 

public interface Comparable

{

       public int comparaTo(Object o);  // 被覆盖

       // comparaTo判断这个对象相对于给定对象o的顺序,并且当这个对象小于、等于或大于给定对象o时,返回负整数、0或正整数。

}

 

public class Max

{

       public static Comparable max(Comparable o1 , Comparable o2)

{

       if (o1. comparator(o2)>0)

              return o1;

       else

              return o2;

}

/*

public class Max

{

       public static Comparable max(Object o1 , Object o2)

{

       if ((Comparable)o1. comparator(o2)>0)

              return o1;

       else

              return o2;

}

}

*/

 

Public class ComparableRectangle extends Rectangle implements Comparable

{

       public int comparaTo(Object o)

{

       if (getArea()> (ComparableRectangle)o.getArea())

       {

              ……

       }

}

 

Cloneable接口

package java.lang;

public interface Cloneable { }

这个接口是空的,一个带空体的接口称为标记接口。一个标记接口不包括常量也不包括方法,它用来表示一个类拥有某些特定的属性。实现Cloneable接口的类标记为可克隆的,而且它的对象可以使用在Object类中定义的clone()方法克隆。

 

Calendar calendar = new GregorianCalendar(2013,1,1)

Calendar calendar1 = calendar ;   // 相同对象

Calendar calendar2 = (Calendar) calendar.clone() ;   //不同对象相同内容

//   == 比较对象的引用   // equals 比较内容

calendar1 == calendar ;  true

calendar2 == calendar ;  false

calendar2.equals (calendar) ;  true

 

在Object类中定义的clone方法的方法头:

protected native Object clone( ) throw CloneNotSupportException;

关键字native表示这个方法不是用Java写的,但是它是JVM针对自身平台实现的。

关键字protected 限定方法只能在同一个包内或在其子类中使用。

==》在覆盖clone()方法时候把修饰符改为public,就可以在任何一个包中使用,而调用super.clone()方法就可以完成克隆。

 

在Object类中定义的clone方法将原始对象的每个数据域复制给目标对象。(浅复制)

如果数据域是基本类型:复制值。

如果数据域是引用类型:复制引用。

 

 

 

1.浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

 

深复制:(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

2.Java的clone()方法
⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

⑵Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 
②在派生类中覆盖基类的clone()方法,并声明为public。 
③在派生类的clone()方法中,调用super.clone()。 
④在派生类中实现Cloneable接口。

请看如下代码:


class Student implements Cloneable    
{    
     String name;    
    int age;    
     Student(String name,int age)    
     {    
        this.name=name;    
        this.age=age;    
     }    
    public Object clone()    
     {    
         Object o=null;    
        try    
         {    
         o=(Student)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
        return o;    
     }    
}    
   
public static void main(String[] args)    
     {    
       Student s1=new Student("zhangsan",18);    
       Student s2=(Student)s1.clone();    
       s2.name="lisi";    
       s2.age=20;    
       System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后,不影响学生1的值。    
    }   


说明:
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。 
②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。


class Professor    
{    
     String name;    
     int age;    
     Professor(String name,int age)    
     {    
        this.name=name;    
        this.age=age;    
     }    
}    
class Student implements Cloneable    
{    
     String name;// 常量对象。    
     int age;    
     Professor p;// 学生1和学生2的引用值都是一样的。    
     Student(String name,int age,Professor p)    
     {    
        this.name=name;    
        this.age=age;    
        this.p=p;    
     }    
    public Object clone()    
     {    
         Student o=null;    
        try    
         {    
             o=(Student)super.clone();    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
         o.p=(Professor)p.clone();    
        return o;    
     }    
}    
public static void main(String[] args)    
     {    
       Professor p=new Professor("wangwu",50);    
       Student s1=new Student("zhangsan",18,p);     // p为引用类型
       Student s2=(Student)s1.clone();    
       s2.p.name="lisi";    
       s2.p.age=30;    
       System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授成为lisi,age为30。    
}   


那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。

改进使学生1的Professor不改变(深层次的克隆)
class Professor implements Cloneable    
{    
     String name;    
     int age;    
     Professor(String name,int age)    
     {    
        this.name=name;    
        this.age=age;    
     }    
    public Object clone()    
     {    
         Object o=null;    
        try    
         {    
             o=super.clone();    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
        return o;    
     }    
}    
class Student implements Cloneable    
{    
     String name;    
     int age;    
     Professor p;    
     Student(String name,int age,Professor p)    
     {    
        this.name=name;    
        this.age=age;    
        this.p=p;    
     }    
    public Object clone()    
     {    
         Student o=null;    
        try    
         {    
             o=(Student)super.clone();    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }     
         o.p=(Professor)p.clone();        // 调用Professor类中的clone()方法复制
        return o;    
     }    
}    
public static void main(String[] args)    
     {    
       Professor p=new Professor("wangwu",50);    
       Student s1=new Student("zhangsan",18,p);    
       Student s2=(Student)s1.clone();    
       s2.p.name="lisi";    
       s2.p.age=30;    
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不 改变。    
}    

将基本数据类型作为对象处理

Java提供一个方便的方法将基本数据类型并入对象或包装成对象,对应的类成为包装类。

 

Double 、Float 、Long 、Integer 、Short 、Byte 继承Number类

Number 、Character 、Boolean 继承Object类

所有类都实现Comparable接口。

 

1、  用基本数据类型值或者用表示数值的字符串来构造包装类

Double mydouble = new Double( 5.0);

Double mydouble = new Double( “5.0”);

2、  包装类没有无参构造方法,所有包装类的实例是不可变的,这意味着一旦创建对象后,它们内部的值就不可变。

3、  每个包装类都有MAX_VALUE、MIN_VALUE 、

MAX_VALUE 表示对应的基本数据类型的最大值。

MIN_VALUE 对于Long 、Integer 、Short 、Byte表示long 、int 、short 、byte基本数据类型的最小值

       MIN_VALUE 对于Double 、Float 表示 double 、float基本数据类型的最小正值。

4、  数值包装类有个静态方法 valueOf( String s ) :创建一个对象并初始化为指定字符串表示的值。

 Double mydouble = valueOf( ( “5.0”);

5、  Integer.parseInt()

(1)  int x = Integer.parseInt(s);  //将字符串值转换为基本类型值

(2)  Integer.parseInt(“s” , 2/8/10/16)    //将数值字符串s 转换为2/8…进制的数值

 

对一个对象数组的排序(通用程序设计)

例:

public class GenericSort

{

    public static void main(String[] args)

    {

    //构建对象数组

    Integer[] intArray = { new Integer(2),new Integer(4),new Integer(3)};

    Double [] doubleArray = { new Double(3.4),new Double(3.5),new Double(5.5)};

    Character[] charArray = { new Character('a'),new Character('g'),new Character('x')};

    String[] stringArray = { "Tom","Jack","Fred"};

   

    sort(intArray);

    sort(doubleArray);

    sort(charArray);

    sort(stringArray);

 

    }  

   

   

    public static void sort(Comparable[] list)

    {

       Comparable currentMin;

       int currentMinIndex;

      

       for(int i= 0; i<list.length-1; i++)   //n-1次排序

       {

           currentMin = list[i];

           currentMinIndex = i;

          

           for(int j = 0; j<list.length;j++)   //选出最小的

           {

              if(currentMin.compareTo(list[j])>0)

              {

                  currentMin = list[j];

                  currentMinIndex = j ;

              }

           }

           if(currentMinIndex != i)           //将最小的数与第i躺上的数交换

           {

              list[currentMinIndex] = list[j];

              list[i] = currentMin;

           }

       }

    }

}

 

在 java.util.Array 类中,Java提供一个对任意对象类型的数组进行排序的静态方法sort。

 

java.util.Arrays.sort(intArray);

java.util.Arrays.sort(doubleArray);

java.util.Arrays.sort(charArray);

java.util.Arrays.sort(stringArray);

 

注意:new Integer[10] intanceof Object[]/Comparable[]/Number[];   都为true

 

 

基本类型与包装类类型之间的自动转换

Integer intArray = new Integer {1,2,3};                        //自动装箱

System.outt.printlin(intArray[0] + intArray[1] + intArray[2]);      //自动开箱

 

BigInteger 和 BigDecimal 类

算术运算:add 、subtract 、multiply 、divide 和 remainder

BigInteger a = new BigInteger (“10”);

BigInteger b = new BigInteger(“99999999999999999999999”);

a.multiply(b);  相乘

 

BigDecimal a = new BigDecimal (“.10”);

BigDecimal b = new BigDecimal (“3”);

a.divide(b,20, BigDecimal.ROUND_UP);  //相除  0.3333333333333333334 

// BigDecimal.ROUND_UP向上约等于、 20 表示小数点后的位数

 

Rational类