抽象类与接口
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类
浙公网安备 33010602011771号