首页 文章 精选 留言 我的

精选列表

搜索[整理],共9147篇文章
优秀的个人博客,低调大师

MaxCompute问答整理之2020-01月

问题一、如果把MaxCompute计算费用从按量付费变为包年包月,是否会引起数据变化或者服务重启?不会,目前,MaxCompute支持在按量计费和包年包月两种计费方式之间进行转换,但您必须提前开通好两种模式的MaxCompute资源。具体限制以及操作步骤可参考官方文档:https://help.aliyun.com/document_detail/35455.html 问题二、在MaxCompute中可以在Java业务代码中调起一个任务开始执行吗?可以,在业务代码中调MaxCompute的Java sdk执行SQL任务。可参考官方文档:https://help.aliyun.com/document_detail/34614.html 问题三、在MaxCompute中如何获取系统当前时间?可以使用MaxCompute内建函数GETDA

优秀的个人博客,低调大师

2018年java技术面试题整理

1、servlet执行流程 客户端发出http请求,web服务器将请求转发到servlet容器,servlet容器解析url并根据web.xml找到相对应的servlet,并将request、response对象传递给找到的servlet,servlet根据request就可以知道是谁发出的请求,请求信息及其他信息,当servlet处理完业务逻辑后会将信息放入到response并响应到客户端。 2、springMVC的执行流程 springMVC是由dispatchservlet为核心的分层控制框架。首先客户端发出一个请求web服务器解析请求url并去匹配dispatchservlet的映射url,如果匹配上就将这个请求放入到dispatchservlet,dispatchservlet根据mapping映射配置去寻找相对应的handel,然后把处理权交给找到的handel,handel封装了处理业务逻辑的代码,当handel处理完后会返回一个逻辑视图modelandview给dispatchservlet,此时的modelandview是一个逻辑视图不是一个正式视图,所以dispatchservlet会通过viewresource视图资源去解析modelandview,然后将解析后的参数放到view中返回到客户端并展现。 3、给定一个txt文件,如何得到某字符串出现的次数 1 File file = new File("E://test.txt"); 2 InputStream is = new FileInputStream(file); 3 byte b[] = new byte[1024]; 4 int a = is.read(b); 5 String str[] = new String(b,0,a).split(""); 6 int count = 0; 7 for(int i = 0;i<str.length;i++){ 8 if("a".equals(str[i]))count++; 9 } 10 System.out.println(count); 4、Java设计模式思想(单列模式,工厂模式,策略模式,共23种设计模式) a) 单例模式:单例模式核心只需要new一个实例对象的模式,比如数据库连接,在线人数等,一些网站上看到的在线人数统计就是通过单例模式实现的,把一个计时器存放在数据库或者内存中,当有人登陆的时候取出来加一再放回去,有人退出登陆的时候取出来减一再放回去,但是当有两个人同时登陆的时候,会同时取出计数器,同时加一,同时放回去,这样的话数据就会错误,所以需要一个全局变量的对象给全部人使用,只需要new出一个实例对象,这就是单例模式的应用,并且单例模式节省资源,因为它控制了实例对象的个数,并有利于gc回收。 b) 策略模式:就是将几个类中公共的方法提取到一个新的类中,从而使扩展更容易,保证代码的可移植性,可维护性强。比如有个需求是写鸭子对象,鸭子有叫,飞,外形这三种方法,如果每个鸭子类都写这三个方法会出现代码的冗余,这时候我们可以把鸭子中的叫,飞,外形这三个方法提取出来,放到鸭父类中,让每个鸭子都继承这个鸭父类,重写这三个方法,这样封装的代码可移植性强,当用户提出新的需求比如鸭子会游泳,那么对于我们oo程序员来讲就非常简单了我们只需要在鸭父类中加一个游泳的方法,让会游泳的鸭子重写游泳方法就可以了。 c) 工厂模式:简单的工厂模式主要是统一提供实例对象的引用,通过工厂模式接口获取实例对象的引用。比如一个登陆功能,后端有三个类,controller类,interface类,实现接口的实现类。当客户端发出一个请求,当请求传到controller类中时,controller获取接口的引用对象,而实现接口的实现类中封装好了登陆的业务逻辑代码。当你需要加一个注册需求的时候只需要在接口类中加一个注册方法,实现类中实现方法,controller获取接口的引用对象即可,不需要改动原来的代码,这种做法是的可拓展性强。 5、冒泡排序、二分查找 a) 冒泡 ? 1 public static void mp(int a[]) { 2 int swap = 0; 3 for (int i = 0; i < a.length; i++) { 4 for (int j = i; j < a.length; j++) { 5 if (a[j] > a[i]) { 6 swap = a[i]; 7 a[i] = a[j]; 8 a[j] = swap; 9 } 10 } 11 } 12 System.out.println(Arrays.toString(a)); 13 } b)二分查找 ? 1 public static int ef(int a[], int tag) { 2 int first = 0; 3 int end = a.length; 4 for (int i = 0; i < a.length; i++) { 5 int middle = (first + end) / 2; 6 if (tag == a[middle]) { 7 return middle; 8 } 9 if (tag > a[middle]) { 10 first = middle + 1; 11 } 12 if (tag < a[middle]) { 13 end = middle - 1; 14 } 15 } 16 return 0; 17 } 6-8、对ajax的理解 a) Ajax为异步请求,即局部刷新技术,在传统的页面中,用户需要点击按钮或者事件触发请求,到刷新页面,而异步技术为不需要点击即可触发事件,这样使得用户体验感增强,比如商城购物车的异步加载,当你点击商品时无需请求后台而直接动态修改参数。 9、父类与子类之间的调用顺序(打印结果) a) 父类静态代码块 b) 子类静态代码块 c) 父类构造方法 d) 子类构造方法 e) 子类普通方法 f) 重写父类的方法,则打印重写后的方法 10、内部类与外部类的调用 a) 内部类可以直接调用外部类包括private的成员变量,使用外部类引用的this.关键字调用即可 b) 而外部类调用内部类需要建立内部类对象 11、多线程 a)一个进程是一个独立的运行环境,可以看做是一个程序,而线程可以看做是进程的一个任务,比如QQ是一个进程,而一个QQ窗口是一个线程。 b)在多线程程序中,多线程并发可以提高程序的效率,cpu不会因为某个线程等待资源而进入空闲状态,它会把资源让给其他的线程。 c)用户线程就是我们开发程序是创建的线程,而守护线程为系统线程,如JVM虚拟中的GC d)线程的优先级别:每一个线程都有优先级别,有限级别高的可以先获取CPU资源使该线程从就绪状态转为运行状态。也可以自定义线程的有限级别 e)死锁:至少两个以上线程争取两个以上cpu资源,避免死锁就避免使用嵌套锁,只需要在他们需要同步的地方加锁和避免无限等待 12、AOP与IOC的概念(即spring的核心) a) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度。而spring的核心是IOC控制反转和AOP面向切面编程。IOC控制反转主要强调的是程序之间的关系是由容器控制的,容器控制对象,控制了对外部资源的获取。而反转即为,在传统的编程中都是由我们创建对象获取依赖对象,而在IOC中是容器帮我们创建对象并注入依赖对象,正是容器帮我们查找和注入对象,对象是被获取,所以叫反转。 b) AOP:面向切面编程,主要是管理系统层的业务,比如日志,权限,事物等。AOP是将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为切面(aspect),切面将那些与业务逻辑无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。 13、hibernate的核心思想 a) Hibernate的核心思想是ROM对象关系映射机制。它是将表与表之间的操作映射成对象与对象之间的操作。也就是从数据库中提取的信息会自动按照你设置的映射要求封装成特定的对象。所以hibernate就是通过将数据表实体类的映射,使得对对象的修改对应数据行的修改。 14、Struts1与Struts2的区别 15、最优删除谋字符串的某个字符 16-17、Arraylist与linkedlist的区别 a) 都是实现list接口的列表,arraylist是基于数组的数据结构,linkedlist是基于链表的数据结构,当获取特定元素时,ArrayList效率比较快,它通过数组下标即可获取,而linkedlist则需要移动指针。当存储元素与删除元素时linkedlist效率较快,只需要将指针移动指定位置增加或者删除即可,而arraylist需要移动数据。 18、数据库优化 a) 选择合适的字段,比如邮箱字段可以设为char(6),尽量把字段设置为notnull,这样查询的时候数据库就不需要比较null值 b) 使用关联查询( left join on)查询代替子查询 c) 使用union联合查询手动创建临时表 d) 开启事物,当数据库执行多条语句出现错误时,事物会回滚,可以维护数据库的完整性 e) 使用外键,事物可以维护数据的完整性但是它却不能保证数据的关联性,使用外键可以保证数据的关联性 f) 使用索引,索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快的多的速度检索特定的行,特别是对于max,min,order by查询时,效果更明显 g) 优化的查询语句,绝大多数情况下,使用索引可以提高查询的速度,但如果sql语句使用不恰当的话,索引无法发挥它的特性。 19、Tomcat服务器优化(内存,并发连接数,缓存) a) 内存优化:主要是对Tomcat启动参数进行优化,我们可以在Tomcat启动脚本中修改它的最大内存数等等。 b) 线程数优化:Tomcat的并发连接参数,主要在Tomcat配置文件中server.xml中配置,比如修改最小空闲连接线程数,用于提高系统处理性能等等。 c) 优化缓存:打开压缩功能,修改参数,比如压缩的输出内容大小默认为2KB,可以适当的修改。 20、HTTP协议 a) 常用的请求方法有get、post b) Get与post的区别:传送数据,get携带参数与访问地址传送,用户可以看见,这的话信息会不安全,导致信息泄露。而post则将字段与对应值封装在实体中传送,这个过程用户是不可见的。Get传递参数有限制,而post无限制。 21、TCP/UDP协议 22、Java集合类框架的基本接口有哪些 a) Collection集合接口,List、set实现Collection接口,arraylist、linkedlist,vector实现list接口,stack继承vector,Map接口,hashtable、hashmap实现map接口 23、类加载的过程 a) 遇到一个新的类时,首先会到方法区去找class文件,如果没有找到就会去硬盘中找class文件,找到后会返回,将class文件加载到方法区中,在类加载的时候,静态成员变量会被分配到方法区的静态区域,非静态成员变量分配到非静态区域,然后开始给静态成员变量初始化,赋默认值,赋完默认值后,会根据静态成员变量书写的位置赋显示值,然后执行静态代码。当所有的静态代码执行完,类加载才算完成。 24、对象的创建 a) 遇到一个新类时,会进行类的加载,定位到class文件 b) 对所有静态成员变量初始化,静态代码块也会执行,而且只在类加载的时候执行一次 c) New 对象时,jvm会在堆中分配一个足够大的存储空间 d) 存储空间清空,为所有的变量赋默认值,所有的对象引用赋值为null e) 根据书写的位置给字段一些初始化操作 f) 调用构造器方法(没有继承) 25、jvm的优化 a) 设置参数,设置jvm的最大内存数 b) 垃圾回收器的选择 26、高并发处理 a) 了解一点高并发性问题,比如一W人抢一张票时,如何保证票在没买走的情况下所有人都能看见这张票,显然是不能用同步机制,因为synchronize是锁同步一次只能一个人进行。这时候可以用到锁机制,采用乐观锁可以解决这个问题。乐观锁的简单意思是在不锁定表的情况下,利用业务的控制来解决并发问题,这样即保证数据的可读性,又保证保存数据的排他性,保证性能的同时解决了并发带来的脏读数据问题。 27、事物的理解 a) 事物具有原子性,一致性,持久性,隔离性 b) 原子性:是指在一个事物中,要么全部执行成功,要么全部失败回滚。 c) 一致性:事物执行之前和执行之后都处于一致性状态 d) 持久性:事物多数据的操作是永久性 e) 隔离性:当一个事物正在对数据进行操作时,另一个事物不可以对数据进行操作,也就是多个并发事物之间相互隔离。 28、Struts工作流程 a) 客户端发出一个请求到servlet容器 b) 请求经过一些列过滤被filterdispatcher调用,filterdispatch通过actionMapper去找相对应的action。 c) Actionmapper找到对应的action返回给filterdispatch,dispatch把处理权交给actionproxy d) Actionproxy通过配置文件找到对应的action类 e) Actionproxy创建一个actionIinvocation的实例处理业务逻辑 f) 一旦action处理完毕,actioninvocation负责根据stuts.xml的配置找到对应的返回结果。返回结果通常是jsp页面。 以上就是java技术面试题,小编个人觉得还是需要时刻提升自己的技术。给大家推荐一个程序员学习交流群:960439918。群里有分享的视频,还有思维导图主要分享分布式架构、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战学习架构师视频。

优秀的个人博客,低调大师

高级 Java 面试通关知识点整理

1、常用设计模式 单例模式:懒汉式、饿汉式、双重校验锁、静态加载,内部类加载、枚举类加载。保证一个类仅有一个实例,并提供一个访问它的全局访问点。 代理模式:动态代理和静态代理,什么时候使用动态代理。 适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 装饰者模式:动态给类加功能。 观察者模式:有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 策略模式:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 外观模式:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 命令模式:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。 创建者模式:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 2、基础知识 Java基本类型哪些,所占字节和范围 Set、List、Map的区别和联系 什么时候使用Hashmap 什么时候使用Linkedhashmap、Concurrenthashmap、Weakhashmap 哪些集合类是线程安全的 为什么Set、List、map不实现Cloneable和Serializable接口 Concurrenthashmap的实现,1.7和1.8的实现 Arrays.sort的实现 什么时候使用CopyOnArrayList volatile的使用 synchronied的使用 reentrantlock的实现和Synchronied的区别 CAS的实现原理以及问题 AQS的实现原理 接口和抽象类的区别,什么时候使用 类加载机制的步骤,每一步做了什么,static和final修改的成员变量的加载时机 双亲委派模型 反射机制:反射动态擦除泛型、反射动态调用方法等 动态绑定:父类引用指向子类对象 JVM内存管理机制:有哪些区域,每个区域做了什么 JVM垃圾回收机制:垃圾回收算法 垃圾回收器 垃圾回收策略 jvm参数的设置和jvm调优 什么情况产生年轻代内存溢出、什么情况产生年老代内存溢出 内部类:静态内部类和匿名内部类的使用和区别 Redis和memcached:什么时候选择redis,什么时候选择memcached,内存模型和存储策略是什么样的 MySQL的基本操作 主从数据库一致性维护 mysql的优化策略有哪些 mysql索引的实现 B+树的实现原理 什么情况索引不会命中,会造成全表扫描 java中bio nio aio的区别和联系 为什么bio是阻塞的 nio是非阻塞的 nio是模型是什么样的 Javaio的整体架构和使用的设计模式 Reactor模型和Proactor模型 http请求报文结构和内容 http三次握手和四次挥手 rpc相关:如何设计一个rpc框架,从io模型 传输协议 序列化方式综合考虑 Linux命令 统计,排序,前几问题等 StringBuff 和StringBuilder的实现,底层实现是通过byte数据,外加数组的拷贝来实现的 cas操作的使用 内存缓存和数据库的一致性同步实现 微服务的优缺点 线程池的参数问题 ip问题 如何判断ip是否在多个ip段中 判断数组两个中任意两个数之和是否为给定的值 乐观锁和悲观锁的实现 synchronized实现原理 你在项目中遇到的困难和怎么解决的 你在项目中完成的比较出色的亮点 消息队列广播模式和发布/订阅模式的区别 生产者消费者代码实现 死锁代码实现 线程池:参数,每个参数的作用,几种不同线程池的比较,阻塞队列的使用,拒绝策略 Future和ListenableFuture 异步回调相关 算法相关:判断能否从数组中找出两个数字和为给定值,随机生成1~10000不重复并放入数组,求数组的子数组的最大和,二分查找算法的实现及其时间复杂计算 3、其它 算法:常用排序算法,二分查找,链表相关,数组相关,字符串相关,树相关等 常见序列化协议及其优缺点 memcached内存原理,为什么是基于块的存储 搭建一个rpc需要准备什么 如果线上服务器频繁地出现full gc ,如何去排查 如果某一时刻线上机器突然量变得很大,服务扛不住了,怎么解决 LUR算法的实现 LinkedHashMap实现LRU 定义栈的数据结构,请在该类型中实现一个能够找到栈最小元素的min函数 海量数据处理的解决思路 reactor模型的演变 阻塞、非阻塞、同步、异步区别 Collection的子接口 jvm调优相关 zookeeper相关,节点类型,如何实现服务发现和服务注册 nginx负载均衡相关,让你去实现负载均衡,该怎么实现 linux命令,awk、cat、sort、cut、grep、uniq、wc、top等 压力测试相关,怎么分析,单接口压测和多情况下的压测 你觉得你的有点是什么,你的缺点是什么 springmvc的实现原理 netty底层实现,IO模型,ChannelPipeline的实现和原理 缓存的设计和优化 缓存和数据库一致性同步解决方案 你所在项目的系统架构,谈谈整体实现 消息队列的使用场景 ActiveMQ、RabbitMQ、Kafka的区别 欢迎大家加入Java架构开发:744677563 本群提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导 进群修改群备注:开发年限-地区-经验 方便架构师解答问题

优秀的个人博客,低调大师

java并发编程笔记--Executor相关API整理

Executor框架是concurrent包提供的用于执行线程任务的框架,它基于生产者-消费者模式实现,将提交任务的线程和执行任务的线程解耦。提交任务的线程视作生产者,执行任务的线程视作消费者。任务的执行策略可以通过定制不同的消费者实现,比如:任务可以同步执行,也可以异步执行;任务可以按照编排优先级,高优先级的任务可以优先执行;任务可以延迟执行或者按周期执行...这些实现对于生产者而言透明,生产者无需关注消费者的具体实现,仅需要按照业务需求提交任务即可。 类图 Executor接口定义了concurrent包线程任务执行的入口,其扩展接口和实现类形成了一套满足线程任务执行的通用框架。 Executor接口 一个线程任务的执行入口,包含一个execute方法,接收Runnable参数,用于解耦线程任务的提交和执行。execute方法依赖于具体的实现,即可以在提交任务的线程中执行线程任务,也可以启动新的线程异步执行,或者将提交的任务进行编排按照一定规则执行。 ExecutorService接口 作为Executor的扩展,分离了任务的执行(execute)和提交方法(submit/invoke*)。包含3种状态: 运行(running):ExecutorService创建后的状态,表示执行器处于正常状态,可以接受任务; 关闭(shutdown):执行shutdown/shutdownNow后的状态,此时不再接受新任务,且等待ExecutorService中的工作线程终止; 终止(terminated):ExecutorService中的所有工作线程终止运行,可通过isTerminated判断是否终止;通过awaitTermination同步等待终止; ExecutorService定义了多个方法实现对线程任务状态更加精细的控制,扩展方法包括: void shutdown():触发Executor关闭操作,Executor在关闭前会等待已经提交的任务执行完成后才关闭。shutdown方法触发关闭操作后即刻返回,并不会等待任务执行完成才返回; List shutdownNow():触发Executor关闭操作,停止所有正在执行的任务,并返回所有等待执行的任务列表; boolean isShutdown():是否已经触发Executor的关闭操作,当执行shutdown/shutdownNow方法后,该方法返回true; boolean isTerminated():是否已经结束关闭操作;当关闭操作触发时,Executor并不一定立即关闭,可能需要等待已经提交任务执行完成后才关闭,因此只有当Executor真正执行完关闭操作后,该方法返回true; boolean awaitTermination(long timeout, TimeUnit unit):调用该方法的线程会阻塞等待,直到Executor执行完关闭操作;阻塞期间可能因超时(返回false)或者被中断(抛出InterruptedException异常)返回; Future submit(Callable task):提交一个线程任务,返回一个Futrue对象,以便接收和处理线程执行结果; Future submit(Runnable task, T result):同上,因为Runnable的run方法没有返回值,故单独用一个参数存放执行结果; Future<?> submit(Runnable task):同上; List> invokeAll(Collection<? extends Callable> tasks):批量提交任务,同步等待全部任务执行完并返回Future对象集合存放每个任务的执行结果; List> invokeAll(Collection<? extends Callable> tasks, long timeout, TimeUnit unit):同上,允许设置超时时间; T invokeAny(Collection<? extends Callable> tasks):执行所提交的任务,同步等待第一个已经执行完成的任务并返回结果,其余未完成任务将被取消执行; T invokeAny(Collection<? extends Callable> tasks, long timeout, TimeUnit unit):同上,允许设置超时时间; 面试问题:Runnable接口和Callable接口有何异同?相同点:均被设计用来抽象线程任务的执行,将任务的提交和任务的执行解耦,使得任务的提交和执行可以放在不同的线程中执行;不同点:Callable接口允许返回计算结果,也可以抛出异常,在任务执行过程中可以异步的捕获异常,也可以获取线程执行结果;而Runnable接口不允许这样做,通常异常处理需要放在接口内实现,计算结果也无法直接返回,需要借助消息队列等其它数据结构和组件实现; 注意:是用execute方法和submit方法提交任务在异常处理上存在区别:execute提交的任务在执行时如果抛出未捕获异常,则可以由java.lang.Thread.UncaughtExceptionHandler捕获处理。而submit提交的任务执行过程中如果抛出未捕获异常,将被视为任务执行结果的一部分,异常通过返回Future.get封装在ExecutionException中抛出。 ScheduledExecutorService接口 定时任务执行入口,允许延迟或者周期性调度线程任务,类似java.util.Timer的调度功能。 面试问题:java.util.Timer和ScheduledExecutorService接口的实现有何异同? 提交任务参数不同:Timer的任务参数必须是TimerTask类型;而ScheduledExecutorService参数相对灵活,可以是Runnable也可以是Callable类型; 调度线程不同:一个Timer对象包含一个TimerThread和一个TaskQueue对象,TimerThread线程用于调度所有的TimerTask任务,TaskQueue负责存放当前Timer对象等待调度的所有任务。TaskQueue是一个优先队列,基于堆实现,调度效率为log(n),任务通过下一次执行时间进行排序,以便保证最近的任务最先被调度执行。在创建Timer之后,TimerThread即已创建并且调用start方法启动,Timer调度任务是逐个调度,如果队列中的任务执行时间过长,将会导致整个任务序列执行时间的延迟。ScheduledExecutorService的实现类对执行任务的线程控制更加灵活,如ScheduledThreadPoolExecutor使用线程池来调度任务,可以同时调度多个任务,减少了因为任务排队执行而造成的延迟;当ScheduledThreadPoolExecutor指定的线程池大小为1时,效果等同于使用Timer; 时间单位不同:ScheduledExecutorService使用TimeUnit指定时间,更加灵活; 调度时间基准不同:Timer基于绝对时间调度,因而对操作系统的时钟变化敏感,一旦操作系统调整时钟,可能导致任务执行时间变化;ScheduledThreadPoolExecutor基于相对时间调度,因而对于系统时钟变化不敏感,具有更好的兼容性; Timer存在线程泄漏问题:Timer对于执行任务抛出的异常不作捕获处理,一旦任务抛出异常,将导致整个Timer不可用,累及其它待执行任务;而ScheduledThreadPoolExecutor可以正确处理任务抛出的异常; ScheduledExecutorService接口方法包括: ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit):以给定延迟调度一个一次性的任务,当任务执行完成后,ScheduledFuture<?>的get方法返回null; ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit):同上,在任务执行完后,返回Callable执行结果; ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):周期性的执行给定任务。任务第一次执行时延迟initialDelay时长,然后按照( initialDelay + period*( n - 1 ) ,n表示任务执行次数)固定周期执行;如果单次任务执行时间超过period,则下一次执行将会等待当次执行完成后立即执行,而不会并行执行; ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):周期性的执行给定任务。任务第一次执行时延迟initialDelay时长,然后按照( 上一次结束时间 + period )周期性执行,因而该方法执行任务的周期并不固定,会根据任务执行时间的长短变化;上一次任务结束到下一次任务执行开始,总是相隔period时长; 面试问题:ScheduledExecutorService接口的scheduleAtFixedRate与scheduleWithFixedDelay区别? 解释如上 AbstractExecutorService抽象类 作为ScheduledExecutorService的默认实现,实现了提交任务submit/invoke*方法,使用RunnableFuture作为返回结果(FutureTask作为默认实现类);未实现execute方法,等待子类实现; ThreadPoolExecutor类 基于线程池的ExecutorService的实现,底层通过线程池并发执行任务,从而提高执行效率,ThreadPoolExecutor本身即为一个线程池的实现,线程池中用于执行任务的线程称为工作线程。根据不同的场景,线程池的执行策略可能不同,需要通过一些列参数进行控制,包括:corePoolSize(核心工作线程数),maximumPoolSize(最大工作线程数),keepAliveTime,workQueue(任务队列),threadFactory(线程创建类),handler(提交任务被拒绝后的处理策略)。为了简化操作,concurrent包的Executors类提供了几种常用线程池的创建方法,用来简化操作。 corePoolSize与maximumPoolSize参数 1)当poolSize < corePoolSize(poolSize为线程池当前的大小,通过getPoolSize方法获取),线程池会新建一个core线程用来执行新来的任务,即便此时线程池中有空闲的线程;2)当corePoolSize <= poolSize <= maximumPoolSize,且任务队列未满,线程池将会优先将新来的任务放入workQueue中等待core线程执行;3)当corePoolSize <= poolSize < maximumPoolSize,且任务队列已满,线程池新建一个线程执行新到任务;4)当corePoolSize和maximumPoolSize设置相同时,则线程池大小固定;5)corePoolSize和maximumPoolSize可以被设置为整型的上限Integer.MAX_VALUE,然而线程池大小的设置依赖于业务需要,同时也受限于所在物理设备的资源(CPU个数、内存大小、文件句柄数等),因此一般情况下,线程池大小不应该设置过大。如果需要处理海量的并发任务,则考虑使用分布式方法来处理;6)corePoolSize和maximumPoolSize可以通过构造函数设置,也可以通过setter方法设置; prestartCoreThread / prestartAllCoreThreads方法 当线程池大小poolSize threadFactory参数 创建线程时可以指定线程名称,所属的ThreadGroup,线程的优先级,是否是守护线程等。有时创建线程时,我们希望这些参数都能够遵守一定规则,比如:创建的线程都归属于同一个ThreadGroup、线程名称以相同的前缀开始...ThreadFactory接口的定义就是为了创建某一类线程,通过不同的实现类实现对不同类型线程测创建。ThreadPoolExecutor默认使用DefaultThreadFactory作为线程创建的工厂类,该类创建的线程都归属于同一个ThreadGroup,线程名以统一的前缀开始,优先级都是Thread.NORM_PRIORITY,非守护线程。可以在构造函数中通过threadFactory参数进行定制。 注意:当ThreadFactory创建线程返回null时,ThreadPoolExecutor将继续运行,但是可能无法正常执行任务。 keepAliveTime参数 如果线程池的poolSize>corePoolSize,并且有空闲的非core线程,则当非core线程空闲时间达到keepAliveTime时,将会被回收,以便减少资源消耗。该参数可以通过构造函数指定,也可以通过setter方法动态指定。当设置为Long.MAX_VALUE时,表示线程永久保留。当keepAliveTime不为0,且同时设置allowCoreThreadTimeOut为true时,将会对core线程也执行相同的回收策略。 注:allowCoreThreadTimeOut设置为true还有一项额外的作用,即可以确保当ThreadPoolExecutor需要被terminate时,所有的工作线程均被shutdown。 workQueue参数 ThreadPoolExecutor中的workQueue用于暂存等待执行的任务。workQueue可以是任意BlockingQueue类型。workQueue的使用同poolSize相关。1)当poolSize < corePoolSize时,线程池将会通过新增core线程的方式处理新来的任务,而不会放入workQueue中;2)当corePoolSize <= poolSize <= maximumPoolSize时,且workQueue未满时,线程池将会优先将新来的任务放入workQueue中等待core线程执行;3)当corePoolSize <= poolSize < maximumPoolSize,且workQueue已满,线程池会新建非core线程处理新来的任务; workQueue常用的3种策略: 直接传递任务:使用SynchronousQueue,SynchronousQueue可以理解为一个size为0的阻塞队列,每一个任务提交都必须等待有对应的任务获取操作,省去了中间的存储和查找操作。如果当前池中没有线程接收正在提交的任务,则会新建一个线程,直到工作线程数达到maximumPoolSizes后开始驳回任务。为了避免任务驳回,通常需要设置maximumPoolSizes为不限制。当提交任务的速率大于处理任务的速率时,将会导致线程数的无限制增加。 无界队列:使用LinkedBlockingQueue等无界队列,当poolSize达到corePoolSize,并且没有core线程空闲时,新任务将会进入队列等待,由于队列长度没有限制,因而线程池中最多只会有corePoolSize个线程,此时maximumPoolSizes参数无效。该策略适合于任务之前没有依赖的情况,以确保任务执行不会相互影响,比如处理http请求时,即可使用该策略。当提交任务的速率大于处理任务的速率时,将会导致任务队列中任务的积压。 有界队列:使用ArrayBlockingQueue等有界队列,可以避免大量创建线程或者任务积压造成资源耗尽。但是,需要权衡queueSize和maximumPoolSizes设置。比如:I/O密集型任务可以设置较小的queueSize和较大的maximumPoolSizes,以便CPU资源被充分利用,避免因为等待I/O操作造成CPU资源不能够被充分利用。 注:只要是BlockingQueue的实现类可以被ThreadPoolExecutor使用,因而可以根据各种BlockingQueue的子类特性影响任务执行的顺序,比如:使用PriorityBlockingQueue能够将任务按照优先级排序,使得高优先级的任务能够被优先执行。使用DelayQueue则适合于执行延迟任务,队列中的任务会按照延迟时间排序,仅当任务超过延迟时间后,才可以执行take操作; ThreadPoolExecutor提供了对workQueue元素操作的外部方法,如getQueue()允许直接获取workQueue的引用,方便监控和调试;remove和purge方法允许删除workQueue中的元素。 RejectedExecutionHandler参数 RejectedExecutionHandler接口定义了当任务被线程池驳回时,需要执行的处理策略。任务驳回包括2种情况: 线程池已经shutdown; 线程池能够处理的任务已经达到饱和,如:poolSize达到maximumPoolSizes,且workQueue已满,此时新来的任务将会被驳回; concurrent包提供4种处理策略,用户也可以通过实现RejectedExecutionHandler接口自定义处理策略: AbortPolicy:中止策略,直接抛出RejectedExecutionException异常; CallerRunsPolicy:直接在调用execute方法的线程中执行被驳回的任务;该策略由于占用了任务提交线程,因而会降低任务提交的速率。等同于任务提交线程直接执行任务; DiscardPolicy:丢弃策略,将会丢弃被驳回的任务; DiscardOldestPolicy:丢弃最老任务策略,将会删除workQueue头部的任务,然后重新提交被驳回任务;如果任务一直被驳回,该策略将会一直重复执行; 注意:使用CallerRunsPolicy策略可能引起线程安全问题场景:假设任务访问了某种非线程安全的资源,为了保证线程安全,使用poolSize为1的线程池串行处理任务,如果任务被驳回,触发驳回策略使用外部线程重新执行,则可能和工作线程同时访问非线程安全的资源,引发线程安全问题。 回调方法 ThreadPoolExecutor提供了beforeExecute,afterExecute,terminated等回调用法,用于根据线程池的反馈执行相关操作。这些方法可以通过子类重写。 beforeExecute/afterExecute方法,会在每个任务执行前/后被调用,可以用作重置执行参数、打印日志、统计执行数据等; terminated方法,在ThreadPoolExecutor被termniate之后调用,可用于执行资源清理等操作; 线程池大小&工作队列大小设置的考量 很难精确的给出线程池应该设置的大小,需要根据业务运行的情况不断调整。但是我们也可以根据一些经验给出大概的大小。 CPU密集型:较小的poolSize和较大的workQueue;因为CPU密集型任务,资源的瓶颈主要在CPU,较小的poolSize可以保障cpu资源充分被用于任务执行,而非进行上下文切换;设置较大的workQueue可以确保充分接收更多的任务,提高吞吐。poolSize通常设置Ncpu+1个线程比较合适; I/O密集型:设置较大的poolSize和较小的workQueue;I/O密集型任务的瓶颈主要在I/O的等待,任务的I/O等待降低了工作线程处理速率,可能会导致后续任务的延迟,因此提高任务处理的并发度,能够有效减少I/O等待,故设置一个较大的poolSize。同时,为了保障任务不因为I/O等待而过多积压,造成时延增加,故设置一个较小的workQueue。 经验公式:Nthread = Ncpu Ucpu ( 1 + W/C )Nthread,计算得出的poolSize大小;Ncpu,可使用的cpu个数/核数;Ucpu,期望最高的cpu使用率,考虑需要限制CPU使用率的场景,不能够总是将CPU使用率估计为100%,因而使用此参数;W,线程的等待时间,需要自己统计求平均值;C,线程的运行时间,需要自己统计求平均值; 注:决定线程池数量上限的因素还包括一些内存、文件句柄、socket句柄、数据库连接等资源的限制,在设置时也应该考虑; ForkJoinPool类 主要用于执行ForkJoinTask任务,同时支持非ForkJoinTask类型的任务。ForkJoinPool的优点在于实现了『工作窃取算法』:池中的工作线程不仅可以执行外部的线程任务,同时也可以执行其它运行中的任务所产生的子任务。这种策略适合于处理任务产生大量子任务的场景,也适合于处理由外部提交的大量细小的任务; 静态方法commonPool返回一个通用的ForkJoinPool,可用来执行那些没有明确指定线程池的任务; 线程池支持的最大线程数为32767; ScheduledThreadPoolExecutor类 基于线程池的ScheduledExecutorService的实现,底层通过线程池并发调度任务,该类继承ThreadPoolExecutor,使用无界队列策略,即使用corePoolSize个线程和无界的workQueue; 不推荐将corePoolSize设置为0,或者allowCoreThreadTimeOut设置为true,因为当任务执行周期较长超过keepAliveTime时,可能导致任务执行时,池中的线程都被回收的情况; 当任务在执行前被cancel后,将不会被执行,任务不会从队列中立即删除,而是等到超过delay时间后,才会从队列中删除。通过setRemoveOnCancelPolicy(true)可以设置cancel后立即删除任务; 当一个任务同时被scheduleAtFixedRate和scheduleAtFixedRate调度,可能会在不同的线程中执行,但不会产生重叠执行的情况,因为前一次执行happens-before后一次执行; Executors类 Executors类的主要功能包括如下: 提供ExecutorService的创建方法,并使用DelegatedExecutorService包装,仅暴露接口方法,防止外部修改操作; 提供ScheduledExecutorService的创建方法,并使用DelegatedScheduledExecutorService包装,仅暴露接口方法,防止外部修改操作; 提供ThreadFactory的创建方法; 提供Callable类型转换方法; ExecutorService线程池相关工具方法 ExecutorService newSingleThreadExecutor() 无界队列策略,创建只有一个线程的线程池,因为使用了包装器,可以防止外部修改; ExecutorService newFixedThreadPool(int nThreads) 无界队列策略,创建固定大小的线程池,使用无界队列;keepAliveTime为0; ExecutorService newCachedThreadPool() 直接传递任务策略,使用SynchronousQueue作为workQueue; ExecutorService newCachedThreadPool(ThreadFactory threadFactory) ScheduledExecutorService newSingleThreadScheduledExecutor() 创建单线程的任务调度; ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建指定线程池大小的任务调度; ExecutorService newWorkStealingPool(int parallelism) 创建一个ForkJoinPool,使用parallelism指定并发度; ExecutorService newWorkStealingPool() 创建ForkJoinPool,使用处理器个数作为并发度;

优秀的个人博客,低调大师

java工程师面试经典题目整理

本人已面试成功 1、面向对象的特征有哪些方面? 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。 2、访问修饰符public,private,protected,以及不写(默认)时的区别? 作用域当前类同包子类其他 public√√√√ protected√√√× default√√×× private√××× 类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。 3、构造器(constructor)是否可被重写(override)? 答:构造器不能被继承,因此不能被重写,但可以被重载。 4、两个对象值相同(x.equals(y)==true),但却可有不同的hashcode,这句话对不对? 答:不对,如果两个对象x和y满足x.equals(y)==true,它们的哈希码(hashcode)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。 5、抽象类(abstractclass)和接口(interface)有什么异同? 答:抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。抽象类和接口中都可以包含静态成员变量。 6、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰? 答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。 7、接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concreteclass)? 答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。 8、AnonymousInnerClass(匿名内部类)是否可以继承其它类?是否可以实现接口? 答:可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。 9、数据类型之间的转换: 1)如何将字符串转换为基本数据类型? 2)如何将基本数据类型转换为字符串? 1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;Integer.parseInt(a)Integer.valueOf(a) 2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String类中的valueOf(…)方法返回相应字符串String.valueOf(int)Integer.toString 10、如何实现字符串的反转及替换? 答:方法很多,可以自己写实现也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示: [java] view plain copy 1.publicstaticStringreverse(StringoriginStr){ 2.if(originStr==null||originStr.length()<=1) 3.returnoriginStr; 4.returnreverse(originStr.substring(1))+originStr.charAt(0); 5.} 11、列出一些你常见的运行时异常? 答: ArithmeticException(算术异常) ClassCastException(类转换异常) IllegalArgumentException(非法参数异常) IndexOutOfBoundsException(下表越界异常) NullPointerException(空指针异常) SecurityException(安全异常) 12、List、Map、Set三个接口存取元素时,各有什么特点? 答:List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-valuepair)映射,映射关系可以是一对一或多对一。Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。 13、什么是进程,什么是线程?为什么需要多线程编程? 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位; 线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位。 线程的划分尺度小于进程,这使得多线程程序的并发性高;进程在执行时通常拥有独立的内存单元,而线程之间可以共享内存。使用多线程的编程通常能够带来更好的性能和用户体验,但是多线程的程序对于其他程序是不友好的,因为它占用了更多的CPU资源。 14.阐述JDBC操作数据库的步骤 答:下面的代码以连接本机的Oracle数据库为例,演示JDBC操作数据库的步骤。 1.加载驱动。 [java] view plain copy Class.forName("oracle.jdbc.driver.OracleDriver"); 2.创建连接。 [java] view plain copy Connectioncon=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger"); 3.创建语句。 [java] view plain copy PreparedStatementps=con.prepareStatement("select*fromempwheresalbetween?and?"); ps.setInt(1,1000); ps.setInt(2,3000); 4.执行语句。 [java] view plain copy ResultSetrs=ps.executeQuery(); 5.处理结果。 [java] view plain copy while(rs.next()){ System.out.println(rs.getInt("empno")+"-"+rs.getString("ename"));} 6.关闭资源。 [java] view plain copy finally{ if(con!=null){ try{ con.close(); }catch(SQLExceptione){e.printStackTrace(); } } } 15.Statement和PreparedStatement有什么区别?哪个性能更好? 与Statement相比 ①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性) ②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全; ③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。 16、在进行数据库编程时,连接池有什么作用? 由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行TCP的三次握手,释放连接需要进行TCP四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换取时间的策略(浪费了空间存储连接,但节省了创建和释放连接的时间)。池化技术在Java开发中是很常见的,在使用线程时创建线程池的道理与此相同。 17、Java中是如何支持正则表达式操作的? 答:Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作,请参考下面面试题的代码。 面试题:-如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写? [java] view plain copy importjava.util.regex.Matcher; importjava.util.regex.Pattern; classRegExpTest{ publicstaticvoidmain(String[]args){ Stringstr="北京市(朝阳区)(西城区)(海淀区)"; Patternp=Pattern.compile(".*?(?=\\()"); Matcherm=p.matcher(str); if(m.find()){ System.out.println(m.group());} } } 18、获得一个类的类对象有哪些方式? 答: -方法1:类型.class,例如:String.class -方法2:对象.getClass(),例如:"hello".getClass() -方法3:Class.forName(),例如:Class.forName("java.lang.String") 19、如何通过反射创建对象? 答: -方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance() -方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance("Hello"); 20、如何通过反射调用对象的方法? 答:请看下面的代码: [java] view plain copy importjava.lang.reflect.Method; classMethodInvokeTest{ publicstaticvoidmain(String[]args)throwsException{ Stringstr="hello"; Methodm=str.getClass().getMethod("toUpperCase"); System.out.println(m.invoke(str)); //HELLO } } 21、简述一下面向对象的"六原则一法则"。 答: 1)单一职责原则:一个类只做它该做的事情。(单一职责原则想表达的就是"高内聚",写代码最终极的原则只有六个字"高内聚、低耦合") 2)开闭原则:软件实体应当对扩展开放,对修改关闭。(在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。要做到开闭有两个要点:①抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;②封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而换乱) 3)依赖倒转原则:面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代) 4)里氏替换原则:任何时候都可以用子类型替换掉父类型。(子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。) 5)接口隔离原则:接口要小而专,绝不能大而全。(臃肿的接口是对接口的污染,既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高度内聚的。Java中的接口代表能力、代表约定、代表角色,能否正确的使用接口一定是编程水平高低的重要标识。) 6)合成聚合复用原则:优先使用聚合或合成关系复用代码。(通过继承来复用代码是面向对象程序设计中被滥用得最多的东西,记住:任何时候都不要继承工具类,工具是可以拥有并可以使用的,而不是拿来继承的。) 迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。(迪米特法则简单的说就是如何做到"低耦合",门面模式和调停者模式就是对迪米特法则的践行。JavaWeb开发中作为前端控制器的Servlet或Filter不就是一个门面吗,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作。迪米特法则用通俗的话来将就是不要和陌生人打交道,如果真的需要,找一个自己的朋友,让他替你和陌生人打交道。) 22.简述一下你了解的设计模式 -工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。 -代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。 -适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。 -模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。 23、用Java写一个单例类。 饿汉式单例 [java] view plain copy publicclassSingleton{ privateSingleton(){} privatestaticSingletoninstance=newSingleton(); publicstaticSingletongetInstance(){returninstance; } } 懒汉式单例 [java] view plain copy publicclassSingleton{ privateSingleton(){} privatestaticSingletoninstance=null; publicstaticsynchronizedSingletongetInstance(){ if(instance==null) instance=newSingleton(); returninstance; } } 注意:实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例。这里有一个问题可以思考:Spring的IoC容器可以为普通的类创建单例,它是怎么做到的呢? 24.什么是DAO模式? 答:DAO(DataAccessObject)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露数据库实现细节的前提下提供了各种数据操作。将所有对数据源的访问操作进行抽象化后封装在一个公共API中。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是DataAccessor(数据访问器),二是DataObject(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。 25.Servlet的生命周期 Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service方法,service方法会调用与请求对应的doGet或doPost等方法;当服务器关闭会项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy方法。 26.转发(forward)和重定向(redirect)的区别? 1)forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。 2)redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址。 3)前者更加高效,在前者可以满足需要时,尽量使用转发(通过RequestDispatcher对象的forward方法,RequestDispatcher对象可以通过ServletRequest对象的getRequestDispatcher方法获得),并且,这样也有助于隐藏实际的链接;在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用重定向(通过HttpServletResponse对象调用其sendRedirect方法)。 27.get和post请求的区别? ①get请求用来从服务器上获得资源,而post是用来向服务器提交数据; ②get将表单中数据按照name=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;post是将表单中的数据放在HTML头部(header),传递到action所指向URL; ③get传输的数据要受到URL长度限制(1024字节);而post可以传输大量的数据,上传文件只能使用post方式; ④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post; 28、JSP和Servlet有有什么关系? 答:其实这个问题在上面已经阐述过了,Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。 JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。 Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件(有人说,Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码,当然,这个说法还是很片面的)。 JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。 29、JSP中的四种作用域? 答:page、request、session和application,具体如下: ①page代表与一个页面相关的对象和属性。 ②request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域 ③session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中 ④application代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域。 30.实现会话跟踪的技术有哪些? 答:由于HTTP协议本身是无状态的,服务器为了区分不同的用户,就需要对用户会话进行跟踪,简单的说就是为用户进行登记,为用户分配唯一的ID,下一次用户在请求中包含此ID,服务器据此判断到底是哪一个用户。 ①URL重写:在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。 ②设置表单隐藏域:将和会话跟踪相关的字段添加到隐式表单域中,这些信息不会在浏览器中显示但是提交表单时会提交给服务器。 ③cookie:cookie当用户通过浏览器和服务器建立一次会话后,会话ID就会随响应信息返回存储在基于窗口的cookie中,那就意味着只要浏览器没有关闭,会话没有超时,下一次请求时这个会话ID又会提交给服务器让服务器识别用户身份。会话中可以为用户保存信息。会话对象是在服务器内存中的,而基于窗口的cookie是在客户端内存中的。 ④HttpSession:在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建HttpSession,每个用户可以访问他自己的HttpSession。与上面三种方式不同的是,HttpSession放在服务器的内存中 31.JSP中的静态包含和动态包含有什么区别? 答:静态包含是通过JSP的include指令包含页面,动态包含是通过JSP标准动作<jsp:forward>包含页面。静态包含是编译时包含,如果包含的页面不存在则会产生编译错误,而且两个页面的"contentType"属性应保持一致,因为两个页面会合二为一,只产生一个class文件,因此被包含页面发生的变动再包含它的页面更新前不会得到更新。动态包含是运行时包含,可以向被包含的页面传递参数,包含页面和被包含页面是独立的,会编译出两个class文件,如果被包含的页面不存在,不会产生编译错误,也不影响页面其他部分的执行。代码如下所示: <%--静态包含--%><%@includefile="..."%><%--动态包含--%><jsp:includepage="..."><jsp:paramname="..."value="..."/></jsp:include> 32、什么是WebService(Web服务)? 答:从表面上看,WebService就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。例如可以创建一个提供天气预报的WebService,那么无论你用哪种编程语言开发的应用都可以通过调用它的API并传入城市信息来获得该城市的天气预报。 补充:这里必须要提及的一个概念是SOA(Service-OrientedArchitecture,面向服务的架构)显然,WebService是SOA的一种较好的解决方案,它更多的是一种标准,而不是一种具体的技术。 33、hashmap和hashtable区别 1.hashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。 2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。 3.hashMap允许空键值,而hashTable不允许。 34、Socket的通信机制? 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。 应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。 建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。 套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。 连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。 35、Http的通信机制? HTTP协议即超文本传送协议(HypertextTransferProtocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。 HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。 1)在HTTP1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。 2)在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。 由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。 由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。 而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。 很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。 36、HttpServlet容器响应Web客户请求流程? 1)Web客户向Servlet容器发出Http请求; 2)Servlet容器解析Web客户的Http请求; 3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息; 4)Servlet容器创建一个HttpResponse对象; 5)Servlet容器调用HttpServlet的service方法,这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象; 6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息; 7)HttpServlet调用HttpResponse的有关方法,生成响应数据; 8)Servlet容器把HttpServlet的响应结果传给Web客户 37、Hibernate中Session的load和get方法的区别是什么? 答:主要有以下三项区别: ①如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。 ②get方法直接返回实体类对象,load方法返回实体类对象的代理。 ③在Hibernate3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。 说明:对于load()方法Hibernate认为该数据在数据库中一定存在可以放心的使用代理来实现延迟加载,如果没有数据就抛出异常,而通过get()方法获取的数据可以不存在。 38、如何理解Hibernate的延迟加载机制 答:延迟加载就是并不是在读取的时候就把数据加载进来,而是等到使用时再加载。Hibernate使用了虚拟代理机制实现延迟加载。返回给用户的并不是实体本身,而是实体对象的代理。代理对象在用户调用getter方法时就会去数据库加载数据。 39、简述Hibernate常见优化策略。 ①制定合理的缓存策略 ②采用合理的Session管理机制 ③尽量使用延迟加载特性 ④如果可以,选用基于version的乐观锁替代悲观锁 ⑤在开发过程中,开启hibernate.show_sql选项查看生成的SQL,从而了解底层的状况;开发完成后关闭此选项 40、什么是IoC和DI?DI是如何实现的? 答:IoC叫控制反转,是InversionofControl的缩写,控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。 控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象,是容器在对象初始化时不等对象请求就主动将依赖传递给它。通过IOC反转控制DI依赖注入完成各个层之间的注入,使得层与层之间实现完全脱耦,增加运行效率利于维护。 41、解释一下什么叫AOP(面向切面编程)? 答: spring的AOP面向切面编程,实现在不改变代码的情况下完成对方法的增强。比较常用的就是spring的声明式事务管理,底层通过AOP实现,避免了我们每次都要手动开启事物,提交事务的重复性代码,使得开发逻辑更加清晰。 简单点解释,比方说你想在你的service层所有类中都加上一个打印‘你好’的功能这你经可以用aop思想来做,你先写个类写个方法,方法经实现打印‘你好’然后你Ioc这个类ref=“service.*”让每个类都注入。 aop就是面向切面的编程。比如说你每做一次对数据库操作,都要生成一句日志。如果,你对数据库的操作有很多类,那你每一类中都要写关于日志的方法。但是如果你用aop,那么你可以写一个方法,在这个方法中有关于数据库操作的方法,每一次调用这个方法的时候,就加上生成日志的操作。 42、选择使用Spring框架的原因(Spring框架为企业级开发带来的好处)? 答:可以从以下几个方面作答: 1.IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神“不要重复的发明轮子”。 2.AOP:面向切面编程,将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。 3.MVC:Spring的MVC框架是非常优秀的,从各个方面都可以甩Struts2几条街,为Web表示层提供了更好的解决方案。 4.事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。 43、简述拦截器的工作原理以及你在项目中使用过哪些自定义拦截器 答:Struts2中定义了拦截器的接口以及默认实现,实现了Interceptor接口或继承了AbstractInterceptor的类可以作为拦截器。接口中的init()方法在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。每拦截一个请求,intercept()方法就会被调用一次。destory()方法将在拦截器被销毁之前被调用,它在拦截器的生命周期内也只被调用一次。 项目中使用过的有权限拦截器、执行时间拦截器、令牌拦截器等。 44、谈一下拦截器和过滤器的区别 答:拦截器和过滤器都可以用来实现横切关注功能,其区别主要在于: 1、拦截器是基于java反射机制的,而过滤器是基于函数回调的。 2、过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。 3、拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。 4、拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。 5、在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。 过滤器,是在javaweb中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符. 拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。 执行顺序:过滤前-拦截前-Action处理-拦截后-过滤后。 个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。 45、struts1.2和struts2.0的区别? struts1.2和struts2.0的对比 a、Action类: struts1.2要求Action类继承一个基类。struts2.0Action要求继承ActionSupport基类 b、线程模式 struts1.2Action是单例模式的并且必须是线程安全的,因为仅有一个Action的实例来处理所有的请求。struts2.0Action为每一个请求产生一个实例,因此没有线程安全问题。 c、Servlet依赖 struts1.2Action依赖于ServletAPI,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execut方法。struts2.0Action不依赖于容器,允许Action脱离容器单独测试。 46、常见的网络协议有哪些? 1.IP协议:互联网协议 主要用于负责IP寻址、路由选择和IP数据包的分割和组装。通常我们所说的IP地址可以理解为符合IP协议的地址。 2.TCP协议:传输控制协议 该协议主要用于在主机间建立一个虚拟连接,以实现高可靠性的数据包交换。IP协议可以进行IP数据包的分割和组装,但是通过IP协议并不能清楚地了解到数据包是否顺利地发送给目标计算机。而使用TCP协议就不同了,在该协议传输模式中在将数据包成功发送给目标计算机后,TCP会要求发送一个确认;如果在某个时限内没有收到确认,那么TCP将重新发送数据包。另外,在传输的过程中,如果接收到无序、丢失以及被破坏的数据包,TCP还可以负责恢复。 3.FTP(FileTransferProtocol):远程文件传输协议,允许用户将远程主机上的文件拷贝到自己的计算机上。 4.HTTP:超文本传输协议(HTTP,HyperTextTransferProtocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 5.ARP协议:AddressResolutionProtocol地址解析协议 简单地说,ARP协议主要负责将局域网中的32为IP地址转换为对应的48位物理地址,即网卡的MAC地址。 47、计算机网络分层,每层所用协议,协议所占端口 (1)应用层:与其他计算机进行通讯的一个应用,它是对应应用程序的通信服务的。示例:telnet,HTTP,FTP,WWW,NFS,SMTP等。 (2)表示层:这一层的主要功能是定义数据格式及加密。示例:加密,ASII等。 (3)会话层:他定义了如何开始、控制和结束一个会话,包括对多个双向小时的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的。示例:RPC,SQL等。 (4)传输层:这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。 (5)网络层:这层对端到端的包传输进行定义,他定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。。示例:IP,IPX等。 (6)数据链路层:他定义了在单个链路上如何传输数据。 (7)物理层:OSI的物理层规范是有关传输介质的特性标准,这些规范通常也参考了其他组织制定的标准。 48、html访问全过程 A)解析Web页面的URL,得到Web服务器的域名 B)通过DNS服务器获得Web服务器的IP地址 I)与Web服务器建立TCP连接 E)与Web服务器建立HTTP连接 C)从Web服务器获得URL指定的文档 G)浏览器解释页面文档,并显示在屏幕 49、classloader原理 1.classLoader的介绍及加载过程 与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Javaclass加载到JVM里头运行,负责加载Javaclass的这部分就叫做ClassLoader。所以classLoader的目的在于把class文件装入到jvm中。 那么classLoader又在那里的啦?又由谁调用呢?其实classLoader只是jvm的一个实现的一部分。Jvm提供的一个顶级的classLoader(bootStrapclassLoader),bootStrapclassLoader负责加载java核心的API以满足java程序最基本的需求。Jvm还提供的两个classLoader,其中ExtensionClassLoader负责加载扩展的Javaclass,ApplicationClassLoader负责加载应用程序自身的类。而ExtensionClassLoader和ApplicationClassLoader则由bootStrapclassLoader加载。 2.classLoader加载的基本流程 当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。 3.classLoader加载的方式 其实classLoader在加载class文件的时候就采用的双亲委托模式。每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parentClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前ClassLoader的parent。 50、快速排序原理 原理: 快速排序也是分治法思想的一种实现,他的思路是使数组中的每个元素与基准值(Pivot,通常是数组的首个值,A[0])比较,数组中比基准值小的放在基准值的左边,形成左部;大的放在右边,形成右部;接下来将左部和右部分别递归地执行上面的过程:选基准值,小的放在左边,大的放在右边。。。直到排序结束。 步骤: 1.找基准值,设Pivot=a[0] 2.分区(Partition):比基准值小的放左边,大的放右边,基准值(Pivot)放左部与右部的之间。 3.进行左部(a[0]-a[pivot-1])的递归,以及右部(a[pivot+1]-a[n-1])的递归,重复上述步骤。 [java] view plain copy 1.//快速排序 2.voidquick_sort(ints[],intl,intr) 3.{ 4.if(l<r) 5.{ 6.//Swap(s[l],s[(l+r)/2]);//将中间的这个数和第一个数交换参见注1 7.inti=l,j=r,x=s[l]; 8.while(i<j) 9.{ 10.while(i<j&&s[j]>=x)//从右向左找第一个小于x的数 11.j--; 12.if(i<j) 13.s[i++]=s[j]; 14. 15.while(i<j&&s[i]<x)//从左向右找第一个大于等于x的数 16.i++; 17.if(i<j) 18.s[j--]=s[i]; 19.} 20.s[i]=x; 21.quick_sort(s,l,i-1);//递归调用 22.quick_sort(s,i+1,r); 23.} 24.} 51、各种集合类之间的区别 1.ArrayList:元素单个,效率高,多用于查询 2.Vector:元素单个,线程安全,多用于查询 3.LinkedList:元素单个,多用于插入和删除 4.HashMap:元素成对,元素可为空 5.HashTable:元素成对,线程安全,元素不可为空 52、内存溢出和内存泄漏 内存溢出是指已有的数据超过了其获得到的内存所能存储的范围,比如用一个字节存放1000这个数字就属于内存溢出。比如说你申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。 Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽)。Java内存泄露是说程序逻辑问题,造成申请的内存无法释放.这样的话无论多少内存,早晚都会被占用光的.最简单的例子就是死循环了.由于程序判断错误导经常发生此事。 53、jvm布局 以下是JVM的一个基本架构图,在这个基本架构图中,栈有两部份,Java线程栈以及本地方法栈 在JVM中堆空间划分如下图所示 上图中,刻画了Java程序运行时的堆空间,可以简述成如下2条 1.JVM中堆空间可以分成三个大区,新生代、老年代、永久代 2.新生代可以划分为三个区,Eden区,两个幸存区 Jvm主要包括下面两面方面: ·Java代码编译和执行的整个过程 ·JVM内存管理及垃圾回收机制 54、在浏览器中输入www.baidu.com后执行的全部过程 1、客户端浏览器通过DNS解析到www.baidu.com的IP地址220.181.27.48,通过这个IP地址找到客户端到服务器的路径。客户端浏览器发起一个HTTP会话到220.161.27.48,然后通过TCP进行封装数据包,输入到网络层。 2、在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。 3、客户端的网络层不用关系应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。 4、客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。 55、IO流类 原文地址http://www.bieryun.com/856.html

优秀的个人博客,低调大师

大数据分析之技术框架整理

大数据离线部分 HDFS 1:HDFS的架构部分及工作原理 NameNode:负责管理元素据,将信息保存在内存中 DataNode:保存数据,以块的形式保存。启动后需要定时的向NameNode发送心跳,报告自身存储的块信息 2:HDFS的上传过程 3:HDFS的下载 4:NameNode的元数据安全机制 以记日志的形式将每一个操作写在磁盘的日志文件中,然后借助Secondary NameNode的checkpoint功能将fsImage和日志进行合并。 重点:记住checkpoint工作过程 5:如果服务器的磁盘坏了,如何挽救数据? 配置多个dfs.namenode.name.dir 路径为本地磁盘路径和nfs网络磁盘路径。 6:hdfs集群中,受到拓展瓶颈的是NameNode还是Datanode? 是NameNode,因为DataNode不够可以很方便的水平拓展,而工作的NameNode只有一个,他的存储能力完全取决于他的内存,所以。。。。, 但是其实NameNode一般不会成为瓶颈,因为一个块记录的元数据信息大小约为150B,如果每一个块大小为128M的话,那么15G的NameNode内存可以存储12PB的数据。 7:datanode明明已启动,但是集群中的可用datanode列表中就是没有,怎么办? 已经不是处女,在她的Data目录下,已经有其他NameNode的标记,这个NameNode不认。 8:文件下载到window中,为什么会报错? 默认使用操作系统的内核进行磁盘数据的写入,也就是需要一个winutil的工具,而默认的安装包中不提供,所以需要编译源码或者设置为使用Java的进行磁盘写入。 9:hadoop的HA(高可用) MapReduce 1:MapReduce中,fileinputformat -> map -> shuffle -> reduce的过程 2:MapReduce中,job提交的过程 3:自定义Javabean作为数据,需要extends writableandCompareble接口。 4:自定义outputformat,进行不同方向的处理。 5:MapReduce的一些应用场景 1、排序并且求 TOPOne 和TOPN 2、求某个用户前几个月的总流量,并且选择出流量前几名的用户。 3、reduce端的join 4、map端join 5、求共同好友问题 hive 1:什么是hive? 一个将sql转化为MapReduce程序的、单机版的、数据仓库工具。通过关系型数据库(mysql等)来记录表元数据信息。真正的数据在HDFS中。 Hive利用HDFS存储数据,利用MapReduce查询分析数据 hive2.0版本之后,都是基于Spark处理了。 安装的时候,需要注意jline的版本冲突。 2:如何启动? 3:执行的sql的形式 hiveshell、 hive -e “sql命令”、 hive -f “一个包含着很多SQL语句的文件” 4:hive的创建表操作 内部表、外部表 就差连个关键字(external 和 location) 分区表、分桶表 5:hive查询表 join 动态分区 分组查询 复杂的那个累计报表操作。 6:hive自定义函数(UDF) sqoop 利用hadoop的map端进行数据的并行导入导出。 安装在HDFS上,配置HDFS的路径和Hive路径即可。 flume 1:agent:sources 、 channel 、 sinks 2:sources:exec、spooldir、arvo (加一个拦截器) 3:channel:men 、 disk 4:sinks:arvo 、HDFS、kafka 5:flume安装在数据源这一边。 6:如何自定义拦截器? classmyiterceptorimplementsIterceptor //里面有一个静态的公共内部类。 publicstaticclassmybuilderimplementsIterceptor.Builder 7:如何实现flume的多级连接,以及如何实现高可用? 大数据实时storm部分 storm 1 : storm是一个实时的计算框架,只负责计算,不负责存储。它通过spout的open和nextTuple方法去外部存储系统(kafka)获取数据,然后传送给后续的bolt处理, bolt利用prepare和execute方法处理完成后,继续往后续的bolt发送,或者根据输出目录,把信息写到指定的外部存储系统中。 2:storm的数据不丢失原理 交叉收到的数据做异或元算中间结果不为0的原理。 3:设置spout_max_pending (可以限流) 4:jstorm的通信机制,每一个:worker都有一个接受线程和输出线程 5:storm的架构分析 nimbus、zookeeper、supervisor、worker nimbus:接受任务请求,并且进行任务的分发,最后写入到zookeeper中。 supervisor:接受nimbus的任务调度,然后启动和管理属于自己的worker进程,supervisor是可以快速失败的,不影响任务的执行。 我们可以写一个脚本来监控supervisor的进程,如果不存在了,立马启动,就可以了。 worker:启动spoutTask、boltTask等等任务,去执行业务逻辑。 6:storm的编程模型 topology:由spout和bolt组成的一个流程图。他描述着本次任务的信息 spout: open nexttuple declareOutputFields bolt: prepare execute declareOutputFields 6:storm的tuple结构,它里面有两个数据结构,一个list、一个是map list:记录着信息 map:记录着每个字段对应的下表,通过找到下边再去上面的list中找数据。 7:storm任务提交的过程 kafka 1、kafka和jms的区别 2、kafka的topic理解 topic是逻辑存在的,真正在物理磁盘中的体现是partitioner,一个topic可以对应多个partition,不同的paritition存放在不同的broker中,以提高并发存储能力。 3、partitioner partition是topic信息在屋里存储中的具体体现,在磁盘中它是一个文件夹,名字是topic名字_partition编号。4、segment 每个partition对对应多个segment文件,默认大小是1G,为了快速定位到指定的offset位置。 5、kafka为什么这么快 1/使用了操作系统使用的pagecache缓存,缓存大,缓存到一定量的数据时,以顺序写入的方 式写入到磁盘中。 因为:磁盘顺序写入的方式非常的快=>600MB/s,而随机存储只有100kb/s左右。 2/使用操作系统的sendfile技术。在读取信息发送的时候,不需要经过用户区,而是在os端直接发送,可以减少很多步骤。 6、为什么要多个partitioner7、为什么每个partitioner需要切分为多个segment文件 8、kafka的HA 对partitioner分区进行备份,利用zookeeper的选举机制选择leader。数据的生产存储和消费读取都是有leader负责,其他的replicatition只是负责备份而已。 9、kafka如何用shell脚本来讲一个文件读写进去?10、kafka如何用JavaAPI实现生产者和消费者? 大数据一站式解决方案:Scala和Spark部分 scala回顾 1、如何定义变量 2、如何定义函数、方法,如何在将函数作为方法的参数传入进去? 3、条件判断语句,循环控制语句 4、集合操作:Array、list、set、tuple、map (注意:可变和不可变的区别)5、样例类的使用6、trit、抽象类的使用7、主构造器和辅助构造器的使用 8、scala的高级特性 高阶函数:作为值得函数、匿名函数、闭包、柯里化 隐式转换:一个类对象中,如果他没有摸一个功能,但是我们有想要它实现,可以使用英式转换的方式。 objectMyPredef{ //定义隐式转换方法 implicitdeffileReadToRichFile(file:File)=newRichFile(file) } 使用: import MyPredef._9、Actor 写起来像多线程,用起来像socket10、akka ActorSystem.actorOf()创建一个Actor, 创建的同时,就是执行Actor中的prestart方法,去初始化一些信息。 Spark RDD 1、SparkRDD叫做:弹性分布式数据集,其实就是一个类,用来描述:任务的数据从哪里读取、用那个算进行计算、得到的结果有存放在哪里、RDD之间的依赖关系是款以来还是窄依赖 2、RDD有五个特点 一系列分区 每个算子作用在每个分区上 一系列依赖关系 最有位置(如果从HDFS上读取数据) 3、RDD的两种算子Transformation和Action Transformation是懒加载,只是定义了这个算子的任务,该如何做,但是还没有做。 Action是立即执行,当执行到Action时,会触发DAGSchudle切分stage,切分完成后,有TaskScheduler将任务通过DriverActor发送到executor中执行。 4、RDD的几个复杂的Transformation ->combineByKey(x=>x,(a:List[String],b:String)=>a:+b, (m:List[String],n:List[String])=>m++n) 第一个参数表示分组后的第一个值如何处理, 第二个参数表示后续的值和前一个值如何处理, 第三个参数表示,map端处理完成后,在reduce端如何对这些list进行处理。 ->aggregate(“初始量,可以是String也可以是int”)(第一个func,第二个func) 初始量作用于没一个分区,第一个func作用于map端,第二个func作用于reduce端。 ->reduceByKey(_+_) 作用于map端和reduce端,可以进行局部聚合。 其实reduceByKey和aggregateByKey在底层都调用了combineByKey方法来实现响应的功能。 ->mapPartitions 对每一个分区进行操作,直接在里面使用匿名函数即可 当然如果逻辑非常复杂也是可以考虑在外面先定义好这个函数之后在传输进去。 rdd1.mapPartitions((it:Iterator[String])=>{ it.toList.map(x=>(x,1)).iterator }) >mapPartitionsWithIndex 首先定义一个函数,当然也可以写在里面作为匿名函数 valfunc=(index:Int,it:Iterator[Int])=>{ it.toList.map(x=>("index:"+index,x)).iterator } rdd1.mapPartitionsWithIndex(func).collect 5、RDD自定义Partitioner //自定义分区器,重写里面的getPartition方法和numPartitions方法。 //构造这个对象的时候,就把所有情况的信息传输过来,然后在里面进行分类处理。 classHostPartition(hostArr:Array[String])extendsPartitioner{ //对所有的数据进行分类,每一种类型对应一个int编号。所以使用map比较合适。 valmap=newmutable.HashMap[String,Int]() for(index<-0until(hostArr.length)){ map.put(hostArr(index),index) } //重写getPartition的方法。 overridedefgetPartition(key:Any):Int={ map.getOrElse(key.toString,0) } overridedefnumPartitions:Int=hostArr.length } 应用: valhostPartition:HostPartition=newHostPartition(hostList) valallPartitionRDD:RDD[(String,(String,Int))]=host_url_count.partitionBy(hostPartition) 6、自定义排序规则 ==>定义一个 caseclassGril(yanzhi:Int,nianling:Int)extendsOrdered[Gril]withSerializable{ overridedefcompare(that:Gril):Int={ valyanzhiResult:Int=this.yanzhi.compareTo(that.yanzhi) if(yanzhiResult==0){ returnthis.nianling.compareTo(that.nianling) } returnyanzhiResult } } 应用: valrdd2:RDD[(String,Int,Int)]=rdd1.sortBy(msg=>Gril(msg._2,msg._3)) Spark的SQLContext 1、Spark整合Hive和HDFS 只需要将Hive的hive-site.xml ; hadoop的core-site.xml和hdfs-site.xml拷贝到Spark的conf目录下即可。Spark就知道如何使用hive的表,同时也知道去哪个NameNode哪里都数据了。 2、DataFrame是什么? 是一个分布式数据集,对RDD的封装。RDD有的方法他基本上都有 3、DataFrame如何创建? 三种方式:->RDD + case class ->RDD + structType ->sqlContext.read.format.options(Map()) 4、DataFrame首先需要注册成表结构之后才可以使用sqlContext来操作。 dF.registerTempTable(“person”) 5、使用sqlContext ==> 返回一个DataFrame sqlContext.sql(“select * from person”) 6、DataFrame将数据写入到HDFS或者mysql中 valprop=newProperties() prop.put("user","root") prop.put("password","815325") //如果数据库中没有这个表,那么他也会创建一张表(很强大) resultDF.write.mode("append").jdbc("jdbc:mysql://localhost:3306/bigdata","result",prop) 本文作者:佚名 来源:51CTO

优秀的个人博客,低调大师

Spark on yarn配置项说明与优化整理

配置于spark-default.conf 1. #spark.yarn.applicationMaster.waitTries 5 用于applicationMaster等待Spark master的次数以及SparkContext初始化尝试的次数 (一般不用设置) 2.spark.yarn.am.waitTime 100s 3.spark.yarn.submit.file.replication 3 应用程序上载到HDFS的复制份数 4.spark.preserve.staging.files false 设置为true,在job结束后,将stage相关的文件保留而不是删除。 (一般无需保留,设置成false) 5.spark.yarn.scheduler.heartbeat.interal-ms 5000 Spark application master给YARN ResourceManager发送心跳的时间间隔(ms) 6.spark.yarn.executor.memoryOverhead 1000 此为vm的开销(根据实际情况调整) 7.spark.shuffle.consolidateFiles true 仅适用于HashShuffleMananger的实现,同样是为了解决生成过多文件的问题,采用的方式是在不同批次运行的Map任务之间重用Shuffle输出文件,也就是说合并的是不同批次的Map任务的输出数据,但是每个Map任务所需要的文件还是取决于Reduce分区的数量,因此,它并不减少同时打开的输出文件的数量,因此对内存使用量的减少并没有帮助。只是HashShuffleManager里的一个折中的解决方案。 8.spark.serializer org.apache.spark.serializer.KryoSerializer 暂时只支持Java serializer和KryoSerializer序列化方式 9.spark.kryoserializer.buffer.max 128m 允许的最大大小的序列化值。 10.spark.storage.memoryFraction 0.3 用来调整cache所占用的内存大小。默认为0.6。如果频繁发生Full GC,可以考虑降低这个比值,这样RDD Cache可用的内存空间减少(剩下的部分Cache数据就需要通过Disk Store写到磁盘上了),会带来一定的性能损失,但是腾出更多的内存空间用于执行任务,减少Full GC发生的次数,反而可能改善程序运行的整体性能。 11.spark.sql.shuffle.partitions 800 一个partition对应着一个task,如果数据量过大,可以调整次参数来减少每个task所需消耗的内存. 12.spark.sql.autoBroadcastJoinThreshold -1 当处理join查询时广播到每个worker的表的最大字节数,当设置为-1广播功能将失效。 13.spark.speculation false 如果设置成true,倘若有一个或多个task执行相当缓慢,就会被重启执行。(事实证明,这种做法会造成hdfs中临时文件的丢失,报找不到文件的错) 14.spark.shuffle.manager tungsten-sort tungsten-sort是一种类似于sort的shuffle方式,shuffle data还有其他两种方式sort、hash. (不过官网说tungsten-sort 应用于spark 1.5版本以上) 15.spark.sql.codegen true Spark SQL在每次执行次,先把SQL查询编译JAVA字节码。针对执行时间长的SQL查询或频繁执行的SQL查询,此配置能加快查询速度,因为它产生特殊的字节码去执行。但是针对很短的查询,可能会增加开销,因为它必须先编译每一个查询 16.spark.shuffle.spill false 如果设置成true,将会把spill的数据存入磁盘 17.spark.shuffle.consolidateFiles true 我们都知道shuffle默认情况下的文件数据为map tasks * reduce tasks,通过设置其为true,可以使spark合并shuffle的中间文件为reduce的tasks数目。 18.代码中 如果filter过滤后 会有很多空的任务或小文件产生,这时我们使用coalesce或repartition去减少RDD中partition数量。

优秀的个人博客,低调大师

CSS 6种完全居中最佳实践(整理

2016年4月28日 1.最佳法: .Absolute-Center{ width:50%; height:50%; overflow:auto; margin:auto; position:absolute; top:0;left:0;bottom:0;right:0; background-color:red; } 在线演示 在普通文档流里,margin: auto; 的意思是设置元素的margin-top和margin-bottom为0。W3.org:?If ‘margin-top’, or ‘margin-bottom’ are ‘auto’, their used value is 0. 设置了position: absolute; 的元素会变成块元素,并脱离普通文档流。而文档的其余部分照常渲染,元素像是不在原来的位置一样。 Developer.mozilla.org:?…an element that is positioned absolutely is taken out of the flow and thus takes up no space 设置了top: 0; left: 0; bottom: 0; right: 0; 样式的块元素会让浏览器为它包裹一层新的盒子,因此这个元素会填满它相对父元素的内部空间,这个相对父元素可以是是body标签,或者是一个设置了position: relative; 样式的容器。 Developer.mozilla.org:?For absolutely positioned elements, the top, right, bottom, and left properties specify offsets from the edge of the element’s containing block (what the element is positioned relative to). 给元素设置了宽高以后,浏览器会阻止元素填满所有的空间,根据margin: auto; 的要求,重新计算,并包裹一层新的盒子。 Developer.mozilla.org:?The margin of the [absolutely positioned] element is then positioned inside these offsets. 既然块元素是绝对定位的,又脱离了普通文档流,因此浏览器在包裹盒子之前会给margin-top和margin-bottom设置一个相等的值。 W3.org:?If none of the three [top, bottom, height] are ‘auto’: If both ‘margin-top’ and ‘margin-bottom’ are ‘auto’, solve the equation under the extra constraint that the two margins get equal values.?AKA: center the block vertically 使用“完全居中”,有意遵照了标准margin: auto; 样式渲染的规定,所以应当在与标准兼容的各种浏览器中起作用。 优点: 跨浏览器,兼容性好(无需hack,可兼顾IE8~IE10) 无特殊标记,样式更精简 自适应布局,可以使用百分比和最大最小高宽等样式 居中时不考虑元素的padding值(也不需要使用box-sizing样式) 布局块可以自由调节大小 img的图像也可以使用 同时注意: 必须声明元素高度 推荐设置overflow:auto;样式避免元素溢出,显示不正常的问题 这种方法在Windows Phone上不起作用 2.负margin法: .negative-margin{ width:300px; height:200px; padding:20px; position:absolute; top:50%;left:50%; margin-left:-170px;/*(width+padding)/2*/ margin-top:-120px;/*(height+padding)/2*/ } 在线演示 3.transform法: .transform{ width:50%; margin:auto; position:absolute; top:50%;left:50%; -webkit-transform:translate(-50%,-50%); -ms-transform:translate(-50%,-50%); transform:translate(-50%,-50%); } 在线演示 4.inner-block法: HTML: CSS: .Center-Container.is-Inline{ text-align:center; overflow:auto; } .Center-Container.is-Inline:after, .is-Inline.Center-Block{ display:inline-block; vertical-align:middle; } .Center-Container.is-Inline:after{ content:''; height:100%; margin-left:-0.25em;/*Tooffsetspacing.Mayvarybyfont*/ } .is-Inline.Center-Block{ max-width:99%;/*Preventsissueswithlongcontentcausesthecontentblocktobepushedtothetop*/ /*max-width:calc(100%-0.25em)/*OnlyforIE9+*/ } 在线演示 5.Flexbox法: .Center-Container.is-Flexbox{ display:-webkit-box; display:-moz-box; display:-ms-flexbox; display:-webkit-flex; display:flex; -webkit-box-align:center; -moz-box-align:center; -ms-flex-align:center; -webkit-align-items:center; align-items:center; -webkit-box-pack:center; -moz-box-pack:center; -ms-flex-pack:center; -webkit-justify-content:center; justify-content:center; } 在线演示 优点: 内容可以是任意高宽,溢出也能表现良好 可以用于各种高级布局技巧 同时注意: 不支持IE8-9 同时注意: 需要在body上写样式,或者需要额外容器 需要各种厂商前缀兼容现代浏览器 可能有潜在的性能问题 6.Table-cell法: HTML: CSS: .Center-Container.is-Table{display:table;} .is-Table.Table-Cell{ display:table-cell; vertical-align:middle; } .is-Table.Center-Block{ width:50%; margin:0auto; } 在线演示 参考出处: CodePen of shshaw 伯乐在线

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。