最新幕后英雄的用武之地——浅谈Java内部类的四个应用场景,阿里架构师的Java知识地图(28个知识点)

最后

这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。

image

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!!!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

strDivision += rs.getString(“DIVISION_ID”) + “,” ;

}

int length = 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(Exception e)

{

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…里面的代码是可变的,这意味着这些代码是可扩展的,是应该由用户来实现的,对于这样的可扩展内容,我们很容易想到用接口来定义它们,然后由用户去实现。这样以来我们首先定义一个接口:

public interface DataManager

{

public void manageData();

}

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

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

public class DataTemplate

{

public void execute(DataManager dm)

{

try

{

dm.manageData();

}

catch(Exception e)

{

LoggerAgent.error(“GetHeaderData”, “getDivisionData”,

"SQLException: " + e);

e.printStackTrace() ;

}finally

{

manager.close(stmt);

manager.releaseConnection(conn);

}

}

}

这样,一个模板类就完成了。我们也通过这个模板类将catch…finally…两段代码提出来了。我们来看看使用了这个模板类的数据层方法是怎么实现的:

new DataTemplate().execute(new DataManager()

{

public void manageData()

{

String[] divisionData = null;

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

stmt = (OracleCallableStatement)conn.prepareCall(“{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }”);

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

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

stmt.execute();

ResultSet rs = stmt.getCursor(2);

int i = 0 ;

String strDivision = “”;

while( rs.next() )

{

strDivision += rs.getString(“DIVISION_ID”) + “,” ;

}

int length = 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) ;

}

});

注意:本段代码仅供思路上的参考,没有经过上机测试。

我们可以看到,正是这个实现了DataManager接口得匿名内部类的使用,才使得我们解决了对try…catch…finally…语句的改造。这样,第一为我们解决了令人痛苦的重复代码;第二也让我们在数据层方法的编码中,直接关注对数据的操作,不用关心那些必需的但是与数据操作无关的东西。

我们现在来回想一下Spring框架的数据层,是不是正是使用了这种方法呢?

场景之三:一些多算法场合

假如我们有这样一个需求:我们的一个方法用来对数组排序并且依次打印各元素,对数组排序方法有很多种,用哪种方法排序交给用户自己确定。

对于这样一个需求,我们很容易解决。我们决定给哪些排序算法定义一个接口,具体的算法实现由用户自己完成,只要求他实现我们的接口就行。

public interface SortAlgor

{

public void sort(int[] is);

}

这样,我们再在方法里实现先排序后打印,代码如下:

public void printSortedArray(int[] is,SortAlgor sa)

{

……

sa.sort(is);

for(int i=0;i<is.length;i++)

{

System.out.print(is[i]+” “);

}

System.out.println();

}

客户端对上面方法的使用如下:

int[] is = new int[]{3,1,4,9,2};

printSortedArray(is,new SortAlgor()

{

public void sort(is)

{

int k = 0;

for(int i=0;i<is.length;i++)

{

for(int j=i+1;j<is.length;j++)

{

if(is[i]>is[j])

{

k = is[i];

is[i] = is[j];

is[j] = k;

}

}

}

}

});

这样的用法很多,我们都或多或少的被动的使用过。如在Swing编程中,我们经常需要对组件增加监听器对象,如下所示:

spinner2.addChangeListener(new ChangeListener()

{

public void stateChanged(ChangeEvent e)

{

System.out.println("Source: " + e.getSource());

}

}

);

在Arrays包里,对元素为对象的数组的排序:

Arrays.sort(emps,new Comparator(){

Public int compare(Object o1,Object o2)

{

return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();

}

});

这样的例子还有很多,JDK教会了我们很多使用内部类的方法。随时我们都可以看一看API,看看还会在什么地方使用到内部类呢?

场景之四:适当使用内部类,使得代码更加灵活和富有扩展性

适当的使用内部类,可以使得你的代码更加灵活和富有扩展性。当然,在这里头起作用的还是一些模式的运行,但如果不配以内部类的使用,这些方法的使用效果就差远了。不信?请看下面的例子:

我们记得简单工厂模式的作用就是将客户对各个对象的依赖转移到了工厂类里。很显然,简单工厂模式并没有消除那些依赖,只是简单的将它们转移到了工厂类里。如果有新的对象增加进来,则我们需要修改工厂类。所以我们需要对工厂类做进一步的改造,进一步消除它对具体类的依赖。以前我们提供过一个使用反射来消除依赖的方法;这里,我们将提供另外一种方法。

这种方法是将工厂进一步抽象,而将具体的工厂类交由具体类的创建者来实现,这样,工厂类和具体类的依赖的问题就得到了解决。而工厂的使用者则调用抽象的工厂来获得具体类的对象。如下。

我们以一个生产形体的工厂为例,下面是这些形体的接口:

package polyFactory;

public interface Shape {

public void draw();

public void erase();

}

通过上面的描述,大家都可能已经猜到,这个抽象的工厂肯定使用的是模板方法模式。如下:

package polyFactory;

import java.util.HashMap;

import java.util.Map;

public abstract class ShapeFactory {

protected abstract Shape create();

private static Map factories = new HashMap();

public static void addFactory(String id,ShapeFactory f)

{

factories.put(id,f);

}

public static final Shape createShape(String id)

{

if(!factories.containsKey(id))

{

try

{

Class.forName(“polyFactory.”+id);

}

catch(ClassNotFoundException e)

{

throw new RuntimeException("Bad shape creation : "+id);

}

}

return ((ShapeFactory)factories.get(id)).create();

}

}

不错,正是模板方法模式的运用。这个类蛮简单的:首先是一个create()方法,用来产生具体类的对象,留交各具体工厂实现去实现。然后是一个Map类型的静态变量,用来存放具体工厂的实现以及他们的ID号。接着的一个方法使用来增加一个具体工厂的实现。最后一个静态方法是用来获取具体对象,里面的那个Class.forName……的作用是调用以ID号为类名的类的一些静态的东西。

下面,我们来看具体的类的实现:

package polyFactory;

public class Circle implements Shape {

public void draw() {

// TODO Auto-generated method stub

System.out.println(“the circle is drawing…”);

}

public void erase() {

// TODO Auto-generated method stub

System.out.println(“the circle is erasing…”);

}

private static class Factory extends ShapeFactory

{

protected Shape create()

{

return new Circle();

}

}

static {ShapeFactory.addFactory(“Circle”,new Factory());}

}

这个类的其他的地方也平常得很。但就是后面的那个内部类Factory用得好。第一呢,这个类只做一件事,就是产生一个Circle对象,与其他类无关,就这一个条也就满足了使用内部类的条件。第二呢,这个Factory类需要是静态的,这也得要求它被使用内部类,不然,下面的ShapeFacotry.addFactory就没办法add了。而最后的那个静态的语句块是用来将具体的工厂类添加到抽象的工厂里面去。在抽象工厂里调用Class.forName就会执行这个静态的语句块了。

下面仍然是一个具体类:

package polyFactory;

最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

.(img-MMzt0M3L-1715670689051)]

MySQL面试专题

[外链图片转存中…(img-CMbVoz1h-1715670689052)]

Netty面试专题

[外链图片转存中…(img-dCVvGnmJ-1715670689052)]

RabbitMQ面试专题

[外链图片转存中…(img-oJlH0nyd-1715670689052)]

Redis面试专题

[外链图片转存中…(img-FNDO1BJ8-1715670689053)]

Spring Cloud面试专题

[外链图片转存中…(img-h7d9ybzD-1715670689053)]

SpringBoot面试专题

[外链图片转存中…(img-m7ixqqTT-1715670689053)]

zookeeper面试专题

[外链图片转存中…(img-kMjyNf9X-1715670689053)]

常见面试算法题汇总专题

[外链图片转存中…(img-GMb0c9OE-1715670689054)]

计算机网络基础专题

[外链图片转存中…(img-lw0kOe3N-1715670689054)]

设计模式专题

[外链图片转存中…(img-D48SGPFB-1715670689054)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>