博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java探索之旅(11)——抽象类与接口
阅读量:5888 次
发布时间:2019-06-19

本文共 7009 字,大约阅读时间需要 23 分钟。

1.Java数据类型

     
❶不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值。 它包括:        Primitive变量:boolean,byte, char, double ,float, integer, long, short        JDK不可变类:Boolean, Byte, Character, Double, Float, Integer, Long, Short, String (java.lang包中)     ❷可变类,是当你获得这个类的一个实例引用时,你可以改变这个实例的内容。 可变类对象间用“=”赋值,则会是使两个对象实际上会引用同一个实例。所以,只有实现深度clone才能使可变类对象的修改不影响原始对象的值。

     ❸对于不可变类,可变类的特性也有意义,有的时候我们不希望重复创建相同的内容的实例。因此,我们也可以利用不可变类获得实例缓存。如:

                Integer a=Integer.valueOf(10);                Integer b= Integer.valueOf(10);

    只会在第一次创建取值为10的Integer对象。也就是说a和b指向同一处内存上的内容。

2.抽象类

    ❶继承层次结构中。父类通用而不明确,子类越来越明确和具体。接口是定义多个类的共同行为。

    ❷抽象关键字abstract,位置紧随访问修饰符(public,protected,private)之后。

    ❸抽象类的构造函数一律定义为protected。抽象方法只有定义没有实现(一般定义为public,且抽象方法禁止定义为静态方法)。

    ❹包含抽象方法的类必须定义为抽象类。抽象类不一定需要包含抽象方法。

    ❺若子类没有实现父类的抽象方法。子类仍需要定义为抽象类。即,抽象类派生出的非抽象子类,必须实现所有基类的抽象方法,即使它没有使用

    ❺父类为具体类,子类可以是抽象类。子类可以覆盖父类的方法并将其定义为抽象方法,当然前提是子类定义为抽象类。

    ❻new无法作用抽象类创建实例,但是可以作为一种数据类型,创建引用变量(或者引用数组),然后指向子类对象。当然其引用类型也可以作为函数参数。

     如下定义抽象类Gobject。定义两个扩展类圆Circle和长方形rectangle。定义抽象方法getArea()返回面积

package GeometricObject;public abstract class Gobject {	private String color="white";	private boolean filled;	private java.util.Date dateCreated;//时间类	//构造函数必须定义protected	protected Gobject()	   {dateCreated=new java.util.Date();}	protected Gobject(String s,boolean f)	   {this();	     filled=f;color=s;}		public String toString()	   {return "Created on:"+dateCreated+"\ncolor:"+color+"\nfilled with?--"+filled;}	public void setColor(final String s){color=s;}	public String getColor(){return color;}	public abstract double getArea();//抽象方法}//圆类class Circle extends Gobject implements Comparable,Cloneable{	double radius;	final static double PI=3.1415;	Circle()	  {radius=1.0;}//隐含调用super();	Circle(double r,String s,boolean f){		super(s,f);//调用父类构造函数	    radius=r;	 }	public String toString()	{return super.toString()+"\nArea--"+getArea();}}//长方形类class rectangle extends Gobject implements Comparable,Cloneable{//常用方法,从虚函数中扩展	double width,height;	rectangle ()	  {width=height=1.0;}//隐含调用super();	rectangle(double w,double h,String s,boolean f)	  {super(s,f);//调用父类构造函数	   width=w;height=h;}		public double getArea()	   {return width*height;}}

  测试如下:

public class test {   public static void main(String[] args)	{		Gobject[] p=new Gobject[2];//抽象类作为数据类型定义数组		p[0]=new Circle(2.3,"Blue",true);		p[1]=new rectangle(4.0,5.0,"Red",false);        		System.out.println(p[0].toString());		System.out.println(p[1].toString());		System.out.println("The two Object have "+equalArea(p[0],p[1])+" area");				   public static String equalArea(Gobject o1,Gobject o2)//抽象类引用类型作为函数参数    {	   if(o1.getArea()==o2.getArea())//JVM动态调用实例的函数	       return "same";	   else	       return "different";    }}

3.接口

   ❶类似于类,目的是指明多个对象的共同行为。

   ❷接口类似于抽象类。编译为单独的字节码文件。不能使用new创建实例,但是可以声明引用变量或者作为类型转换的结果。

   ❸接口仅仅包括常量和抽象方法或者完全为空(所谓的标记接口maker interface)。即所有的方法默认都是public abstract,所有的变量都是public final static<

   ❹接口类定义的常量可以使用“接口名.变量名”访问。

4.可比较接口 Comparable

       ❶Java中的许多类,比如String和Data实现(implements)Comparable接口,以比较自然对象的大小。

   ❷接口引用变量可作函数参数类型和返回类型。声明如下:

public interface Comparable //比较接口                    {int comparaTo(Object o);//判断当前对象与目标对象的大小}
   定义的通用求最大值的Max函数如下:

//通用的求最大值的类//接口引用作为函数参数和返回参数,此时类似虚函数public class Max {	public static Comparable max(Comparable a,Comparable b)	{		if(a.comparaTo(b)>0)//调用具体的比较函数			return a;		else			return b;	}}

   Circlerectangle分别实现了该接口,即继承了接口的抽象方法,并具体实现。如下:

class Circle extends Gobject implements Comparable,Cloneable{       ......................	public int comparaTo(Object o){//继承并且实现camparaTo函数		if(getArea()>((Gobject)o).getArea())//显式转换			return 1;		else if(getArea()<((Gobject)o).getArea())			return -1;		else			return 0;	}       .................}class rectangle extends Gobject implements Comparable,Cloneable{//常用方法,从虚函数中扩展      ..................	public int comparaTo(Object o){//继承并且实现camparaTo函数		if(getArea()>((Gobject)o).getArea())			return 1;		else if(getArea()<((Gobject)o).getArea())			return -1;		else			return 0;	}     .....................}

    利用Max求两个圆或者两个长方体最大的面积的代码片段为

//Comparable 接口	//使用通用的Max类,比较任意扩展了comparable的对象	Circle[] cp=new Circle[2];	cp[0]=new Circle(1.56,"Blue",true);	cp[1]=new Circle(3.45,"Green",false);	Comparable max=Max.max(cp[0], cp[1]);//接口类型引用	System.out.println("The max Area of 2 Circle is "+((Circle)max).getArea());//显式转换	    	rectangle[] rp=new rectangle[2];	rp[0]=new rectangle(1.56,12.0,"Blue",true);	rp[1]=new rectangle(3.45,6.7,"Green",false);	Comparable max1=Max.max(rp[0], rp[1]);//接口类型引用	System.out.println("The max Area of 2 rectangle is  "+((rectangle)max1).getArea());//显式转换

   由于max输出的类型为Comparable类型,所以调用Circle或者rectangle的getArea()函数必须显式转换

5.可克隆接口 Cloneable

   ❶该接口为标记接口,即无常量和方法。标记用来表示类拥有某种属性。定义如下:

public interface Cloneable {}

    ❷对于可复制的类,必须满足:     实现Cloneable接口。这样才有资格调用Object.clone()方法      覆盖Object的clone()方法。Object.clone()方法是protected的,覆盖并改为public

   ❸Object的clone的行为是最简单的。以堆上的内存存储解释的话(不计内存),对一个对象a的clone就是在堆上分配一个和a在堆上所占存储空间一样大的一块地方,然后把a的堆内存的内容按位(bit-wise)复制到这个新分配的内存。

   ❹Primitive数据类型(如int,double)为深拷贝,引用类型(包括可变类和不可变类)均为浅拷贝,浅拷贝指拷贝前后引用变量指向同一对象。深拷贝或者克隆的目的在数据前后隔离,默认的浅copy不是隔离的——即改变copy的东西,会影响到原型的内部。

   ❺改变拷贝对象的Primitive数据值或者不可变类引用变量(如String)的指向对象,不影响源对象的对应数据,即满足数据隔离。前者的原因显而易见,后者的原因是因为---不可变类不能通过【对象名+"."方法(数据)】改变数据域,只能通过将其指向其他对象改变其数据域,如此一来,肯定不影响。

   对于前面定义的Circle,rectangle类,实现Coloneable接口如下:

class Circle extends Gobject implements Comparable,Cloneable{	......................	public Object clone() throws CloneNotSupportedException{		  return super.clone();		}	......................}//长方形类class rectangle extends Gobject implements Comparable,Cloneable{//常用方法,从虚函数中扩展	.......................	public Object clone() throws CloneNotSupportedException{      return super.clone();	}       .......................}
 注意

    ①由于返回的为Object,可能需要显式转换。

    ②使用super.clone()而非this.clone()的原因。Object中的clone执行的时候使用了RTTI(run-time type identification)的机制,动态得找到目前正在调用clone方法的reference,根据它的大小申请内存空间,然后进行bitwise的复制,将该对象的内存空间完全复制到新的空间中去,从而达到shallowcopy的目的。所以调用super.clone() 得到的是当前调用类的副本,而不是父类的副本。根本没有必用调用this.clone()

    ③如果需要克隆的类引用到了其它的类的对象,甚至这个对象也引用到了别的对象,那么在必要情况下,你需要将这个对象树进行完整的克隆。如下:

class User implements Cloneable {	String name;	int age;	@Override	public User clone() throws CloneNotSupportedException {		return (User) super.clone();	}}class Account implements Cloneable {	User user;	long balance;	@Override	public Account clone() throws CloneNotSupportedException {		Account account = (Account) super.clone();		if (user != null) {			account.user = user.clone();//显式深拷贝		}		return account;	}}

6.抽象类和接口的比较

   ❶变量:抽象类无限制;接口必须为public static final   ❷构造方法:抽象类子类经过构造链调用构造法。接口无构造方法。两者均不能用new实例化   ❸方法:抽象类无限制;接口必须是public abstract   ❹抽象类只能(被)单一扩展;类可以同时实现多重接口,接口同时可以同时继承多重接口而不是类。   ❺所有类有公共根Object;而所有接口没有公共接口。   ❻两者均可以定义类型,且引用变量可以引用---任何实现了接口(或抽象类)的对象。
    一般而言,父子关系强,使用抽象类;弱使用接口。接口可以定义不相关类共有的父类型(例如房屋可以比较面积,数值可以比较大小,使用comparable接口)。
抽象类更加使用方便,接口更加灵活。
   注意: 
如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法。接口做不到这一点,如果向一个Java接口里加入一个 新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点之一。 
               经典的使用方法
A extends AbstractB implements interfaceC
           
详细可点击:
参考:
    1.
    2.
    3.

转载于:https://www.cnblogs.com/engineerLF/p/5393089.html

你可能感兴趣的文章
nodejs 安装 postgresql module
查看>>
【转】iOS学习之iOS禁止Touch事件
查看>>
Java8新特性之Collectors
查看>>
怎么用CorelDRAW制作表格
查看>>
eclipse智能配置
查看>>
安装Scrapy遇到的问题处理
查看>>
个人作业——软件产品案例分析
查看>>
Java学习:方法重载的使用规则
查看>>
ASP.NET MVC 防止CSRF攻击
查看>>
EF:无法检查模型兼容性,因为数据库不包含模型元数据。
查看>>
0和5
查看>>
C# WinFrom一些技术小结
查看>>
hdu5001 Walk 概率DP
查看>>
模拟select控件&&显示单击的坐标&&用户按下键盘,显示keyCode
查看>>
Mac-OSX下Ruby更新
查看>>
jsp九个内置对象
查看>>
[Python笔记][第一章Python基础]
查看>>
Bloomberg SEP 12.x 迁移小记
查看>>
生日小助手V1.1发布了——拥有更整齐的信息列表
查看>>
代理模式
查看>>