首页 文章 精选 留言 我的

精选列表

搜索[禅道],共6181篇文章
优秀的个人博客,低调大师

2020年春招面试:全网最全Spring系列面试题129道(附答案解析)

前言关于Spring的知识总结了个思维导图分享给大家 1、不同版本的 Spring Framework 有哪些主要功能? 2、什么是 Spring Framework?Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。它是轻量级、松散耦合的。它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。它可以集成其他框架,如 Structs、Hibernate、EJB 等,所以又称为框架的框架。 3、列举 Spring Framework 的优点。由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件。Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持续集成和可测试性。由于依赖注入和控制反转,JDBC 得以简化。它是开源免费的。 4、Spring Framework 有哪些不同的功能?轻量级 - Spring 在代码量和透明度方面都很轻便。IOC - 控制反转 AOP - 面向切面编程可以将应用业务逻辑和系统服务分离,以实现高内聚。容器 - Spring 负责创建和管理对象(Bean)的生命周期和配置。MVC - 对 web 应用提供了高度可配置性,其他框架的集成也十分方便。事务管理 - 提供了用于事务管理的通用抽象层。Spring 的事务支持也可用于容器较少的环境。JDBC 异常 - Spring的 JDBC 抽象层提供了一个异常层次结构,简化了错误处理策略。 5、Spring Framework 中有多少个模块,它们分别是什么? Spring 核心容器 – 该层基本上是 Spring Framework 的核心。它包含以下模块:(1)Spring Core(2)Spring Bean(3)SpEL (Spring Expression Language)(4) Spring Context数据访问/集成 – 该层提供与数据库交互的支持。它包含以下模块:(1)JDBC (Java DataBase Connectivity)(2)ORM (Object Relational Mapping)(3)OXM (Object XML Mappers)(4)JMS (Java Messaging Service)(5)TransactionWeb – 该层提供了创建 Web 应用程序的支持。它包含以下模块:(1)Web(2)Web – Servlet(3)Web – Socket(4)Web – PortletAOP该层支持面向切面编程Instrumentation该层为类检测和类加载器实现提供支持。Test该层为使用 JUnit 和 TestNG 进行测试提供支持。几个杂项模块:(1)Messaging – 该模块为 STOMP 提供支持。它还支持注解编程模型,该模型用于从WebSocket 客户端路由和处理 STOMP 消息。(2)Aspects – 该模块为与 AspectJ 的集成提供支持。 6、什么是 Spring 配置文件?Spring 配置文件是 XML 文件。该文件主要包含类信息。它描述了这些类是如何配置以及相互引入的。但是,XML 配置文件冗长且更加干净。如果没有正确规划和编写,那么在大项目中管理变得非常困难。 7、Spring 应用程序有哪些不同组件?Spring 应用一般有以下组件:(1) 接口 - 定义功能。(2)Bean 类 - 它包含属性,setter 和 getter 方法,函数等。(3)Spring 面向切面编程(AOP) - 提供面向切面编程的功能。(4)Bean 配置文件 - 包含类的信息以及如何配置它们。(5)用户程序 - 它使用接口。 8、使用 Spring 有哪些方式?使用 Spring 有以下方式:(1)作为一个成熟的 Spring Web 应用程序。(2)作为第三方 Web 框架,使用 Spring Frameworks 中间层。(3)用于远程使用。(4)作为企业级 Java Bean,它可以包装现有的 POJO(Plain Old JavaObjects)。 9、什么是 Spring IOC 容器?Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。欢迎大家关注我的公种浩:程序员追风,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 10、什么是依赖注入?在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC容器将它们装配在一起。 11、可以通过多少种方式完成依赖注入?通常,依赖注入可以通过三种方式完成,即:(1)构造函数注入(2)setter 注入(3) 接口注入在 Spring Framework 中,仅使用构造函数和 setter 注入。12、区分构造函数注入和 setter 注入。 13、spring 中有多少种 IOC 容器?BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。 14、区分 BeanFactory 和 ApplicationContext。 15、列举 IoC 的一些好处。IoC 的一些好处是:(1)它将最小化应用程序中的代码量。(2)它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制。(3)它以最小的影响和最少的侵入机制促进松耦合。(4)它支持即时的实例化和延迟加载服务。 16、Spring IoC 的实现机制。Spring 中的 IoC 的实现原理就是工厂模式加反射机制。示例:interface Fruit { public abstract void eat(); }class Apple implements Fruit { public void eat(){ System.out.println("Apple"); } }class Orange implements Fruit { public void eat(){ System.out.println("Orange"); } }class Factory { public static Fruit getInstance(String ClassName) { Fruit f=null; try { f=(Fruit)Class.forName(ClassName).newInstance(); } catch (Exception e) { e.printStackTrace(); } return f; } }class Client { public static void main(String[] a) { Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple"); if(f!=null){ f.eat(); } } } 17、什么是 spring bean?(1)它们是构成用户应用程序主干的对象。(2)Bean 由 Spring IoC 容器管理。(3)它们由 Spring IoC 容器实例化,配置,装配和管理。(4)Bean 是基于用户提供给容器的配置元数据创建。 18、spring 提供了哪些配置方式?基于 xml 配置bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:基于注解配置您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如: 基于 Java API 配置Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。(1) @Bean 注解扮演与 元素相同的角色。(2) @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。例如:@Configurationpublic class StudentConfig { @Bean public StudentBean myStudent() { return new StudentBean(); } } 19、spring 支持集中 bean scope?Spring bean 支持 5 种 scope:Singleton - 每个 Spring IoC 容器仅有一个单实例。Prototype - 每次请求都会产生一个新的实例。Request - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。Session - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。Global-session - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 globalsession 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web会自动当成 session 类型来使用。仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。 20、spring bean 容器的生命周期是什么样的?spring bean 容器的生命周期流程如下:(1)Spring 容器根据配置中的 bean 定义中实例化 bean。(2)Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。(3)如果 bean 实现BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用setBeanName()。(4)如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。(5)如果存在与 bean 关联的任何BeanPostProcessors,则调用preProcessBeforeInitialization() 方法。(6)如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。(7)最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。(8)如果 bean 实现DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。(9)如果为bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。欢迎大家关注我的公种浩:程序员追风,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 21、什么是 spring 的内部 bean?只有将 bean 用作另一个 bean 的属性时,才能将 bean 声明为内部 bean。为了定义 bean,Spring 的基于 XML 的配置元数据在 或 中提供了 元素的使用。内部 bean 总是匿名的,它们总是作为原型。例如,假设我们有一个 Student 类,其中引用了 Person 类。这里我们将只创建一个 Person 类实例并在 Student 中使用它。Student.javapublic class Student { private Person person; //Setters and Getters }public class Person { private String name; private String address; //Setters and Getters }bean.xml “Bangalore"> 22、什么是 spring 装配当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。Spring容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean 23、自动装配有哪些方式?Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。自动装配的不同模式:no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML文件中由相同名称定义的 bean。byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。构造函数- 它通过调用类的构造函数来注入依赖项。它有大量的参数。autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。 24、自动装配有什么局限?覆盖的可能性 - 您始终可以使用 和 设置指定依赖项,这将覆盖自动装配。基本元数据类型 - 简单属性(如原数据类型,字符串和类)无法自动装配。令人困惑的性质 - 总是喜欢使用明确的装配,因为自动装配不太精确。 25、什么是基于注解的容器配置不使用 XML 来描述 bean 装配,开发人员通过在相关的类,方法或字段声明上使用注解将配置移动到组件类本身。它可以作为 XML 设置的替代方案。例如:Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。@Bean 注解扮演与 元素相同的角色。 @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。例如:@Configurationpublic class StudentConfig { @Bean public StudentBean myStudent() { return new StudentBean(); } } 26、如何在 spring 中启动注解装配?默认情况下,Spring 容器中未打开注解装配。因此,要使用基于注解装配,我们必须通过配置 元素在 Spring 配置文件中启用它。 27、@Component, @Controller, @Repository,@Service 有何区别?@Component :这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。@Controller :这将一个类标记为 Spring Web MVC 控制器。标有它的Bean 会自动导入到 IoC 容器中。@Service :此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用@Service 而不是 @Component,因为它以更好的方式指定了意图。@Repository :这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。 28、@Required 注解有什么用?@Required 应用于 bean 属性 setter 方法。此注解仅指示必须在配置时使用bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出 BeanInitializationException。示例:public class Employee { private String name; @Required public void setName(String name){ this.name=name; } public string getName(){ return name; } } 29、@Autowired 注解有什么用?@Autowired 可以更准确地控制应该在何处以及如何进行自动装配。此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配bean。默认情况下,它是类型驱动的注入。public class Employee { private String name; @Autowired public void setName(String name) { this.name=name; } public string getName(){ return name; } } 30、@Qualifier 注解有什么用?当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean来消除歧义。例如,这里我们分别有两个类,Employee 和 EmpAccount。在 EmpAccount中,使用@Qualifier 指定了必须装配 id 为 emp1 的 bean。Employee.javapublic class Employee { private String name; @Autowired public void setName(String name) { this.name=name; } public string getName() { return name; } }EmpAccount,javapublic class EmpAccount { private Employee emp; @Autowired @Qualifier(emp1) public void showName() { System.out.println(“Employee name : ”+emp.getName); } } 31、@RequestMapping 注解有什么用?@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注释可应用于两个级别:类级别:映射请求的 URL 方法级别:映射 URL 以及 HTTP 请求方法 32、spring DAO 有什么用?Spring DAO 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工作。这使得用户容易在持久性技术之间切换。它还允许您在编写代码时,无需考虑捕获每种技术不同的异常。 33、列举 Spring DAO 抛出的异常。 34、spring JDBC API 中存在哪些类?(1)JdbcTemplate(2)SimpleJdbcTemplate(3)NamedParameterJdbcTemplate(4)SimpleJdbcInsert(5)SimpleJdbcCall 35、使用 Spring 访问 Hibernate 的方法有哪些?我们可以通过两种方式使用 Spring 访问 Hibernate:(1) 使用 Hibernate 模板和回调进行控制反转(1) 扩展 HibernateDAOSupport 并应用 AOP 拦截器节点 36、列举 spring 支持的事务管理类型Spring 支持两种类型的事务管理:(1)程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。(2) 声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML的配置来管理事务。 37、spring 支持哪些 ORM 框架(1)Hibernate(2)iBatis(3) JPA(4)JDO(5) OJB 38、什么是 AOP?AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与OOP 不同的抽象软件结构的视角. 在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面) 39、什么是 Aspect?aspect 由 pointcount 和 advice 组成, 它既包含了横切逻辑的定义, 也包括了连接点的定义. Spring AOP 就是负责实施切面的框架, 它将切面所定义的横切逻辑编织到切面所指定的连接点中. AOP 的工作重心在于如何将增强编织目标对象的连接点上, 这里包含两个工作:(1)如何通过 pointcut 和 advice 定位到特定的 joinpoint 上 (2)如何在advice 中编写切面代码. 可以简单地认为, 使用 @Aspect 注解的类就是切面. 40、什么是切点(JoinPoint)程序运行中的一些时间点, 例如一个方法的执行, 或者是一个异常的处理.在 Spring AOP 中, join point 总是方法的执行点。 41、什么是通知(Advice)?特定 JoinPoint 处的 Aspect 所采取的动作称为 Advice。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint “周围”维护一系列的拦截器。 42、有哪些类型的通知(Advice)?(1)Before - 这些类型的 Advice 在 joinpoint 方法之前执行,并使用@Before 注解标记进行配置。(2)After Returning - 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。(3)After Throwing - 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。(4)After (finally) - 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。(5)Around - 这些类型的 Advice 在连接点之前和之后执行,并使用@Around 注解标记进行配置。 43、指出在 spring aop 中 concern 和 cross-cuttingconcern 的不同之处。concern 是我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能。cross-cutting concern 是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题。 44、AOP 有哪些实现方式?实现 AOP 的技术,主要分为两大类:静态代理指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;(1)编译时编织(特殊编译器实现)(2)类加载时编织(特殊的类加载器实现)。 动态代理在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。(1)JDK 动态代理(2)CGLIB 45、Spring AOP and AspectJ AOP 有什么区别?Spring AOP 基于动态代理方式实现;AspectJ 基于静态代理方式实现。SpringAOP 仅支持方法级别的 PointCut;提供了完全的 AOP 支持,它还支持属性级别的 PointCut。 46、如何理解 Spring 中的代理?将 Advice 应用于目标对象后创建的对象称为代理。在客户端对象的情况下,目标对象和代理对象是相同的。Advice + Target Object = Proxy 47、什么是编织(Weaving)?为了创建一个 advice 对象而链接一个 aspect 和其它应用类型或对象,称为编织(Weaving)。在 Spring AOP 中,编织在运行时执行。请参考下图: 48、Spring MVC 框架有什么用?Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序。MVC 模式有助于分离应用程序的不同方面,如输入逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供松散耦合。 49、描述一下 DispatcherServlet 的工作流程DispatcherServlet 的工作流程可以用一幅图来说明: (1)向服务器发送 HTTP 请求,请求被前端控制器 DispatcherServlet 捕获。(2) DispatcherServlet 根据 -servlet.xml 中的配置对请求的 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以HandlerExecutionChain 对象的形式返回。(3) DispatcherServlet 根据获得的 Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(...)方法)(4)提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler( Controller)。在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:1) HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。2)数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等。3)数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。4)数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult 或 Error 中。(5)Handler(Controller)执行完成后,向 DispatcherServlet 返回一个ModelAndView 对象;(6)根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver)返回给 DispatcherServlet。(7) ViewResolver 结合 Model 和 View,来渲染视图。(8)视图负责将渲染结果返回给客户端。 50、介绍一下 WebApplicationContextWebApplicationContext 是 ApplicationContext 的扩展。它具有 Web 应用程序所需的一些额外功能。它与普通的 ApplicationContext 在解析主题和决定与哪个 servlet 关联的能力方面有所不同。 51、什么是 spring?Spring 是个 java 企业级应用的开源开发框架。Spring 主要用来开发 Java 应用,但是有些扩展是针对构建 J2EE 平台的 web 应用。Spring 框架目标是简化 Java企业级应用开发,并通过 POJO 为基础的编程模型促进良好的编程习惯。 52、使用 Spring 框架的好处是什么?(1)轻量:Spring 是轻量的,基本的版本大约 2MB。(2)控制反转:Spring 通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。(3)面向切面的编程(AOP):Spring 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。(4)容器:Spring 包含并管理应用中对象的生命周期和配置。(5)MVC 框架:Spring 的 WEB 框架是个精心设计的框架,是 Web 框架的一个很好的替代品。(6)事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。(7)异常处理:Spring 提供方便的 API 把具体技术相关的异常(比如由 JDBC,Hibernate or JDO 抛出的)转化为一致的 unchecked 异常。 53、Spring 由哪些模块组成?以下是 Spring 框架的基本模块:(1)Core module(2)Bean module(3)Context module(3)Expression Language module(4)JDBC module(5)ORM module(6) OXM module(7)Java Messaging Service(JMS) module(8)Transaction module(9)Web module(10)Web-Servlet module(11)Web-Struts module(12)Web-Portlet module 54、核心容器(应用上下文) 模块。这是基本的 Spring 模块,提供 spring 框架的基础功能,BeanFactory 是 任何以 spring 为基础的应用的核心。Spring 框架建立在此模块之上,它使 Spring 成为一个容器。 55、BeanFactory – BeanFactory 实现举例。Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从正真的应用代码中分离。最常用的 BeanFactory 实现是 XmlBeanFactory 类。 66、XMLBeanFactory最常用的就是 org.springframework.beans.factory.xml.XmlBeanFactory ,它根据 XML 文件中的定义加载 beans。该容器从 XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。 67、解释 AOP 模块AOP 模块用于发给我们的 Spring 应用做面向切面的开发, 很多支持由 AOP 联盟提供,这样就确保了 Spring 和其他 AOP 框架的共通性。这个模块将元数据编程引入 Spring。 68、解释 JDBC 抽象和 DAO 模块。通过使用 JDBC 抽象和 DAO 模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用 Spring 的 AOP 模块给 Spring 应用中的对象提供事务管理服务。 69、解释对象/关系映射集成模块。Spring 通过提供 ORM 模块,支持我们在直接 JDBC 之上使用一个对象/关系映射映射(ORM)工具,Spring 支持集成主流的 ORM 框架,如 Hiberate,JDO 和 iBATISSQL Maps。Spring 的事务管理同样支持以上所有 ORM 框架及 JDBC。 70、解释 WEB 模块。Spring 的 WEB 模块是构建在 application context 模块基础之上,提供一个适合 web 应用的上下文。这个模块也包括支持多种面向 web 的任务,如透明地处理多个文件上传请求和程序级请求参数的绑定到你的业务对象。它也有对 JakartaStruts 的支持。 72、Spring 配置文件Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。 73、什么是 Spring IOC 容器?Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。 74、IOC 的优点是什么?IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和 JNDI 查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。 75、ApplicationContext 通常的实现是什么?(1) FileSystemXmlApplicationContext :此容器从一个 XML 文件中加载 beans 的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。(2)ClassPathXmlApplicationContext:此容器也从一个 XML 文件中加载 beans 的定义,这里,你需要正确设置 classpath 因为这个容器将在 classpath里找 bean 配置。(3)WebXmlApplicationContext:此容器加载一个 XML 文件,此文件定义了一个 WEB 应用的所有 bean。 76、Bean 工厂和 Application contexts 有什么区别?Application contexts 提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的 bean 发布事件。另外,在容器或容器内的对象上执行的那些不得不由 bean 工厂以程序化方式处理的操作,可以在Application contexts 中以声明的方式处理。Application contexts 实现了MessageSource 接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。 77、一个 Spring 的应用看起来象什么?(1) 一个定义了一些功能的接口。(2)这实现包括属性,它的 Setter , getter 方法和函数等。(3)Spring AOP。(4)Spring 的 XML 配置文件。(5)使用以上功能的客户端程序。依赖注入 78、什么是 Spring 的依赖注入?依赖注入,是 IOC 的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC 容器)负责把他们组装起来。 79、有哪些不同类型的 IOC(依赖注入)方式?(1)构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。(2)Setter 方法注入:Setter 方法注入是容器通过调用无参构造器或无参static 工厂 方法实例化 bean 之后,调用该 bean 的 setter 方法,即实现了基于 setter 的依赖注入。 80、哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入?你两种依赖方式都可以使用,构造器注入和 Setter 方法注入。最好的解决方案是用构造器参数实现强制依赖,setter 方法实现可选依赖。 81.什么是 Spring beans?Spring beans 是那些形成 Spring 应用的主干的 java 对象。它们被 Spring IOC容器初始化,装配,和管理。这些 beans 通过容器中配置的元数据创建。比如,以 XML 文件中 的形式定义。Spring 框架定义的 beans 都是单件 beans。在 bean tag 中有个属性”singleton”,如果它被赋为 TRUE,bean 就是单件,否则就是一个 prototypebean。默认是 TRUE,所以所有在 Spring 框架中的 beans 缺省都是单件。 82、一个 Spring Bean 定义 包含什么?一个 Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。 83、如何给 Spring 容器提供配置元数据?这里有三种重要的方法给 Spring 容器提供配置元数据。(1)XML 配置文件。(2)基于注解的配置。(3)基于 java 的配置。 84、你怎样定义类的作用域?当定义一个 在 Spring 里,我们还能给这个 bean 声明一个作用域。它可以通过bean 定义中的 scope 属性来定义。如,当 Spring 要在需要的时候每次生产一个新的 bean 实例,bean 的 scope 属性被指定为 prototype。另一方面,一个 bean每次使用的时候必须返回同一个实例,这个 bean 的 scope 属性 必须设为singleton。 85、解释 Spring 支持的几种 bean 的作用域。Spring 框架支持以下五种 bean 的作用域:(1)singleton : bean 在每个 Spring ioc 容器中只有一个实例。(1)prototype:一个 bean 的定义可以有多个实例。(3)request:每次 http 请求都会创建一个 bean,该作用域仅在基于 web的 Spring ApplicationContext 情形下有效。(4)session:在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。(5)global-session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。缺省的 Spring bean 的作用域是 Singleton. 86、Spring 框架中的单例 bean 是线程安全的吗?不,Spring 框架中的单例 bean 不是线程安全的。 87、解释 Spring 框架中 bean 的生命周期。(1)Spring 容器 从 XML 文件中读取 bean 的定义,并实例化 bean。(2)Spring 根据 bean 的定义填充所有的属性。(3)如果 bean 实现了 BeanNameAware 接口,Spring 传递 bean 的 ID 到setBeanName 方法。(4)如果 Bean 实现了 BeanFactoryAware 接口, Spring 传递beanfactory 给 setBeanFactory 方法。(5)如果有任何与 bean 相关联的 BeanPostProcessors,Spring 会在postProcesserBeforeInitialization()方法内调用它们。(6)如果 bean 实现 IntializingBean 了,调用它的 afterPropertySet 方法,如果 bean 声明了初始化方法,调用此初始化方法。(7) 如果有 BeanPostProcessors 和 bean 关联,这些 bean 的postProcessAfterInitialization() 方法将被调用。(8)如果 bean 实现了 DisposableBean,它将调用 destroy()方法。 88、哪些是重要的 bean 生命周期方法?你能重载它们吗?有两个重要的 bean 生命周期方法,第一个是 setup , 它是在容器加载 bean的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。The bean 标签有两个重要的属性(init-method 和 destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct 和@PreDestroy)。 89、什么是 Spring 的内部 bean?当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner bean,在 Spring 的 基于 XML 的 配置元数据中,可以在 或 元素内使用 元素,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。 90、在 Spring 中如何注入一个 java 集合?Spring 提供以下几种集合的配置元素:(1)类型用于注入一列值,允许有相同的值。(2)类型用于注入一组值,不允许有相同的值。(3)类型用于注入一组键值对,键和值都可以为任意类型。(4)类型用于注入一组键值对,键和值都只能为 String 类型。 91、什么是 bean 装配?装配,或 bean 装配是指在 Spring 容器中把 bean 组装到一起,前提是容器需要知道 bean 的依赖关系,如何通过依赖注入来把它们装配到一起。 92、什么是 bean 的自动装配?Spring 容器能够自动装配相互合作的 bean,这意味着容器不需要和配置,能通过 Bean 工厂自动处理 bean 之间的协作。 93、解释不同方式的自动装配 。有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。(1)no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。(2)byName:通过参数名 自动装配,Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。(3)byType::通过参数类型自动装配,Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byType,之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件,则抛出错误。(4)constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。(5)autodetect:首先尝试使用 constructor 来自动装配,如果无法工作,则使用 byType 方式。(6)no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。(7)byName:通过参数名 自动装配,Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。(8)byType::通过参数类型自动装配,Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byType,之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件,则抛出错误。(9)constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。(10)autodetect:首先尝试使用 constructor 来自动装配,如果无法工作,则使用 byType 方式。 94.自动装配有哪些局限性 ?自动装配的局限性是:(1)重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。(2)基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。(3)模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。 95、你可以在 Spring 中注入一个 null 和一个空字符串吗?可以。 96、什么是基于 Java 的 Spring 注解配置? 给一些注解的例子.基于 Java 的配置,允许你在少量的 Java 注解的帮助下,进行你的大部分 Spring配置而非通过 XML 文件。以@Configuration 注解为例,它用来标记类可以当做一个 bean 的定义,被Spring IOC 容器使用。另一个例子是@Bean 注解,它表示此方法将要返回一个对象,作为一个 bean 注册进 Spring 应用上下文。 97、什么是基于注解的容器配置?相对于 XML 文件,注解型的配置依赖于通过字节码元数据装配组件,而非尖括号的声明。开发者通过在相应的类,方法或属性上使用注解的方式,直接组件类中进行配置,而不是使用xml 表述 bean 的装配关系。 98、怎样开启注解装配?注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在 Spring 配置文件中配置 context:annotation-config/元素。 99、@Required 注解这个注解表明 bean 的属性必须在配置的时候设置,通过一个 bean 定义的显式的属性值或通过自动装配,若@Required 注解的 bean 属性未被设置,容器将抛出BeanInitializationException。 100、@Autowired 注解@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required 一样,修饰 setter 方法、构造器、属性或者具有任意名称和/或多个参数的 PN 方法。 101、@Qualifier 注解当有多个相同类型的 bean 却只有一个需要自动装配时,将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的 bean。 102.在 Spring 框架中如何更有效地使用 JDBC?使用 SpringJDBC 框架,资源管理和错误处理的代价都会被减轻。所以开发者只需写 statements 和 queries 从数据存取数据,JDBC 也可以在 Spring 框架提供的模板类的帮助下更有效地被使用,这个模板叫 JdbcTemplate (例子见这里here) 103、JdbcTemplateJdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操作语句,提供自定义的数据错误处理。 104、Spring 对 DAO 的支持Spring 对数据访问对象(DAO)的支持旨在简化它和数据访问技术如 JDBC,Hibernate or JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。 105、使用 Spring 通过什么方式访问 Hibernate?在 Spring 中有两种方式访问 Hibernate:(1)控制反转 Hibernate Template 和 Callback。(2)继承 HibernateDAOSupport 提供一个 AOP 拦截器。 106、Spring 支持的 ORMSpring 支持以下 ORM:(1)Hibernate(2)iBatis(3) JPA (Java Persistence API)(4)TopLink(5)JDO (Java Data Objects)(7)OJB 107.如何通过 HibernateDaoSupport 将 Spring 和 Hibernate结合起来?用 Spring 的 SessionFactory 调用 LocalSessionFactory。集成过程分三步:(1)配置 the Hibernate SessionFactory。(2)继承 HibernateDaoSupport 实现一个 DAO。(3) 在 AOP 支持的事务中装配。 108、Spring 支持的事务管理类型Spring 支持两种类型的事务管理:(1)编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。(2)声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和 XML 配置来管理事务。 109、Spring 框架的事务管理有哪些优点?(1)它为不同的事务 API 如 JTA,JDBC,Hibernate,JPA 和 JDO,提供一个不变的编程模式。(2)它为编程式事务管理提供了一套简单的 API 而不是一些复杂的事务 API如(3) 它支持声明式事务管理。(4)它和 Spring 各种数据访问抽象层很好得集成。 110、你更倾向用那种事务管理类型?大多数 Spring 框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许你通过代码控制事务)少了一点灵活性。 111、解释 AOP面向切面的编程,或 AOP, 是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理。 112、Aspect 切面AOP 核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组 API 提供横切功能。比如,一个日志模块可以被称作日志的 AOP 切面。根据需求的不同,一个应用程序可以有若干切面。在 Spring AOP 中,切面通过带有@Aspect 注解的类实现。 113、在 Spring AOP 中,关注点和横切关注的区别是什么?关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。 114、连接点连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个 AOP 切面,它实际上是个应用程序执行 Spring AOP 的位置。 115、通知通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP 框架触发的代码段。Spring 切面可以应用五种类型的通知:(1)before:前置通知,在一个方法执行前被调用。(2)after: 在方法执行之后调用的通知,无论方法执行是否成功。(3)after-returning: 仅当方法成功完成后执行的通知。(4)after-throwing: 在方法抛出异常退出时执行的通知。(5) around: 在方法执行之前和之后调用的通知。 116、切点切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。 117、什么是引入?引入允许我们在已存在的类中增加新的方法和属性。 118、什么是目标对象?被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。 119、什么是代理?代理是通知目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是一样的。 120、有几种不同类型的自动代理?(1)BeanNameAutoProxyCreator(2)DefaultAdvisorAutoProxyCreator(3)Metadata autoproxying 121、什么是织入。什么是织入应用的不同点?织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。织入可以在编译时,加载时,或运行时完成。 122、解释基于 XML Schema 方式的切面实现。在这种情况下,切面由常规类以及基于 XML 的配置实现。 123、解释基于注解的切面实现在这种情况下(基于@AspectJ 的实现),涉及到的切面声明的风格与带有 java5 标注的普通 java 类一致。 124、什么是 Spring 的 MVC 框架?Spring 配备构建 Web 应用的全功能 MVC 框架。Spring 可以很便捷地和其他MVC 框架集成,如 Struts,Spring 的 MVC 框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。 125、DispatcherServletSpring 的 MVC 框架是围绕 DispatcherServlet 来设计的,它用来处理所有的 HTTP请求和响应。 126、WebApplicationContextWebApplicationContext 继承了 ApplicationContext 并增加了一些 WEB 应用必备的特有功能,它不同于一般的 ApplicationContext ,因为它能处理主题,并找到被关联的 servlet。 127、什么是 Spring MVC 框架的控制器?控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring 用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。 128、@Controller 注解该注解表明该类扮演控制器的角色,Spring 不需要你继承任何其他控制器基类或引用 Servlet API。 129、@RequestMapping 注解该注解是用来映射一个 URL 到一个类或一个特定的方处理法上。 最后欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!

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

18道kafka高频面试题哪些你还不会?(含答案和思维导图)

前言 Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源 项目。 关于Kafka的知识总结了个思维导图 kafka 面试题 1、如何获取 topic 主题的列表2、生产者和消费者的命令行是什么?3、consumer 是推还是拉?4、讲讲 kafka 维护消费状态跟踪的方法5、讲一下主从同步6、为什么需要消息系统,mysql 不能满足需求吗?7、Zookeeper 对于 Kafka 的作用是什么?8、数据传输的事务定义有哪三种?9、Kafka 判断一个节点是否还活着有那两个条件?10、Kafka 与传统 MQ 消息系统之间有三个关键区别11、讲一讲 kafka 的 ack 的三种机制13、消费者故障,出现活锁问题如何解决?14、如何控制消费的位置15、kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?16、kafka 的高可用机制是什么?17、kafka 如何减少数据丢失18、kafka 如何不消费重复数据?比如扣款,我们不能重复的扣。 1、如何获取 topic 主题的列表 bin/kafka-topics.sh --list --zookeeper localhost:2181 2、生产者和消费者的命令行是什么? 生产者在主题上发布消息:bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 --topicHello-Kafka注意这里的 IP 是 server.properties 中的 listeners 的配置。接下来每个新行就是输入一条新消息。消费者接受消息:bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topicHello-Kafka --from-beginning 3、consumer 是推还是拉? Kafka 最初考虑的问题是,customer 应该从 brokes 拉取消息还是 brokers 将消息推送到 consumer,也就是 pull 还 push。在这方面,Kafka 遵循了一种大部分消息系统共同的传统的设计:producer 将消息推送到 broker,consumer 从broker 拉取消息。一些消息系统比如 Scribe 和 Apache Flume 采用了 push 模式,将消息推送到下游的 consumer。这样做有好处也有坏处:由 broker 决定消息推送的速率,对于不同消费速率的 consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消息,但不幸的是,push 模式下,当 broker 推送的速率远大于 consumer 消费的速率时,consumer 恐怕就要崩溃了。最终 Kafka 还是选取了传统的 pull 模式。Pull 模式的另外一个好处是 consumer 可以自主决定是否批量的从 broker 拉取数据 。Push 模式必须在不知道下游 consumer 消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。如果为了避免 consumer 崩溃而采用较低的推送速率,将可能导致一次只推送较少的消息而造成浪费。Pull 模式下,consumer 就可以根据自己的消费能力去决定这些策略。Pull 有个缺点是,如果 broker 没有可供消费的消息,将导致 consumer 不断在循环中轮询,直到新消息到 t 达。为了避免这点,Kafka 有个参数可以让 consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发送)。 4、讲讲 kafka 维护消费状态跟踪的方法 大部分消息系统在 broker 端的维护消息被消费的记录:一个消息被分发到consumer 后 broker 就马上进行标记或者等待 customer 的通知后进行标记。这样也可以在消息在消费后立马就删除以减少空间占用。但是这样会不会有什么问题呢?如果一条消息发送出去之后就立即被标记为消费过的,旦 consumer 处理消息时失败了(比如程序崩溃)消息就丢失了。为了解决这个问题,很多消息系统提供了另外一个个功能:当消息被发送出去之后仅仅被标记为已发送状态,当接到 consumer 已经消费成功的通知后才标记为已被消费的状态。这虽然解决了消息丢失的问题,但产生了新问题,首先如果 consumer处理消息成功了但是向 broker 发送响应时失败了,这条消息将被消费两次。第二个问题时,broker 必须维护每条消息的状态,并且每次都要先锁住消息然后更改状态然后释放锁。这样麻烦又来了,且不说要维护大量的状态数据,比如如果消息发送出去但没有收到消费成功的通知,这条消息将一直处于被锁定的状态,Kafka 采用了不同的策略。Topic 被分成了若干分区,每个分区在同一时间只被一个 consumer 消费。这意味着每个分区被消费的消息在日志中的位置仅仅是一个简单的整数:offset。这样就很容易标记每个分区消费状态就很容易了,仅仅需要一个整数而已。这样消费状态的跟踪就很简单了。这带来了另外一个好处:consumer 可以把 offset 调成一个较老的值,去重新消费老的消息。这对传统的消息系统来说看起来有些不可思议,但确实是非常有用的,谁规定了一条消息只能被消费一次呢? 5、讲一下主从同步 Kafka允许topic的分区拥有若干副本,这个数量是可以配置的,你可以为每个topci配置副本的数量。Kafka会自动在每个个副本上备份数据,所以当一个节点down掉时数据依然是可用的。Kafka的副本功能不是必须的,你可以配置只有一个副本,这样其实就相当于只有一份数据。 6、为什么需要消息系统,mysql 不能满足需求吗? (1)解耦:允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。(2)冗余:消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。(3)扩展性:因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。(4)灵活性 & 峰值处理能力:在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。(5)可恢复性:系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。(6)顺序保证:在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)(7)缓冲:有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。(8)异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。 7、Zookeeper 对于 Kafka 的作用是什么? Zookeeper 是一个开放源码的、高性能的协调服务,它用于 Kafka 的分布式应用。Zookeeper 主要用于在集群中不同节点之间进行通信在 Kafka 中,它被用于提交偏移量,因此如果节点在任何情况下都失败了,它都可以从之前提交的偏移量中获取除此之外,它还执行其他活动,如: leader 检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。 8、数据传输的事务定义有哪三种? 和 MQTT 的事务定义一样都是 3 种。(1)最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输(2)最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.(3)精确的一次(Exactly once): 不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次,这是大家所期望的 9、Kafka 判断一个节点是否还活着有那两个条件? (1)节点必须可以维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每个节点的连接(2)如果节点是个 follower,他必须能及时的同步 leader 的写操作,延时不能太久 10、Kafka 与传统 MQ 消息系统之间有三个关键区别 (1).Kafka 持久化日志,这些日志可以被重复读取和无限期保留(2).Kafka 是一个分布式系统:它以集群的方式运行,可以灵活伸缩,在内部通过复制数据提升容错能力和高可用性(3).Kafka 支持实时的流式处理 11、讲一讲 kafka 的 ack 的三种机制 request.required.acks 有三个值 0 1 -1(all)0:生产者不会等待 broker 的 ack,这个延迟最低但是存储的保证最弱当 server 挂掉的时候就会丢数据。1:服务端会等待 ack 值 leader 副本确认接收到消息后发送 ack 但是如果 leader挂掉后他不确保是否复制完成新 leader 也会导致数据丢失。-1(all):服务端会等所有的 follower 的副本受到数据后才会受到 leader 发出的ack,这样数据不会丢失 12、消费者如何不自动提交偏移量,由应用提交? 将 auto.commit.offset 设为 false,然后在处理一批消息后 commitSync() 或者异步提交 commitAsync()即: ConsumerRecords<> records = consumer.poll(); for (ConsumerRecord<> record : records){ 。。。 tyr{ consumer.commitSync() } 。。。 } 13、消费者故障,出现活锁问题如何解决? 出现“活锁”的情况,是它持续的发送心跳,但是没有处理。为了预防消费者在这种情况下一直持有分区,我们使用 max.poll.interval.ms 活跃检测机制。 在此基础上,如果你调用的 poll 的频率大于最大间隔,则客户端将主动地离开组,以便其他消费者接管该分区。 发生这种情况时,你会看到 offset 提交失败(调用commitSync()引发的 CommitFailedException)。这是一种安全机制,保障只有活动成员能够提交 offset。所以要留在组中,你必须持续调用 poll。消费者提供两个配置设置来控制 poll 循环:max.poll.interval.ms:增大 poll 的间隔,可以为消费者提供更多的时间去处理返回的消息(调用 poll(long)返回的消息,通常返回的消息都是一批)。缺点是此值越大将会延迟组重新平衡。max.poll.records:此设置限制每次调用 poll 返回的消息数,这样可以更容易的预测每次 poll 间隔要处理的最大值。通过调整此值,可以减少 poll 间隔,减少重新平衡分组的对于消息处理时间不可预测地的情况,这些选项是不够的。 处理这种情况的推荐方法是将消息处理移到另一个线程中,让消费者继续调用 poll。 但是必须注意确保已提交的 offset 不超过实际位置。另外,你必须禁用自动提交,并只有在线程完成处理后才为记录手动提交偏移量(取决于你)。 还要注意,你需要 pause 暂停分区,不会从 poll 接收到新消息,让线程处理完之前返回的消息(如果你的处理能力比拉取消息的慢,那创建新线程将导致你机器内存溢出)。 14、如何控制消费的位置 kafka 使用 seek(TopicPartition, long)指定新的消费位置。用于查找服务器保留的最早和最新的 offset 的特殊的方法也可用(seekToBeginning(Collection) 和seekToEnd(Collection)) 15、kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费? Kafka 分布式的单位是 partition,同一个 partition 用一个 write ahead log 组织,所以可以保证 FIFO 的顺序。不同 partition 之间不能保证顺序。但是绝大多数用户都可以通过 message key 来定义,因为同一个 key 的 message 可以保证只发送到同一个 partition。Kafka 中发送 1 条消息的时候,可以指定(topic, partition, key) 3 个参数。partiton 和 key 是可选的。如果你指定了 partition,那就是所有消息发往同 1个 partition,就是有序的。并且在消费端,Kafka 保证,1 个 partition 只能被1 个 consumer 消费。或者你指定 key( 比如 order id),具有同 1 个 key 的所有消息,会发往同 1 个 partition。 16、kafka 的高可用机制是什么? 这个问题比较系统,回答出 kafka 的系统特点,leader 和 follower 的关系,消息读写的顺序即可。 17、kafka 如何减少数据丢失 Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生。下面的参数配置及Best practice列表可以较好地保证数据的持久性(当然是trade-off,牺牲了吞吐量)。block.on.buffer.full = trueacks = allretries = MAX_VALUEmax.in.flight.requests.per.connection = 1使用KafkaProducer.send(record, callback)callback逻辑中显式关闭producer:close(0)unclean.leader.election.enable=falsereplication.factor = 3min.insync.replicas = 2replication.factor > min.insync.replicasenable.auto.commit=false消息处理完成之后再提交位移 18、kafka 如何不消费重复数据?比如扣款,我们不能重复的扣。 其实还是得结合业务来思考,我这里给几个思路:比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 最后 欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!

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

2019年Java面试题基础系列228道(1),快看看哪些你还不会?

Java面试题(一) 1、面向对象的特征有哪些方面? 2、访问修饰符 public,private,protected,以及不写(默认)时的区别? 3、String 是最基本的数据类型吗? 4、float f=3.4;是否正确? 5、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗? 6、Java 有没有 goto? 7、int 和 Integer 有什么区别? 8、&和&&的区别? 9、解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。 10、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少? 11、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上? 12、用最有效率的方法计算 2 乘以 8? 13、数组有没有 length()方法?String 有没有 length()方法? 14、在 Java 中,如何跳出当前的多重嵌套循环? 15、构造器(constructor)是否可被重写(override)? 16、两个对象值相同(x.equals(y) == true),但却可有不同的 hashcode,这句话对不对? 17、是否可以继承 String 类? 18、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 19、String 和 StringBuilder、StringBuffer 的区别? 20、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分? 21、描述一下 JVM 加载 class 文件的原理机制? 22、char 型变量中能不能存贮一个中文汉字,为什么? 23、抽象类(abstract class)和接口(interface)有什么异同? 24、静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同? 25、Java 中会存在内存泄漏吗,请简单描述。 26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被 synchronized 修饰? 27、阐述静态变量和实例变量的区别。 28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用? 29、如何实现对象克隆? 30、GC 是什么?为什么要有 GC? 31、String s = new String(“xyz”);创建了几个字符串对象? 32 、 接 口 是 否 可 继 承 ( extends ) 接 口 ? 抽 象 类 是 否 可 实 现(implements)接口?抽象类是否可继承具体类(concrete class)? 33、一个”.java”源文件中是否可以包含多个类(不是内部类)?有什么限制? 34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 36、Java 中的 final 关键字有哪些用法? 37、指出下面程序的运行结果 38、数据类型之间的转换: 39、如何实现字符串的反转及替换? 40、怎样将 GB2312 编码的字符串转换为 ISO-8859-1 编码的字符串? 41、日期和时间: 42、打印昨天的当前时刻。 43、比较一下 Java 和 JavaSciprt。 44、什么时候用断言(assert)? 45、Error 和 Exception 有什么区别? 46、try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally{}里的代码会不会被执行,什么时候被执行,在 return 前还是后? 47、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally 分别如何使用? 48、运行时异常与受检异常有何异同? 49、列出一些你常见的运行时异常? 50、阐述 final、finally、finalize 的区别。 51、类 ExampleA 继承 Exception,类 ExampleB 继承 ExampleA。 52、List、Set、Map 是否继承自 Collection 接口? 53、阐述 ArrayList、Vector、LinkedList 的存储性能和特性。 54、Collection 和 Collections 的区别? 55、List、Map、Set 三个接口存取元素时,各有什么特点? 56、TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素? 57、Thread 类的 sleep()方法和对象的 wait()方法都可以让线程暂停执行,它们有什么区别? 58、线程的 sleep()方法和 yield()方法有什么区别? 59、当一个线程进入一个对象的 synchronized 方法 A 之后,其它线程是否可进入此对象 synchronized 方法 B? 60、请说出与线程同步以及线程调度相关的方法。 61、编写多线程程序有几种实现方式? 62、synchronized 关键字的用法? 63、举例说明同步和异步。 64、启动一个线程是调用 run()还是 start()方法? 65、什么是线程池(thread pool)? 66、线程的基本状态以及状态之间的关系? 67、简述 synchronized 和 java.util.concurrent.locks.Lock 的异同? 68、Java 中如何实现序列化,有什么意义? 69、Java 中有几种类型的流? 70、写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数。 71、如何用 Java 代码列出一个目录下所有的文件? 72、用 Java 的套接字编程实现一个多线程的回显(echo)服务器。 73、XML 文档定义有几种形式?它们之间有何本质区别?解析 XML文档有哪几种方式? 74、你在项目中哪些地方用到了 XML? 75、阐述 JDBC 操作数据库的步骤。 76、Statement 和 PreparedStatement 有什么区别?哪个性能更好? 77、使用 JDBC 操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能? 78、在进行数据库编程时,连接池有什么作用? 79、什么是 DAO 模式? 80、事务的 ACID 是指什么? 82、JDBC 能否处理 Blob 和 Clob? 83、简述正则表达式及其用途。 84、Java 中是如何支持正则表达式操作的? 85、获得一个类的类对象有哪些方式? 88、如何通过反射调用对象的方法? 90、简述一下你了解的设计模式。 91、用 Java 写一个单例类。 92、什么是 UML? 93、UML 中有哪些常用的图? 95、用 Java 写一个折半查找。 Java 面试题(二) 1、Java 中能创建 volatile 数组吗? 2、volatile 能使得一个非原子操作变成原子操作吗? 3、volatile 修饰符的有过什么实践? 4、volatile 类型变量提供什么保证? 5、10 个线程和 2 个线程的同步代码,哪个更容易写? 6、你是如何调用 wait()方法的?使用 if 块还是循环?为什么? 8、什么是 Busy spin?我们为什么要使用它? 9、Java 中怎么获取一份线程 dump 文件? 10、Swing 是线程安全的? 11、什么是线程局部变量? 12、用 wait-notify 写一段代码来解决生产者-消费者问题? 13、用 Java 写一个线程安全的单例模式(Singleton)? 14、Java 中 sleep 方法和 wait 方法的区别? 15、什么是不可变对象(immutable object)?Java 中怎么创建一个不可变对象? 16、我们能创建一个包含可变对象的不可变对象吗? 17、Java 中应该使用什么数据类型来代表价格? 18、怎么将 byte 转换为 String? 19、Java 中怎样将 bytes 转换为 long 类型? 20、我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于byte 类型的范围,将会出现什么现象? 21、存在两个类,B 继承 A ,C 继承 B,我们能将 B 转换为 C 么?如 C = (C) B; 22、哪个类包含 clone 方法?是 Cloneable 还是 Object? 23、Java 中 ++ 操作符是线程安全的吗? 23、不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。 24、a = a + b 与 a += b 的区别 25、我能在不进行强制转换的情况下将一个 double 值赋值给 long类型的变量吗? 26、3*0.1 == 0.3 将会返回什么?true 还是 false? 27、int 和 Integer 哪个会占用更多的内存? 28、为什么 Java 中的 String 是不可变的(Immutable)? 31、64 位 JVM 中,int 的长度是多数? 32、Serial 与 Parallel GC 之间的不同之处? 33、32 位和 64 位的 JVM,int 类型变量的长度是多数? 34、Java 中 WeakReference 与 SoftReference 的区别? 35、WeakHashMap 是怎么工作的? 36、JVM 选项 -XX:+UseCompressedOops 有什么作用?为什么要使用? 37、怎样通过 Java 程序来判断 JVM 是 32 位 还是 64 位? 38、32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数? 39、JRE、JDK、JVM 及 JIT 之间有什么不同? 40、解释 Java 堆空间及 GC? 41、你能保证 GC 执行吗? 42、怎么获取 Java 程序使用的内存?堆使用的百分比? 43、Java 中堆和栈有什么区别? 44、“a==b”和”a.equals(b)”有什么区别? 45、a.hashCode() 有什么用?与 a.equals(b) 有什么关系? 46、final、finalize 和 finally 的不同之处? 47、Java 中的编译期常量是什么?使用它又什么风险? 48、List、Set、Map 和 Queue 之间的区别(答案) 49、poll() 方法和 remove() 方法的区别? 50、Java 中 LinkedHashMap 和 PriorityQueue 的区别是什么? 51、ArrayList 与 LinkedList 的不区别? 52、用哪两种方式来实现集合的排序? 53、Java 中怎么打印数组? 54、Java 中的 LinkedList 是单向链表还是双向链表? 55、Java 中的 TreeMap 是采用什么树实现的?(答案) 56、Hashtable 与 HashMap 有什么不同之处? 57、Java 中的 HashSet,内部是如何工作的? 58、写一段代码在遍历 ArrayList 时移除一个元素? 59、我们能自己写一个容器类,然后使用 for-each 循环码? 60、ArrayList 和 HashMap 的默认大小是多数? 61、有没有可能两个不相等的对象有有相同的 hashcode? 62、两个相同的对象会有不同的的 hash code 吗? 63、我们可以在 hashcode() 中使用随机数字吗? 64、Java 中,Comparator 与 Comparable 有什么不同? 66、在我 Java 程序中,我有三个 socket,我需要多少个线程来处理? 67、Java 中怎么创建 ByteBuffer? 68、Java 中,怎么读写 ByteBuffer ? 69、Java 采用的是大端还是小端? 70、ByteBuffer 中的字节序是什么? 71、Java 中,直接缓冲区与非直接缓冲器有什么区别? 72、Java 中的内存映射缓存区是什么? 73、socket 选项 TCP NO DELAY 是指什么? 74、TCP 协议与 UDP 协议有什么区别? 75、Java 中,ByteBuffer 与 StringBuffer 有什么区别?(答案) 76、Java 中,编写多线程程序的时候你会遵循哪些最佳实践? 77、说出几点 Java 中使用 Collections 的最佳实践 78、说出至少 5 点在 Java 中使用线程的最佳实践。 79、说出 5 条 IO 的最佳实践(答案) 80、列出 5 个应该遵循的 JDBC 最佳实践 81、说出几条 Java 中方法重载的最佳实践? 82、在多线程环境下,SimpleDateFormat 是线程安全的吗? 83、Java 中如何格式化一个日期?如格式化为 ddMMyyyy 的形式? 84、Java 中,怎么在格式化的日期中显示时区? 85、Java 中 java.util.Date 与 java.sql.Date 有什么区别? 86、Java 中,如何计算两个日期之间的差距? 87、Java 中,如何将字符串 YYYYMMDD 转换为日期? 89、如何测试静态方法?(答案) 90、怎么利用 JUnit 来测试一个方法的异常? 91、你使用过哪个单元测试库来测试你的 Java 程序? 92、@Before 和 @BeforeClass 有什么区别? 93、怎么检查一个字符串只包含数字?解决方案 94、Java 中如何利用泛型写一个 LRU 缓存? 95、写一段 Java 程序将 byte 转换为 long? 96、在不使用 StringBuffer 的前提下,怎么反转一个字符串? 97、Java 中,怎么获取一个文件中单词出现的最高频率? 98、如何检查出两个给定的字符串是反序的? 99、Java 中,怎么打印出一个字符串的所有排列? 100、Java 中,怎样才能打印出数组中的重复元素? 101、Java 中如何将字符串转换为整数? 102、在没有使用临时变量的情况如何交换两个整数变量的值? 103、接口是什么?为什么要使用接口而不是直接使用具体类? 104、Java 中,抽象类与接口之间有什么不同? 105、除了单例模式,你在生产环境中还用过什么设计模式? 106、你能解释一下里氏替换原则吗? 107、什么情况下会违反迪米特法则?为什么会有这个问题? 108、适配器模式是什么?什么时候使用? 109、什么是“依赖注入”和“控制反转”?为什么有人使用? 110、抽象类是什么?它与接口有什么区别?你为什么要使用过抽象类? 111、构造器注入和 setter 依赖注入,那种方式更好? 112、依赖注入和工程模式之间有什么不同? 113、适配器模式和装饰器模式有什么区别? 114、适配器模式和代理模式之前有什么不同? 115、什么是模板方法模式? 116、什么时候使用访问者模式? 117、什么时候使用组合模式? 118、继承和组合之间有什么不同? 119、描述 Java 中的重载和重写? 120、Java 中,嵌套公共静态类与顶级类有什么不同? 121、 OOP 中的 组合、聚合和关联有什么区别? 122、给我一个符合开闭原则的设计模式的例子? 123、抽象工厂模式和原型模式之间的区别? 125、嵌套静态类与顶级类有什么区别? 126、你能写出一个正则表达式来判断一个字符串是否是一个数字吗? 127、Java 中,受检查异常 和 不受检查异常的区别? 128、Java 中,throw 和 throws 有什么区别 129、Java 中,Serializable 与 Externalizable 的区别? 130、Java 中,DOM 和 SAX 解析器有什么不同? 131、说出 JDK 1.7 中的三个新特性? 132、说出 5 个 JDK 1.8 引入的新特性? 133、Java 中,Maven 和 ANT 有什么区别? 本次更新Java 面试题(一)的1~20题答案 1、面向对象的特征有哪些方面? 面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段(如果不能理解请阅读阎宏博士的《Java 与模式》或《设计模式精解》中关于桥梁模式的部分)。 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当 A 系统访问 B 系统提供的服务时,B系统有多种提供服务的方式,但一切对 A 系统来说都是透明的(就像电动剃须刀是 A 系统,它的供电系统是 B 系统,B 系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A 系统只会通过 B 类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override) 实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事: 1). 方法重写(子类继承父类并重写父类中已有的或抽象的方法); 2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。 2、访问修饰符 public,private,protected,以及不写(默认)时的区别? 修饰符 当前类 同 包 子 类 其他包 类的成员不写访问修饰时默认为 default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。Java 中,外部类的修饰符只能是 public 或默认,类的成员(包括内部类)的修饰符可以是以上四种。 3、String 是最基本的数据类型吗? 不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。 4、float f=3.4;是否正确? 不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。 5、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗? 对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。 6、Java 有没有 goto? goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。(根据 James Gosling(Java 之父)编写的《The Java Programming Language》一书的附录中给出了一个 Java 关键字列表,其中有goto 和 const,但是这两个是目前无法使用的关键字,因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义,因为熟悉 C 语言的程序员都知道,在系统类库中使用过的有特殊意义的但词或单词的组合都被视为保留字) 7、int 和 Integer 有什么区别? Java 是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper class),int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。 Java 为每个原始类型提供了包装类型: 原始类型: boolean,char,byte,short,int,long,float,double 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double class AutoUnboxingTest { public static void main(String[] args) { Integer a = new Integer(3); Integer b = 3; // 将 3 自动装箱成 Integer 类型 int c = 3; System.out.println(a == b); // false 两个引用没有引用同一对 象 System.out.println(a == c); // true a 自动拆箱成 int 类型再和 c 比较 } } 最近还遇到一个面试题,也是和自动装箱和拆箱有点关系的,代码如下所示: public class Test03 { public static void main(String[] args) { Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println(f1 == f2); System.out.println(f3 == f4); } } 如果不明就里很容易认为两个输出要么都是 true 要么都是 false。首先需要注意的是 f1、f2、f3、f4 四个变量都是 Integer 对象引用,所以下面的==运算比较的不是值而是引用。装箱的本质是什么呢?当我们给一个 Integer 对象赋一个 int 值的时候,会调用 Integer 类的静态方法 valueOf,如果看 valueOf 的源代码就知道发生了什么。 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } IntegerCache 是 Integer 的内部类,其代码如下所示: /** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseint(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for (int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() { } } 简单的说,如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer对象,而是直接引用常量池中的 Integer 对象,所以上面的面试题中 f1f4 的结果是 false。 提醒:越是貌似简单的面试题其中的玄机就越多,需要面试者有相当深厚的功力。 8、&和&&的区别? &运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会生 NullPointerException 异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。 9、解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。 通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用 JVM 中的栈空间;而通过 new 关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为 Eden、Survivor(又可分为 From Survivor 和 To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被 JVM 加载的类信息、常量、静态变量、JIT 编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的 100、”hello”和常量都是放在常量池中,常量池是方法区的一部分,。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过 JVM的启动参数来进行调整,栈空间用光了会引发 StackOverflowError,而堆和常量池空间不足则会引发 OutOfMemoryError。 String str = new String("hello"); 上面的语句中变量 str 放在栈上,用 new 创建出来的字符串对象放在堆上,而”hello”这个字面量是放在方法区的。 补充 1:较新版本的 Java(从 Java 6 的某个更新开始)中,由于 JIT 编译器的发展和”逃逸分析”技术的逐渐成熟,栈上分配、标量替换等优化技术使得对象一定分配在堆上这件事情已经变得不那么绝对了。 补充 2:运行时常量池相当于 Class 文件常量池具有动态性,Java 语言并不要求常量一定只有编译期间才能产生,运行期间也可以将新的常量放入池中,String类的 intern()方法就是这样的。 看看下面代码的执行结果是什么并且比较一下 Java 7 以前和以后的运行结果是否一致。 String s1 = new StringBuilder("go") .append("od").toString(); System.out.println(s1.intern() == s1); String s2 = new StringBuilder("ja") .append("va").toString(); System.out.println(s2.intern() == s2); 10、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少? Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。 11、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上? 在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。 12、用最有效率的方法计算 2 乘以 8? 2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)。补充:我们为编写的类重写 hashCode 方法时,可能会看到如下所示的代码,其实我们不太理解为什么要使用这样的乘法运算来产生哈希码(散列码),而且为什么这个数是个素数,为什么通常选择 31 这个数?前两个问题的答案你可以自己百度一下,选择 31 是因为可以用移位和减法运算来代替乘法,从而得到更好的性能。说到这里你可能已经想到了:31 * num 等价于(num << 5) - num,左移 5位相当于乘以 2 的 5 次方再减去自身就相当于乘以 31,现在的 VM 都能自动完成这个优化。 public class PhoneNumber { private int areaCode; private String prefix; private String lineNumber; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + areaCode; result = prime * result + ((lineNumber == null) ? 0 : lineNumber.hashCode()); result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); return result; } @Override public Boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PhoneNumber other = (PhoneNumber) obj; if (areaCode != other.areaCode) return false; if (lineNumber == null) { if (other.lineNumber != null) return false; } else if (!lineNumber.equals(other.lineNumber)) return false; if (prefix == null) { if (other.prefix != null) return false; } else if (!prefix.equals(other.prefix)) return false; return true; } } 13、数组有没有 length()方法?String 有没有 length()方法? 数组没有 length()方法 ,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 14、在 Java 中,如何跳出当前的多重嵌套循环? 在最外层循环前加一个标记如 A,然后用 break A;可以跳出多重循环。(Java 中支持带标签的 break 和 continue 语句,作用有点类似于 C 和 C++中的 goto 语句,但是就像要避免使用 goto 一样,应该避免使用带标签的 break 和 continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好) 15、构造器(constructor)是否可被重写(override)? 构造器不能被继承,因此不能被重写,但可以被重载。 16、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? 不对,如果两个对象 x 和 y 满足 x.equals(y) == true,它们的哈希码(hash code)应当相同。Java 对于 eqauls 方法和 hashCode 方法是这样规定的: (1)如果两个对象相同(equals 方法返回 true),那么它们的 hashCode 值一定要相同; (2)如果两个对象的 hashCode 相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在 Set 集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。 补充:关于 equals 和 hashCode 方法,很多 Java 程序都知道,但很多人也就是仅仅知道而已,在 Joshua Bloch 的大作《Effective Java》(很多软件公司,《Effective Java》、《Java 编程思想》以及《重构:改善既有代码质量》是 Java程序员必看书籍,如果你还没看过,那就赶紧去买一本吧)中是这样介绍equals 方法的:首先 equals 方法必须满足自反性(x.equals(x)必须返回 true)、对称性(x.equals(y)返回 true 时,y.equals(x)也必须返回 true)、传递性(x.equals(y)和 y.equals(z)都返回 true 时,x.equals(z)也必须返回 true)和一致性(当 x 和 y 引用的对象信息没有被修改时,多次调用 x.equals(y)应该得到同样的返回值),而且对于任何非 null 值的引用 x,x.equals(null)必须返回 false。 实现高质量的 equals 方法的诀窍包括: (1) 使用==操作符检查”参数是否为这个对象的引用”; (2) 使用 instanceof 操作符检查”参数是否为正确的类型”; (3) 对于类中的关键属性,检查参数传入对象的属性是否与之相匹配; (4) 编写完 equals方法后,问自己它是否满足对称性、传递性、一致性; (5) 重写 equals 时总是要重写 hashCode; (6) 不要将 equals 方法参数中的 Object 对象替换为其他的类型,在重写时不要忘掉@Override 注解。 17、是否可以继承 String 类? String 类是 final 类,不可以被继承。补充:继承 String 本身就是一个错误的行为,对 String 类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)。 18、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。C++和 C#中可以通过传引用或传输出参数来改变传入的参数的值。在 C#中可以编写如下所示的代码,但是在 Java 中却做不到。 using System; namespace CS01 { class Program { public static void swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } public static void Main (string[] args) { int a = 5, b = 10; swap (ref a, ref b); // a = 10, b = 5; Console.WriteLine ("a = {0}, b = {1}", a, b); } } } 说明:Java 中没有传引用实在是非常的不方便,这一点在 Java 8 中仍然没有得到改进,正是如此在 Java 编写的代码中才会出现大量的 Wrapper 类(将需要通过方法调用修改的引用置于一个 Wrapper 类中,再将 Wrapper 对象传入方法),这样的做法只会让代码变得臃肿,尤其是让从 C 和 C++转型为 Java 程序员的开发者无法容忍。 19、String 和 StringBuilder、StringBuffer 的区别? Java 平台提供了两种类型的字符串:String 和 StringBuffer/StringBuilder,它们可以储存和操作字符串。其中 String 是只读字符串,也就意味着 String 引用的字符串内容是不能被改变的。而 StringBuffer/StringBuilder 类表示的字符串对象可以直接进行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized 修饰,因此它的效率也比 StringBuffer 要高。 面试题 1 - 什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder 对象的 append 方法连接字符串性能更好? 面试题 2 - 请说出下面程序的输出。 class StringEqualTest { public static void main(String[] args) { String s1 = "Programming"; String s2 = new String("Programming"); String s3 = "Program"; String s4 = "ming"; String s5 = "Program" + "ming"; String s6 = s3 + s4; System.out.println(s1 == s2); System.out.println(s1 == s5); System.out.println(s1 == s6); System.out.println(s1 == s6.intern()); System.out.println(s2 == s2.intern()); } } 补充:解答上面的面试题需要清除两点: (1)String 对象的 intern 方法会得到字符串对象在常量池中对应的版本的引用(如果常量池中有一个字符串与 String 对象的 equals 结果是 true),如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用; (2)字符串的+操作其本质是创建了 StringBuilder 对象进行 append 操作,然后将拼接后的 StringBuilder 对象用toString 方法处理成 String 对象,这一点可以用 javap -c StringEqualTest.class命令获得 class 文件对应的 JVM 字节码指令就可以看出来。 20、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分? 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。 面试题:华为的面试题中曾经问过这样一个问题 - “为什么不能根据返回类型来区分重载”,快说出你的答案吧! 最后 欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

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

python基础(81道题)面试题,再也不用为没有答案发愁了

1、为什么学习Python? 人生苦短....哈哈,自己想吧!!! 2、通过什么途径学习的Python? 官网、网上视频、学习网站 3、Python和Java、PHP、C、C#、C++等其他语言的对比? 1、python代码,简介,明确,优雅,简单易懂2、开发效率高3、可扩展性强 4、简述解释型和编译型编程语言? 解释型:在执行程序时,计算机才一条一条的将代码解释成机器语言给计算机来执行编译型:是把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样计算机运行该程序时可以直接以机器语言来运行此程序,运行速度很快。 5、Python解释器种类以及特点? Cpython,IPython,Jpython,pypy,IronpythonPython是一门解释器语言,代码想运行,必须通过解释器执行,Python存在多种解释器,分别基于不同语言开发,每个解释器有不同的特点,但都能正常运行Python代码,以下是常用的五种Python解释器: CPython:当 从Python官方网站下载并安装好Python2.7后,就直接获得了一个官方版本的解 释器:Cpython,这个解释器是用C语言开发的,所以叫 CPython,在命名行下运行python, 就是启动CPython解释器,CPython是使用最广的Python解释器。 IPython:IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方 式上有所增强,但是执行Python代码的功能和CPython是完全一样的,好比很多国产浏览器 虽然外观不同,但内核其实是调用了IE。 PyPy:PyPy是另一个Python解释器,它的目标是执行速度,PyPy采用JIT技术, 对Python代进行动态编译,所以可以显著提高 Python代码的执行速度。 Jython:Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。 IronPython:IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器, 可以直接把Python代码编译成.Net的字节码。 在Python的解释器中,使用广泛的是CPython,对于Python的编译,除了可以采用以上解释器 进行编译外,技术高超的开发者还可以按照自己的需求自行编写Python解释器来执行Python代码,十分的方便! 6、位和字节的关系? 一个字节=8位 7、b、B、KB、MB、GB 的关系? 1B(字节) = 8b(位)1KB = 1024B1MB = 1024KB1GB = 1024MB 8、请至少列举5个 PEP8 规范 1、缩进:每一级4个缩进。连续跨行应该使用圆括号或大括号或者使用悬挂缩进。 2、代码长度约束 一行列数:PEP8 规定最大为79列,如果拼接url很容易超限 一个函数:不可以超过30行;直观来讲就是完整显示一个函数一个屏幕就够了,不需要上下拖动 一个类:不要超过200行代码,不要超过10个方法 一个模块:不要超过500行 3、import 不要在一句import中引用多个库 4、命名规范 5、注释 总体原则,错误的注释不如没有注释。所以当一段代码发生变化时,第一件事就是要修改注释! 9、通过代码实现如下转换: 答案: 二进制转换成十进制:v = “0b1111011” print(int('0b1111011',2)) 十进制转换成二进制:v = 18 print(bin(18)) 八进制转换成十进制:v = “011” print(int('011',8)) 十进制转换成八进制:v = 30 print(oct(30)) 十六进制转换成十进制:v = “0x12” print(int('0x12',16)) 十进制转换成十六进制:v = 87 print(hex(87)) 10、请编写一个函数实现将IP地址转换成一个整数。 如 10.3.9.12 转换规则为: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ? 答案: def func(x): lis = x.strip().split('.') li = [bin(int(i)) for i in lis] li2 = [i.replace('0b',(10-len(i))*'0') for i in li] return int(''.join(li2),2) ret = func('10.3.9.12') print(ret) 11、python递归的最大层数? 一般计算机默认的最大递归深度在1000左右,python最大递归深度一般在4000左右,跟计算 机的性能有关系,这个数不是一个定数,可通过一下方式测试 import sys print(sys.getrecursionlimit()) print(sys.setrecursionlimit(10000)) 12、求结果: v1 = 1 or 3 -------------->1v2 = 1 and 3-------------->3v3 = 0 and 2 and 1-------->0v4 = 0 and 2 or 1--------->1v5 = 0 and 2 or 1 or 4---->1v6 = 0 or Flase and 1----->False 13、ascii、unicode、utf-8、gbk 区别? ASCII码:使用一个字节编码,所以它的范围基本是只有英文字母、数字和一些特殊符号 ,只有256个字符。Unicode:能够表示全世界所有的字节GBK:是只用来编码汉字的,GBK全称《汉字内码扩展规范》,使用双字节编码。UTF-8:是一种针对Unicode的可变长度字符编码,又称万国码。 14、字节码和机器码的区别? 机器码:是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂字节码:是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。 15、三元运算规则以及应用场景? 规则:为真时的结果 if 判定条件 else 为假时的结果 ```应用场景:在赋值变量的时候,可以直接加判断,然后赋值` 16、列举 Python2和Python3的区别? 1、默认编码:2-->ascii,3-->utf-8 2、print的区别:python2中print是一个语句,不论想输出什么,直接放到print关键字后面即可。python3里,print()是一个函数, 像其他函数一样,print()需要你将要输出的东西作为参数传给它。 3、input的区别: python2有两个全局函数,用在命令行请求用户输入。第一个叫input(),它等待用户输入一个python表达式(然后返回结果)。 第二个叫做raw_input(),用户输入什么他就返回什么。python3 通过input替代了他们。 4、字符串:python2中有两种字符串类型:Unicode字符串和非Unicode字符串。Python3中只有一种类型:Unicode字符串。 5、xrange() python2里,有两种方法获得一定范围内的数字:range(),返回一个列表,还有xrange(),返回一个迭代器。 python3 里,range()返回迭代器,xrange()不再存在。 更多不同:https://www.cnblogs.com/weikunzz/p/6857971.html 17、用一行代码实现数值交换: a = 1 b = 2 答案:a = 1 b = 2 a,b = b,a 18、Python3和Python2中 int 和 long的区别? python2有非浮点数准备的int和long类型。int类型最大值不能超过sys.maxint,而且这个最大值是平台相关的。可以通过在数字的末尾附上一个L来定义长整型,显然,它比int类型表示的数字范围更大。在python3里,只有一种整数类型int,大多数情况下,和python2中的长整型类似。 19、xrange和range的区别? python2里,有两种方法获得一定范围内的数字:range(),返回一个列表,还有xrange(),返回一个迭代器。python3 里,range()返回迭代器,xrange()不再存在。 20、文件操作时:xreadlines和readlines的区别? readlines返回一个list,xreadlines方法返回一个生成器 21、列举布尔值为False的常见值? 0, [] , () , {} , '' , False , None 22、字符串、列表、元组、字典每个常用的5个方法? 字符串:repleace,strip,split,reverse,upper,lower,join.....列表:append,pop,insert,remove,sort,count,index.....元组:index,count,__len__(),__dir__()字典:get,keys,values,pop,popitems,clear,update,items..... 23、lambda表达式格式以及应用场景? 表达式格式:lambda后面跟一个或多个参数,紧跟一个冒号,以后是一个表达式。冒号前是参数,冒号后是返回值。例如:lambda x : 2x应用场景:经常与一些内置函数相结合使用,比如说map(),filter(),sorted(),reduce()等 24、pass的作用? 1、空语句 do nothing2、保证格式完整3、保证语义完整 25、arg和*kwarg作用? 万能参数,解决了函数参数不固定的问题*arg:会把位置参数转化为tuple**kwarg:会把关键字参数转化为dict 26、is和==的区别? is:判断内存地址是否相等==:判断数值是否相等 27、简述Python的深浅拷贝以及应用场景? copy():浅copy,浅拷贝指仅仅拷贝数据集合的第一层数据deepcopy():深copy,深拷贝指拷贝数据集合的所有层 28、Python垃圾回收机制? python采用的是引用计数机制为主,标记-清除和分代收集(隔代回收、分代回收)两种机制为辅的策略 计数机制 Python的GC模块主要运用了引用计数来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除” 解决容器对象可能产生的循环引用的问题。通过分代回收以空间换取时间进一步提高垃圾回收的效率。 标记-清除: 标记-清除的出现打破了循环引用,也就是它只关注那些可能会产生循环引用的对象 缺点:该机制所带来的额外操作和需要回收的内存块成正比。 隔代回收 原理:将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”, 垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾, 就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量, 如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。 29、python的可变类型和不可变类型? 不可变类型(数字、字符串、元组、不可变集合)可变类型(列表、字典、可变集合) 30、求结果: v = dict.fromkeys(['k1','k2'],[]) v['k1'].append(666) print(v) v['k1'] = 777 print(v) 答案:{'k1':[666],'k2':[666]} {'k1':777,'k2':[666]} 解析:formkeys()默认参数为可变数据类型时有坑 31、求结果: def num(): return [lambda x: i*x for i in range(4)] print([m(2) for m in num()]) 答案:[6, 6, 6, 6] 解析: 问题的本质在与python中的属性查找规则,LEGB(local,enclousing,global,bulitin), 在上面的例子中,i就是在闭包作用域(enclousing),而Python的闭包是 迟绑定 , 这意味着闭包中用到的变量的值,是在内部函数被调用时查询得到的 所以:[lambda x: i*x for i in range(4)]打印出来是含有四个内存地址的列表,每个内存地址中的i 在在本内存中都没有被定义,而是通过闭包作用域中的i值,当for循环执行结束后,i的值等于3,所以 再执行[m(2) for m in num()]时,每个内存地址中的i值等于3,当x等于2时,打印出来的结果都是6, 从而得到结果[6, 6, 6, 6]。 32、列举常见的内置函数? map,filter,zip,len,bin,oct,hex,int,float,bool,sum,min,max,str,list,tuple,dict,range,next,hash,help,id..... 33、filter、map、reduce的作用? filter(function,iterable)过滤函数map(function,iterable)循环函数reduce(function, iterable)累积函数 34、一行代码实现9*9乘法表。 lis = ['%s*%s=%s'%(i,j,i*j) for i in range(1,10) for j in range(i,10)] 35、如何安装第三方模块?以及用过哪些第三方模块? pip3 imstall 模块名django,Matplotlib,Tornado,PyGame 36、至少列举8个常用模块都有那些? os,sys,time,random,re,hashlib,logging,json,pickle.... 37、re的match和search区别? match:从字符串的开头位置匹配,必须以此为开头search:从开头开始查,找到符合的就返回结果 38、什么是正则的贪婪匹配? 正则表达式一般趋向于最大长度匹配 39、求结果: a. [ i % 2 for i in range(10) ] ===>[0,1,0,1,0,1,0,1,0,1]b. ( i % 2 for i in range(10) )===>返回一个生成器的内存地址 40、求结果: a. 1 or 2 =========>1b. 1 and 2 ========>2c. 1 < (2==2)======>falsed. 1 < 2 == 2======>ture 41、def func(a,b=[]) 这种写法有什么坑? def func(a,b=[]): b.append(a) print(b) 函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list, 第二次执行还是用第一次执行的时候实例化的地址存储,以后每次实例化都是 42、如何实现 "1,2,3" 变成 ['1','2','3'] ? a = "1,2,3"li = a.split(',') 43、如何实现[‘1’,’2’,’3’]变成[1,2,3] ? li = ['1','2','3']lis = list(map(lambda x:int(x) li)) 44、比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别? a = [1,2,3]正常的列表b = [(1),(2),(3)] 虽然列表的每个元素加上了括号,但是当括号内只有一个元素并且没有逗号时,其数据类型是元素本身的数据类型b = [(1,),(2,),(3,)]列表中的元素类型都是元组类型 45、如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ? li = [x*x for x in range(1,11)] 46、一行代码实现删除列表中重复的值 ? li = [1, 1, 1, 23, 3, 4, 4]new_li = list(set(li))new_li.sort(key=li.index) 47、如何在函数中设置一个全局变量 ? 使用python的内置语法 globals 全局变量 48、logging模块的作用?以及应用场景? logging模块的作用:1、程序调试2、了解软件程序运行情况,是否正常3、软件程序运行故障分析与问题定位应用场景:网站的运维工作,程序实时监控 49、请用代码简答实现stack 。 def Stack(object): def __init__(self): self.stack = [] def push(self,value): # 进栈 self.stack.append(value) def pop(self): # 出栈 if self.stack: self.stack.pop() else: raise LookupError('stack is empty!') def is_empty(self): # 查看stack是否为空 reture bool(self.stack) def top(self): # 取出stack中最新的值 return self.stack[-1] 50、常用字符串格式化哪几种? 1、%s %d2、format格式化输出3、print(f'内容{变量名}') 51、简述 生成器、迭代器、可迭代对象 以及应用场景? 生成器:在 Python 中,一边循环一边计算的机制,称为 生成器(generator), 通过next()取值,两种表现形式1、将列表生成式的[]改为()2、含有yield关键字的函数 应用场景:优化代码,节省内存 迭代器:是访问集合元素的一种方式。迭代器同时实现了__iter__和__next__方法 可迭代对象:只要实现了__iter__方法的对象就是可迭代对象 52、用Python实现一个二分查找的函数。 lis = [0, 1, 3, 4, 5, 6, 7, 9, 10, 11,12,16,17] def two_find(x, lis, start=0, end=None): if end == None:end = len(lis) - 1 num = (end - start) // 2 + start if end > start: if lis[num] > x: return two_find(x, lis, start=start, end=num) elif lis[num] < x: return two_find(x, lis, start=num + 1, end=end) elif lis[num] == x: return num elif lis[end] == x:return end else:return None print(two_find(17, lis)) 53、谈谈你对闭包的理解? 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。 54、os和sys模块的作用? os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。 55、如何生成一个随机数? import random def rdm(n): lis = [] for i in range(n): n = random.randint(1,9) lis.append(str(n)) s = ''.join(lis) return int(s) 56、如何使用python删除一个文件? import osos.remove(r'path') 57、谈谈你对面向对象的理解? 面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。对象是特征和技能的结合,其中特征和技能分别对应对象的数据属性和方法属性。优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。 58、Python面向对象中的继承有什么特点? 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。 区别于在类中调用普通函数时并不需要带上self参数 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。 (先在本类中查找调用的方法,找不到才去基类中找)。 59、面向对象深度优先和广度优先是什么? Python的类可以继承多个类,那么其寻找类方法的方式有两种: 当类是经典类时(主要在python2版本中的没有主动继承object的类),多继承情况下,会按照深度优先方式查找 当类是新式类时(python3版本中的所有类和python2中主动继承object的类),多继承情况下,会按照广度优先方式查找 简单点说就是:经典类是纵向查找,新式类是横向查找 60、面向对象中super的作用? 1、super在面向对象继承类中代指父类,书写方法super(类名,self).属性或者方法或super().属性或者方法 2、super方法可以增加类之间调用的灵活性,当父类名发生变化时不必修改 3、super方法在类的多继承时可以简化代码,避免代码冗余 4、super机制里可以保证公共父类仅被执行一次,执行的顺序遵循MRO,广度优先查询方法 61、是否使用过functools中的函数?其作用是什么? functools用于高阶函数:指那些作用于函数或者返回其他函数的函数。通常情况下,只要是 可以被当做函数调用的对象就是这个模块的目标。 62、列举面向对象中带双下划线的特殊方法,如:new、init __new__:构造方法,创建一个对象,实例化时第一个被执行,返回一个创建好的对象及__init__(self)的self, 只有继承了object的类才会有这个方法 __init__:初始化方法,__init__在__new__的基础上完成一些其它初始化的动作,__init__没有返回值 63、如何判断是函数还是方法? 函数和方法都封装了一些独立的功能,如果在类中定义的函数那就是方法(对象或者类名点方法名调用), 否则就是函数(函数名()直接调用) 64、静态方法和类方法区别? 静态方法:是既不是用类中的属性又不使用对象中的属性,由类或者对象调用的方法,依赖python装饰器@staticmethod来实现 类方法:只使用类中的静态变量,一般都是由类调用,依赖python装饰器@classmethod来实现 65、列举面向对象中的特殊成员以及应用场景? __call__:对象的构造方法,对象加上(),可以触发这个类的__call__方法。 __len__:内置函数的len函数是依赖类中的__len__方法 __eq__:判断值是否相等的时候依赖__eq__方法 __hash__:判断hash值是否相等的时候依赖__hash__方法(拓展:set的去重机制其实就是根据__hash__和__eq__方法实现的) __str__:和str() print() %s 都是息息相关的,返回值一定是字符串类型 __repr__:和 repr() %r都是息息相关的,在没有__str__方法时,__repr__可以完全取代__str__。 __del__ 析构方法,对应着一个对象的删除之前执行的内容 66、1、2、3、4、5 能组成多少个互不相同且无重复的三位数 count = 0 for i in range(1,6): for j in range(1,6): for k in range(1,6): if (i != j) and (i != k) and (j != k): count += 1 if count % 6: print(f'{i}{j}{k}', end='|') else: print(f'{i}{j}{k}') print(count) 67、什么是反射?以及应用场景? 定义:通过用字符串数据类型的变量名来访问这个变量的值,在python面向对象中的反射,通过字符串的形式操作对象相关的属性或方法. 应用场景:用于处理通过用户输入,文件读取,或者网络传输所得到的字符串形式的指令来完成对应的操作 68、metaclass作用?以及应用场景? metaclass,直译为元类,简单的解释就是:当我们定义了类以后,就可以根据这个类创建出实例, 所以:先定义类,然后创建实例。但是如果我们想创建出类呢?那就必须根据metaclass创建出类, 所以:先定义metaclass,然后创建类。换句话说,你可以把类看成是metaclass创建出来的“实例” 69、用尽量多的方法实现单例模式。 1、基于__new__()方法 class Person: def __new__(cls, *args, **kwargs): if not hasattr(cls,cls._instance): # cls._instance = object.__new__(cls) cls._instance = super().__new__(cls) return cls._instance 2、基于模块导入方式,现在一个py文件中写好一个类,实例化一个对象。以后用这个类直接导入这个模块就是单例模式。 3、基于装饰器方法实现 def singleton(cls, *args, **kwargs): instance_dic = {} def inner(*args, **kwargs): if cls not in instance_dic: instance_dic['cls'] = cls(*args, **kwargs) return instance_dic['cls'] return inner @singleton class Person: pass 70、装饰器的写法以及应用场景。 装饰器的写法: def wrapper(func): def inner(*args,**kwargs): '被装饰之前的操作' ret = func(*args,**kwargs) '被装饰之后的操作' return ret return inner 装饰器的应用场景: 比如注册登录、插入日志,性能测试,事务处理,缓存等等场景 71、异常处理写法以及如何主动跑出异常(应用场景) 异常处理的常规写法: try: 执行的主体函数 except Exception as e: print(str(e)) 主动抛出异常: raise TypeError('出现了不可思议的异常')#TypeError可以是任意的错误类型 72、什么是面向对象的mro MRO(Method Resolution Order 方法解析顺序)是面向对象中用于查询类的多继承的继承顺序的方法, 它是基于算法来实现的,不同的算法实现的MRO的顺序不同 73、isinstance作用以及应用场景? isinstance作用是来判断一个对象是否是一个已知的类型 74、写代码并实现: Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1] 代码实现 def func(li,target): try: for i in range(0,len(li)): num = target-li[i] if num in li: return [i,li.index(num)] except:print('li类型为数组类型,内的元素需是整型,target也为整型,请检查') else:return None 75、json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型? 1、可以处理的数据类型是 string、int、list、tuple、dict、bool、null 2、定制支持datetime类型 --------------------------官方文档的memo----------------------------------------------- >>> import json >>> class ComplexEncoder(json.JSONEncoder): ... def default(self, obj): ... if isinstance(obj, complex): ... return [obj.real, obj.imag] ... return json.JSONEncoder.default(self, obj) ... >>> dumps(2 + 1j, cls=ComplexEncoder) '[2.0, 1.0]' >>> ComplexEncoder().encode(2 + 1j) '[2.0, 1.0]' >>> list(ComplexEncoder().iterencode(2 + 1j)) ['[', '2.0', ', ', '1.0', ']'] ---------------------------------------------------------------------------------------- import json import datetime ret = datetime.datetime.now() class CJsonEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.date): return obj.strftime('%Y-%m-%d %H:%M:%S') else: return json.JSONEncoder.default(self, obj) print(json.dumps(ret,cls=CJsonEncoder)) 76、json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办? 在序列化是将json.dumps中的默认参数ensure_ascii改为False就可以保留中文了 json.dumps(obj,ensure_ascii=False) 77、什么是断言?应用场景? assert 条件,'自定义错误提示(可有可无)' 例:assert 1 == 0,'这是一个低级的错误' 合约式设计是断言的经典应用,在一个正确的程序里,所有的前置条件和后置条件都将得到处理。 78、使用代码实现查看列举目录下的所有文件。 方法一:递归处理 import os url = r'C:\Users\Mr.Wang\PycharmProjects\untitled\前段学习' def check_file(url,li = []): if os.path.isdir(url): file_list = os.listdir(url) for ret in file_list: base_url = os.path.join(url,ret) if os.path.isfile(base_url): li.append(ret) else: check_file(base_url) return li else:return os.path.basename(url) 方法二:堆栈的思想处理 import os url = r'C:\Users\Mr.Wang\PycharmProjects\untitled\python基础' lis = [url] while lis: url = lis.pop() ret_list = os.listdir(url) for name in ret_list: abs_path = os.path.join(url,name) if os.path.isdir(abs_path): lis.append(abs_path) else:print(name) 79、简述 yield和yield from关键字。 yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器当你调用这个函数的时候, 函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象,当你使用for进行迭代的时候, 函数中的代码才会执行 yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来, 这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中添加大量处理异常的样板代码。 有了这个结构,协程可以通过以前不可能的方式委托职责。 更多解析详见:http://blog.gusibi.com/post/python-coroutine-yield-from/ 80、代码实现六位随机验证码 import random s = '' for i in range(6): num = random.randint(0,9) alpha1 = chr(random.randint(65,90)) alpha2 = chr(random.randint(97,122)) ret = random.choice([num,alpha1,alpha2]) s += str(ret) print(s) 81、代码实现随机发红包功能 import random def red_packge(money,num): li = random.sample(range(1,money*100),num-1) li.extend([0,money*100]) li.sort() return [(li[index+1]-li[index])/100 for index in range(num)] ret = red_packge(100,10) print(ret) --------------------------生成器版------------------------------------------- import random def red_packge(money,num): li = random.sample(range(1,money*100),num-1) li.extend([0,money*100]) li.sort() for index in range(num): yield (li[index+1]-li[index])/100 ret = red_packge(100,10) print(ret) ---------------------------九九八十一难后继续闯关东:------------------------------- 1、请尽可能列举python列表的成员方法,并给出列表操作的答案: (1) a=[1, 2, 3, 4, 5], a[::2]=? a[-2:]=? a[::2]=[1,3,5], a[-2:] = [4,5] (2)一行代码实现对列表a中的偶数位置的元素进行加3后求和? sum([i+3 for i in a[::2]]) (3)将列表a的元素顺序打乱,再对a进行排序得到列表b,然后把a和b按元素顺序构造一个字典d。 import random random.shuffle(a) b=a.sort() d={} for i in range(len(a)):d[a[i]] = b[i] 2、 Python自省 自省就是面向对象的语言所写的程序在运行时,就能知道对象的类型。也就是程序运行时能够获得对象的类型。比如type(),dir(),getattr(),hasattr(),isinstance()。 3、Python是如何进行内存管理的? 从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一、对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。 引用计数增加的情况: 1,一个对象分配一个新名称 2,将其放入一个容器中(如列表、元组或字典) 引用计数减少的情况: 1,使用del语句对对象别名显示的销毁 2,引用超出作用域或被重新赋值 sys.getrefcount( )函数可以获得对象的当前引用计数 多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。 二、垃圾回收 1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。 2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。 三、内存池机制 Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。 1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。 2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。 3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。 4、介绍一下except的用法和作用? try…except…except…[else…][finally…] -- 执行try下的语句,如果引发异常,则执行过程会跳到except语句。对每个except分支顺序尝试执行,如果引发的异常与except中的异常组匹配,执行相应的语句。如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。 -- try下的语句正常执行,则执行else块代码。如果发生异常,就不会执行 -- 如果存在finally语句,最后总是会执行。 5、如何用Python来进行查询和替换一个文本字符串? 可以使用re模块中的sub()函数或者subn()函数来进行查询和替换,比replace的功能更强大!!! 格式:sub(replacement, string[,count=0])(replacement是被替换成的文本,string是需要被替换的文本,count是一个可选参数,指最大被替换的数量) import re p=re.compile("blue|white|red") print(p.sub('colour','blue socks and red shoes')) print(p.sub('colour','blue socks and red shoes',count=1)) subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量 6、有没有一个工具可以帮助查找python的bug和进行静态的代码分析? PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告 Pylint是另外一个工具可以进行codingstandard检查

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

BAT等公司必问的8道Java经典面试题,你都会了吗?

工作多年以及在面试中,我经常能体会到,有些面试者确实是认真努力工作,但坦白说表现出的能力水平却不足以通过面试,通常是两方面原因: 1、“知其然不知其所以然”。做了多年技术,开发了很多业务应用,但似乎并未思考过种种技术选择背后的逻辑。坦白说,我并不放心把具有一定深度的任务交给他。 2、知识碎片化,不成系统。在面试中,面试者似乎无法完整、清晰地描述自己所开发的系统,或者使用的相关技术。平时可能埋头苦干,或者过于死磕某个实现细节,并没有抬头审视这些技术。 前人已经掉过的坑,后来的同学就别再“前仆后继”了! Java基础 1、谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗? 考点分析: 对于这类笼统的问题,你需要尽量表现出自己的思维深入并系统化,Java 知识理解得也比较全面,一定要避免让面试官觉得你是个“知其然不知其所以然”的人。毕竟明白基本组成和机制,是日常工作中进行问题诊断或者性能调优等很多事情的基础,相信没有招聘方会不喜欢“热爱学习和思考”的面试者。 回归正题,对于 Java 平台的理解,可以从很多方面简明扼要地谈一下,例如:Java 语言特性,包括泛型、Lambda 等语言特性;基础类库,包括集合、IO/NIO、网络、并发、安全等基础类库。对于我们日常工作应用较多的类库,面试前可以系统化总结一下,有助于临场发挥。 下图是我总结的一个相对宽泛的蓝图供你参考。 2、请对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别? 考点分析: 分析 Exception 和 Error 的区别,是从概念角度考察了 Java 处理机制。总的来说,还处于理解的层面,面试者只要阐述清楚就好了。 我们在日常编程中,如何处理好异常是比较考验功底的,我觉得需要掌握两个方面。 第一,理解 Throwable、Exception、Error 的设计和分类。比如,掌握那些应用最为广泛的子类,以及如何自定义异常等。 很多面试官会进一步追问一些细节,比如,你了解哪些 Error、Exception 或者 RuntimeException?我画了一个简单的类图,并列出来典型例子,可以给你作为参考,至少做到基本心里有数。 第二,理解 Java 语言中操作 Throwable 的元素和实践。掌握最基本的语法是必须的,如 try-catch-finally 块,throw、throws 关键字等。与此同时,也要懂得如何处理典型场景。 3、谈谈 Java 反射机制,动态代理是基于什么原理? 考点分析: 这个题目给我的第一印象是稍微有点诱导的嫌疑,可能会下意识地以为动态代理就是利用反射机制实现的,这么说也不算错但稍微有些不全面。功能才是目的,实现的方法有很多。 总的来说,这道题目考察的是 Java 语言的另外一种基础机制: 反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息。而动态代理,则是延伸出来的一种广泛应用于产品开发中的技术,很多繁琐的重复编程,都可以被动态代理机制优雅地解决。 从考察知识点的角度,这道题涉及的知识点比较庞杂,所以面试官能够扩展或者深挖的内容非常多,比如: 考察你对反射机制的了解和掌握程度。 动态代理解决了什么问题,在你业务系统中的应用场景是什么? JDK 动态代理在设计和实现上与 cglib 等方式有什么不同,进而如何取舍? 4、Java 提供了哪些 IO 方式? NIO 如何实现多路复用? 在实际面试中,从传统 IO 到 NIO、NIO 2,其中有很多地方可以扩展开来,考察点涉及方方面面,比如: 基础 API 功能与设计, InputStream/OutputStream 和 Reader/Writer 的关系和区别。 NIO、NIO 2 的基本组成。 给定场景,分别用不同模型实现,分析 BIO、NIO 等模式的设计和实现原理。 NIO 提供的高性能数据操作方式是基于什么原理,如何使用? 或者,从开发者的角度来看,你觉得 NIO 自身实现存在哪些问题?有什么改进的想法吗? IO 的内容比较多,专栏一讲很难能够说清楚。IO 不仅仅是多路复用,NIO 2 也不仅仅是异步 IO,尤其是数据操作部分,会在专栏下一讲详细分析。 5、如何保证容器是线程安全的?ConcurrentHashMap 如何实现高效地线程安全? 典型回答: Java 提供了不同层面的线程安全支持。在传统集合框架内部,除了 Hashtable 等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),我们可以调用 Collections 工具类提供的包装方法,来获取一个同步的包装容器(如 Collections.synchronizedMap),但是它们都是利用非常粗粒度的同步方式,在高并发情况下,性能比较低下。 另外,更加普遍的选择是利用并发包提供的线程安全容器类,它提供了: 各种并发容器,比如 ConcurrentHashMap、CopyOnWriteArrayList。 各种线程安全队列(Queue/Deque),如 ArrayBlockingQueue、SynchronousQueue。 各种有序容器的线程安全版本等。 具体保证线程安全的方式,包括有从简单的 synchronize 方式,到基于更加精细化的,比如基于分离锁实现的 ConcurrentHashMap 等并发实现等。具体选择要看开发的场景需求,总体来说,并发包内提供的容器通用场景,远优于早期的简单同步实现。 6、谈谈接口和抽象类有什么区别? 考点分析: 这是个非常高频的 Java 面向对象基础问题,看起来非常简单的问题,如果面试官稍微深入一些,你会发现很多有意思的地方,可以从不同角度全面地考察你对基本机制的理解和掌握。 比如: 对于 Java 的基本元素的语法是否理解准确。能否定义出语法基本正确的接口、抽象类或者相关继承实现,涉及重载(Overload)、重写(Override)更是有各种不同的题目。 在软件设计开发中妥善地使用接口和抽象类。你至少知道典型应用场景,掌握基础类库重要接口的使用;掌握设计方法,能够在 review 代码的时候看出明显的不利于未来维护的设计。 掌握 Java 语言特性演进。现在非常多的框架已经是基于 Java 8,并逐渐支持更新版本,掌握相关语法,理解设计目的是很有必要的。 Java进阶 7、synchronized 底层如何实现?什么是锁的升级、降级? 考点分析: 今天的问题主要是考察你对 Java 内置锁实现的掌握,也是并发的经典题目。我在前面给出的典型回答,涵盖了一些基本概念。如果基础不牢,有些概念理解起来就比较晦涩,我建议还是尽量理解和掌握,即使有不懂的也不用担心,在后续学习中还会逐步加深认识。 我个人认为,能够基础性地理解这些概念和机制,其实对于大多数并发编程已经足够了,毕竟大部分工程师未必会进行更底层、更基础的研发,很多时候解决的是知道与否,真正的提高还要靠实践踩坑。 后面我会进一步分析: 从源码层面,稍微展开一些 synchronized 的底层实现,并补充一些上面答案中欠缺的细节,有同学反馈这部分容易被问到。如果你对 Java 底层源码有兴趣,但还没有找到入手点,这里可以成为一个切入点。 理解并发包中 java.util.concurrent.lock 提供的其他锁实现,毕竟 Java 可不是只有 ReentrantLock 一种显式的锁类型,我会结合代码分析其使用。 8、synchronized 和 ReentrantLock 有什么区别?有人说 synchronized 最慢,这话靠谱吗? 考点分析: 今天的题目是考察并发编程的常见基础题,我给出的典型回答算是一个相对全面的总结。 对于并发编程,不同公司或者面试官面试风格也不一样,有个别大厂喜欢一直追问你相关机制的扩展或者底层,有的喜欢从实用角度出发,所以你在准备并发编程方面需要一定的耐心。 我认为,锁作为并发的基础工具之一,你至少需要掌握: 理解什么是线程安全。 synchronized、ReentrantLock 等机制的基本使用与案例。 更近一步,你还需要: 掌握 synchronized、ReentrantLock 底层实现;理解锁膨胀、降级;理解偏斜锁、自旋锁、轻量级锁、重量级锁等概念。 掌握并发包中 java.util.concurrent.lock 各种不同实现和案例分析。 典型回答: synchronized 是 Java 内建的同步机制,所以也有人称其为 Intrinsic Locking,它提供了互斥的语义和可见性,当一个线程已经获取当前锁时,其他试图获取的线程只能等待或者阻塞在那里。 在 Java 5 以前,synchronized 是仅有的同步手段,在代码中, synchronized 可以用来修饰方法,也可以使用在特定的代码块儿上,本质上 synchronized 方法等同于把方法全部语句用 synchronized 块包起来。 ReentrantLock,通常翻译为再入锁,是 Java 5 提供的锁实现,它的语义和 synchronized 基本相同。再入锁通过代码直接调用 lock() 方法获取,代码书写也更加灵活。与此同时,ReentrantLock 提供了很多实用的方法,能够实现很多 synchronized 无法做到的细节控制,比如可以控制 fairness,也就是公平性,或者利用定义条件等。但是,编码中也需要注意,必须要明确调用 unlock() 方法释放,不然就会一直持有该锁。 synchronized 和 ReentrantLock 的性能不能一概而论,早期版本 synchronized 在很多场景下性能相差较大,在后续版本进行了较多改进,在低竞争场景中表现可能优于 ReentrantLock。 迎工作一到五年的Java程序员朋友们加入Java架构开发:744677563 本群提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导

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

浏览器事件循环:从一道笔试题到实际业务中的批量更新

这个输出顺序很多人能背出来,但把它放到一个真实的列表渲染场景里,问题就不是背顺序那么简单了。前段时间改一个表格组件,用户连续勾选几百行,每勾选一次就触发一次父组件更新,父组件更新又反过来导致每个子组件重新计算选中状态。代码里用 Promise 做了防抖,结果防抖还没生效,界面已经卡住了。调试时发现 Promise 的微任务一直插在渲染之前执行,宏任务里的渲染帧被无限延后。事件循环的规则本身不复杂,难的是把它和浏览器渲染、微任务队列饥饿、任务拆分这些实际问题对上号。下面从事件循环的调度机制出发,看几个真实场景里容易踩的坑。

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册