如何正确的使用java内部类.docx

上传人:b****8 文档编号:9812542 上传时间:2023-02-06 格式:DOCX 页数:24 大小:25.07KB
下载 相关 举报
如何正确的使用java内部类.docx_第1页
第1页 / 共24页
如何正确的使用java内部类.docx_第2页
第2页 / 共24页
如何正确的使用java内部类.docx_第3页
第3页 / 共24页
如何正确的使用java内部类.docx_第4页
第4页 / 共24页
如何正确的使用java内部类.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

如何正确的使用java内部类.docx

《如何正确的使用java内部类.docx》由会员分享,可在线阅读,更多相关《如何正确的使用java内部类.docx(24页珍藏版)》请在冰豆网上搜索。

如何正确的使用java内部类.docx

如何正确的使用java内部类

内部类是Java言语的一个很重要的概念,《Java编程思想》花了很大的篇幅来讲述这个概念。

但是我们在实践中很少用到它,虽然我们在很多时候会被动的使用到它,但它仍然像一个幕后英雄一样,不为我们所知,不为我们所用。

本文不试图来讲述Java内部类的今生前世、来龙去脉,这些在网络上都已经汗牛充栋。

如果读者想了解这些,可以在网络上搜索来学习。

Java内部类总是躲在它的外部类里,像一个幕后英雄一样。

但是幕后英雄也有用武之地,在很多时候,恰当的使用Java内部类能起到让人拍案叫绝的作用。

本文试图谈一谈让这个幕后英雄也有用武之地的四个场景,希望引起大家对使用Java内部类的兴趣。

以下的文字,要求大家熟悉Java内部类的概念后来阅读。

场景一:

当某个类除了它的外部类,不再被其他的类使用时

我们说这个内部类依附于它的外部类而存在,可能的原因有:

1、不可能为其他的类使用;2、出于某种原因,不能被其他类引用,可能会引起错误。

等等。

这个场景是我们使用内部类比较多的一个场景。

下面我们以一个大家熟悉的例子来说明。

在我们的企业级Java项目开发过程中,数据库连接池是一个我们经常要用到的概念。

虽然在很多时候,我们都是用的第三方的数据库连接池,不需要我们亲自来做这个数据库连接池。

但是,作为我们Java内部类使用的第一个场景,这个数据库连接池是一个很好的例子。

为了简单起见,以下我们就来简单的模拟一下数据库连接池,在我们的例子中,我们只实现数据库连接池的一些简单的功能。

如果想完全实现它,大家不妨自己试一试。

首先,我们定义一个接口,将数据库连接池的功能先定义出来,如下:

Java代码

1.public interface Pool extends TimerListener  

2.{  

3.        //初始化连接池  

4.        public boolean init();  

5.        //销毁连接池  

6.        public void destory();  

7.        //取得一个连接  

8.        public Connection getConn();  

9.        //还有一些其他的功能,这里不再列出  

10.        ……  

11.}  

publicinterfacePoolextendsTimerListener

{

//初始化连接池

publicbooleaninit();

//销毁连接池

publicvoiddestory();

//取得一个连接

publicConnectiongetConn();

//还有一些其他的功能,这里不再列出

……

}

有了这个功能接口,我们就可以在它的基础上实现数据库连接池的部分功能了。

我们首先想到这个数据库连接池类的操作对象应该是由Connection对象组成的一个数组,既然是数组,我们的池在取得Connection的时候,就要对数组元素进行遍历,看看Connection对象是否已经被使用,所以数组里每一个Connection对象都要有一个使用标志。

我们再对连接池的功能进行分析,会发现每一个Connection对象还要一个上次访问时间和使用次数。

通过上面的分析,我们可以得出,连接池里的数组的元素应该是由对象组成,该对象的类可能如下:

Java代码

1.public class PoolConn  

2.{  

3.        private Connection conn;  

4.        private boolean isUse;  

5.        private long lastAccess;  

6.        private int useCount;  

7.        ……  

8.}  

publicclassPoolConn

{

privateConnectionconn;

privatebooleanisUse;

privatelonglastAccess;

privateintuseCount;

……

}

下面的省略号省掉的是关于四个属性的一些get和set方法。

我们可以看到这个类的核心就是Connection,其他的一些属性都是Connection的一些标志。

可以说这个类只有在连接池这个类里有用,其他地方用不到。

这时候,我们就该考虑是不是可以把这个类作为一个内部类呢?

而且我们把它作为一个内部类以后,可以把它定义成一个私有类,然后将它的属性公开,这样省掉了那些无谓的get和set方法。

下面我们就试试看:

Java代码

1.public class ConnectPool implements Pool  

2.{  

3.        //存在Connection的数组  

4.        private PoolConn[] poolConns;  

5.        //连接池的最小连接数  

6.        private int min;  

7.        //连接池的最大连接数  

8.        private int max;  

9.        //一个连接的最大使用次数  

10.        private int maxUseCount;  

11.        //一个连接的最大空闲时间  

12.        private long maxTimeout;  

13.        //同一时间的Connection最大使用个数  

14.        private int maxConns;  

15.        //定时器  

16.        private Timer timer;  

17.        public boolean init()  

18.        {  

19.               try  

20.               {  

21.                      ……  

22.                      this.poolConns = new PoolConn[this.min];  

23.                      for(int i=0;i

24.                      {  

25.                             PoolConn poolConn = new PoolConn();  

26.                             poolConn.conn = ConnectionManager.getConnection();  

27.                             poolConn.isUse = false;  

28.                             poolConn.lastAccess = new Date().getTime();  

29.                             poolConn.useCount = 0;  

30.                             this.poolConns[i] = poolConn;  

31.}  

32.……  

33.return true;  

34.               }  

35.               catch(Exception e)  

36.               {  

37.                      return false;  

38.}  

39.}  

40.……  

41.private class PoolConn  

42.{  

43.       public Connection conn;  

44.       public boolean isUse;  

45.public long lastAccess;  

46.       public int useCount;  

47.}  

48.}  

publicclassConnectPoolimplementsPool

{

//存在Connection的数组

privatePoolConn[]poolConns;

//连接池的最小连接数

privateintmin;

//连接池的最大连接数

privateintmax;

//一个连接的最大使用次数

privateintmaxUseCount;

//一个连接的最大空闲时间

privatelongmaxTimeout;

//同一时间的Connection最大使用个数

privateintmaxConns;

//定时器

privateTimertimer;

publicbooleaninit()

{

try

{

……

this.poolConns=newPoolConn[this.min];

for(inti=0;i

{

PoolConnpoolConn=newPoolConn();

poolConn.conn=ConnectionManager.getConnection();

poolConn.isUse=false;

poolConn.lastAccess=newDate().getTime();

poolConn.useCount=0;

this.poolConns[i]=poolConn;

}

……

returntrue;

}

catch(Exceptione)

{

returnfalse;

}

}

……

privateclassPoolConn

{

publicConnectionconn;

publicbooleanisUse;

publiclonglastAccess;

publicintuseCount;

}

}

因为本文不是专题来讲述数据库连接池的,所以在上面的代码中绝大部分的内容被省略掉了。

PoolConn类不大可能被除了ConnectionPool类的其他类使用到,把它作为ConnectionPool的私有内部类不会影响到其他类。

同时,我们可以看到,使用了内部类,使得我们可以将该内部类的数据公开,ConnectionPool类可以直接操作PoolConn类的数据成员,避免了因set和get方法带来的麻烦。

上面的一个例子,是使用内部类使得你的代码得到简化和方便。

还有些情况下,你可能要避免你的类被除了它的外部类以外的类使用到,这时候你却不得不使用内部类来解决问题。

场景二:

解决一些非面向对象的语句块

这些语句块包括if…elseif…else语句,case语句,等等。

这些语句都不是面向对象的,给我们造成了系统的扩展上的麻烦。

我们可以看看,在模式中,有多少模式是用来解决由if语句带来的扩展性的问题。

Java编程中还有一个困扰我们的问题,那就是try…catch…问题,特别是在JDBC编程过程中。

请看下面的代码:

Java代码

1.try  

2.         {  

3.                String[] divisionData = null;  

4.                conn = manager.getInstance().getConnection();  

5.                stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?

 ?

) }");  

6.                stmt.setLong(1 ,productId.longValue() );  

7.                stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;  

8.                stmt.execute();  

9.                ResultSet rs = stmt.getCursor

(2);  

10.                int i = 0 ;  

11.                String strDivision = "";  

12.                while( rs.next() )  

13.                {  

14.                             strDivision += rs.getString("DIVISION_ID") + "," ;  

15.                  }  

16.                  int length = strDivision.length() ;  

17.                  if(length !

= 0 )  

18.                  {  

19.                         strDivision = strDivision.substring(0,length - 1);  

20.                  }  

21.                  divisionData = StringUtil.split(strDivision, ",") ;  

22.                  map.put("Division", strDivision ) ;  

23.                  LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;  

24.       }catch(Exception e)  

25.        {  

26.                       LoggerAgent.error("GetHeaderData", "getDivisionData",  

27.                                                     "SQLException:

 " + e);  

28.                       e.printStackTrace() ;  

29.   

30.       }finally  

31.        {  

32.                       manager.close(stmt);  

33.                       manager.releaseConnection(conn);  

34.        }  

try

{

String[]divisionData=null;

conn=manager.getInstance().getConnection();

stmt=(OracleCallableStatement)conn.prepareCall("{CallPM_GET_PRODUCT.HEADER_DIVISION(?

?

)}");

stmt.setLong(1,productId.longValue());

stmt.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);;

stmt.execute();

ResultSetrs=stmt.getCursor

(2);

inti=0;

StringstrDivision="";

while(rs.next())

{

strDivision+=rs.getString("DIVISION_ID")+",";

}

intlength=strDivision.length();

if(length!

=0)

{

strDivision=strDivision.substring(0,length-1);

}

divisionData=StringUtil.split(strDivision,",");

map.put("Division",strDivision);

LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue+"+strDivision+""+productId);

}catch(Exceptione)

{

LoggerAgent.error("GetHeaderData","getDivisionData",

"SQLException:

"+e);

e.printStackTrace();

}finally

{

manager.close(stmt);

manager.releaseConnection(conn);

}

这是我们最最常用的一个JDBC编程的代码示例。

一个系统有很多这样的查询方法,这段代码一般分作三段:

try关键字括起来的那段是用来做查询操作的,catch关键字括起来的那段需要做两件事,记录出错的原因和事务回滚(如果需要的话),finally关键字括起来的那段用来释放数据库连接。

我们的烦恼是:

try关键字括起来的那段是变化的,每个方法的一般都不一样。

而catch和finally关键字括起来的那两段却一般都是不变的,每个方法的那两段都是一样的。

既然后面那两段是一样的,我们就非常希望将它们提取出来,做一个单独的方法,然后让每一个使用到它们的方法调用。

但是,try…catch…finally…是一个完整的语句段,不能把它们分开。

这样的结果,使得我们不得不在每一个数据层方法里重复的写相同的catch…finally…这两段语句。

既然不能将那些讨厌的try…catch…finally…作为一个公用方法提出去,那么我们还是需要想其他的办法来解决这个问题。

不然我们老是写那么重复代码,真是既繁琐,又不容易维护。

我们容易想到,既然catch…finally…这两段代码不能提出来,那么我们能不能将try…里面的代码提出去呢?

唉哟,try…里面的代码是可变的呢。

怎么办?

既然try…里面的代码是可变的,这意味着这些代码是可扩展的,是应该由用户来实现的,对于这样的可扩展内容,我们很容易想到用接口来定义它们,然后由用户去实现。

这样以来我们首先定义一个接口:

Java代码

1.public interface DataManager  

2.{  

3.        public void manageData();  

4.}  

publicinterfaceDataManager

{

publicvoidmanageData();

}

我们需要用户在manageData()方法中实现他们对数据层访问的代码,也就是try…里面的代码。

然后我们使用一个模板类来实现所有的try…catch…finally…语句的功能,如下:

publicclassDataTemplate

{

       publicvoidexecute(DataManagerdm)

       {

              try

              {

                     dm.manageData();

}

catch(Exceptione)

{

      LoggerAgent.error("GetHeaderData","getDivisionData",

                       "SQLException:

"+e);

      e.printStackTrace();

}finally

{

      manager.close(stmt);

      manager.releaseConnection(conn);

}

}

}

这样,一个模板类就完成了。

我们也通过这个模板类将catch…finally…两段代码提出来了。

我们来看看使用了这个模板类的数据层方法是怎么实现的:

newDataTemplate().execute(newDataManager()

{

       publicvoidmanageData()

       {

               String[]divisionData=null;

               conn=manager.getInstance().getConnection();

               stmt=(OracleCallableStatement)conn.prepareCall("{CallPM_GET_PRODUCT.HEADER_DIVISION(?

?

)}");

               stmt.setLong(1,productId.longValue());

               stmt.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);;

               stmt.execute();

               ResultSetrs=stmt.getCursor

(2);

               inti=0;

               StringstrDivision="";

               while(rs.next())

               {

         

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1