精华内容
下载资源
问答
  • 我们在日常生活常能听到工程这个词,像桥梁工程、道路工程、南水北调工程等等。 工程说简单点就是各个行业的从业人员通过总结规律或者方法,以最短的时间和人力、物力来做出高效可靠的东西。我们也就能理解桥梁工程...

    1、背景

    1.1 软件是一个工程

            我们在日常生活常能听到工程这个词,像桥梁工程、道路工程、南水北调工程等等。

            工程说简单点就是各个行业的从业人员通过总结规律或者方法,以最短的时间和人力、物力来做出高效可靠的东西。我们也就能理解桥梁工程,其实就是人们通过经验的总结和各种研究得出来的、用来修建桥梁时所采用的高效的方法,当然这种方法是可复用的。我们将这种作工程的思想应用到软件上,于是就产生了一软件工程。

            软件工程:为了能够实现软件的流水线式生产,在设计和构建软件时能够有一种规范和工程化的方法,人们便提出了软件工程概念。

    1.2 完成一个java项目,需要做的工作

    (1)分析项目要做什么,知道项目有哪些组成部分。

    (2)设计项目,通过哪些步骤,使用哪些技术.需要多少人,多长的时间.

    (3)组建团队,招人, 购置设备,服务器, 软件,笔记本..

    (4)开发人员写代码。开发人员需要测试自己写代码。重复多次的工作.

    (5)测试人员,测试项目功能是否符合要求.测试开发人员提交代码-如果测试有问题-需要开发人员修改--再提交代码给测试--测试人员再测试代码-如果还有问题-再交给开发人员-开发人员再提交-再测试直到-测试代码通过.  (多次重复的工作.

    1.3 在没有maven之前,开发一个java项目会遇到的问题

    (1)很多模块,模块之间有关系, 手工管理关系,比较繁琐

    (2)需要很多第三方功能,需要很多jar文件,需要手工从网络中获取各个jar

    (3)需要管理jar的版本, 你需要的是mysgl .5.1.5.jar 那不能给一个mysql.4.0.jar

    (4)管理jar文件之间的依赖, 你的项目要使用a.jar需要使用b.jar里面的类.必须首先获取到b.jar才可以,然后才能使用a.jar.

    说明:a.jar需要b:jar这个关系叫做依赖, 或者你的项目中要使用mysql的驱动, 也可以叫做项目依赖mysql驱动。或者比如 a.class使用b.class, a依赖b类

    1.4 为了改进项目的开发和管理,maven应运而生

    maven可实现以下作用:

    (1)maven可以管理jar文件

    (2)自动下载jar和他的文档,源代码

    (3)管理jar直接的依赖, a.jar需要b.jar , maven会自动下载b.jar

    (4)管理你需要的jar版本

    (5)编译程序,把Java编译为class  (构建)

    (6)测试代码是否正确.  (构建)

    (7)将你编写的类打包,形成jar文件,或者war文件  (构建)

    (8)帮你部署项目  (构建)

    总结:maven帮忙完成费时费力又麻烦的重复性工作,程序员就可以专心写功能型代码了。

    2、maven 构建  项目的构建       

       构建是面向过程的,就是一些步骤,完成项目代码的编译,测试,运行,打包,部署等等.maven支持的构建包括有:

    (1)清理, 把之前项目编译的东西删除掉,为新的编译代码做准备。

    (2)编译, 把程序源代码编译为执行代码, 批量将.Java文件变成.class文件, maven可以同时把成千上百的.java文件编译为.class.(传统的javac一次只能编译一个文件)

    编译方法:maven工程所在的根目录下,启动cmd(直接windows文件目录那里输入cmd),然后输入命令 mvn compile

    (3)测试, maven可以执行测试程序代码,验证你的功能是否正确。maven同时批量执行多个测试代码,同时测试很多功能(传统的测试一次只能测试一个类,那要测试多久才能测试完啊)

    (4)报告, 生成测试结果的文件, 告知测试是否通过。

    (5)打包, 把你的项目中所有的class文件,配置文件等所有资源放到一个压缩文件中。这个压缩文件就是项目的结果文件,通常Java程序,压缩文件是Jar扩展名的.对于web应用,压缩文件扩展名是.war

    (6)安装, 把(5)中生成的文件jar, war安装到本机仓库中

    (7)部署, 把程序安装好可以执行。  (一般不用maven部署)

    说明:开发中主要做1-6,不用maven部署,maven部署更复杂

    3、maven的安装和配置

    (1)从maven的官网下载maven的安装包apache-maven-x.x.x-bin.zip

    (2)解压安装包,解压到一个目录,非中文目录.

                子目录bin :里面有maven执行程序,主要是mvn.cmd

                子目录conf :里面有maven工具本身的配置文件settings .xml

    (3)配置环境变量在系统的环境变量中,指定一个M2_HOME的名称, 指定它的值是maven工具安装目录,(bin之前的目录)

    M2 HOME=安装目录  。再把M2_HOME加入到path之中,在所有路径之前加入%M2_HOME%\bin;4)验证,新的命令行中,执行mvn-v

    4、maven 核心概念 (maven中的术语)

    (1)POM    Project Object Module   项目对象模型

        一个文件名,名称是pom.xml,该文件控制maven构建项目的过程,管理jar依赖

    (2)约定的目录结构

        maven项目的目录和文件位置都是有规定的,不能随便乱放

    (3)坐标(gav)

        Maven把任何一个插件都作为仓库中的一个项目进行管理,用一组(三个)向量组成的坐标来表示。坐标在仓库中可以唯一定位一个Maven项目。

    groupld:组织名,通常是公司或组织域名倒序+项目名

    artifactld:模块名,通常是工程名

    version:版本号

           需要特别指出的是,项目在仓库中的位置是由坐标来决定的、groupld, artifactid和version决定项目在仓库中的路径(groupId对应的包路径/模块名/版本号/jar包), artifactid和version决定jar包的名称。

        进入POM.xml文件,对坐标进行配置。

    (4)依赖管理

        用于管理项目中可以使用的jar文件

    (5)仓库管理(了解即可)

        资源存放的位置

    (6)生命周期(了解即可)

         maven构建项目的过程,就是生命周期。即完成清理、编译,测试,运行、打包等

    (7)插件和目标(了解即可)

        执行maven构建的相关命令时,比如清理,编译、打包等命令,实际是插件在运作。插件就是Maven的功能类。

    (8)继承

         和java继承类似,由父及子

    (9)聚合

            将多个项目汇总到一起

    4.1、maven工程约定的目录结构

    每一个maven项目在磁盘中都是一个文件夹(就相当于是IDEA项目的文件夹)

    JAVA工程名

    src
    main
    java各种包程序的包和包中的java文件
    resourcesjava程序需要的配置文件
    test放置测试程序的代码和配置文件(如果要求测试,允许没有测试文件)
    java各种包测试程序要使用的包和包中的java文件
    resources测试java程序需要的配置文件
    pom.xml maven的核心文件(maven启动后就通过这个文件了解该做什么)

    target

    (maven自动生成的

    结果目录)

    当对src中的java文件进行编译以后,maven自动生成这个文件夹用于存放编译后的class文件

    4.2 编译方法

         进入maven工程的根目录(pom.xml文件所在的位置),启动cmd(直接windows文件目录那里输入cmd),然后输入命令 mvn compile。就会编译main中的所有java文件,并自动在根目录新建一个target文件夹,将编译好的.class文件放入此文件夹。第一次编译,maven会下载一堆插件。

    疑问1 第一次执行时,为什么要下载那些插件

         maven工具执行的操作是通过很多特定功能的插件(java类--jar文件)来完成的,因此需要网上下载相关插件。

    疑问2 下载的插件存放到哪里了.

    默认仓库(本机仓库) :C:\Users\ (登录操作系统的用户名) Administrator\.m2\repository

    修改本地仓库方法(如果不想放在c盘):

          进入maven安装目录/conf/settings.xml(为了安全,先备份),然后进入settings.xml,找到<localRepository>xxx</localRepository>标签,将标签挪到注释外面,将里面的值改成新目录地址(比如F:/apache-maven-3.6.3)即可,注意,文件里面是 \ ,但是maven标签里面是 /,注意该斜杠方向。

    说明:maven默认是从中央仓库下载插件。中央仓库地址就在官网

    4.3 仓库

    (1)仓库是什么:仓库是存放东西的, 存放maven本身需要使用的jar包,和我们项目需要使用的jar包

          ① maven本身需要使用的插件(各种jar)

          ② 项目使用的Jar(第三方的工具),比如mysql,spring等jar包

    (2)仓库的分类

    ① 本地仓库,

           指个人计算机上的文件夹,存放各种jar

    ② 远程仓库, 在互联网上的,使用网络才能使用的仓库

        Ⅰ  中央仓库,最权威的,所有的开发人员都共享使用的一个集中的仓库(因此压力很大),中央仓库地址: https://repo.maven.apache.org

        Ⅱ  中央仓库的镜像:中央仓库的备份,在各大洲,重要的城市都是镜像.(为了缓解中央仓库的压力)

    说明:当我们项目需要jar包时,maven会先找各大洲maven的镜像,都找不到再去中央仓库

        Ⅲ 私服,在公司内部,局域网中使用的仓库,不对外使用。

    (3)仓库的使用

        开发人员需要使用mysql驱动,maven会首先查找本地仓库——>私服(如果有私服)——>各大洲的镜像——>中央仓库

    说明:maven全程自动完成。找到jar包以后,都会自动备份到私服和本地仓库。下次即可直接在本地访问。

    4.4 pom文件  Project Object Model

        pom文件即Project Object Model项目对象模型。Maven把一个项目的结构和内容抽象成一个模型,在xml文件中进行声明,以方便进行构建和描述, pom.xml是Maven的灵魂。所以, maven环境搭建好之后,所有的学习和操作都是关于pom.xml的。

    (1)pom.xml 概述

    modelVeisionMaven模型的版本
    坐标

    groupId

    (互联网唯一)

    组织id,一般是公司域名的倒写(互联网上域名唯一,所以倒写也唯一),格式可以为:
    1.域名倒写。 例如:com.baidu
    2.域名倒写+项目名。 例如:com.baidu.appolo
    groupId、artifactId、version三个元素生成了一个Maven项目的坐标,在互联网众多的Maven项目中可以唯一定位到某一个项目。坐标也决定将来项目在仓库中的路径及名称(groupId对应的包路径/模块名/版本号/jar包

    artifactId

    (公司内部唯一)

    项目名称,也是模块名称,对应groupId中项目的子项目
    version项目的版本号。如果项目还在开发中,是不稳定版本,通常在版本后代-SNAPSHOT
    version使用三位数字标识,例如1.1.0
    packaging(打包)项目打包的类型,可以是jar、war、rar、ear、pom,默认是jar
    dependencies和dependency(依赖)Maven的一个重要作用就是管理jar包,为了一个项目可以构建或运行,项目中不可避免的,会依赖很多其他的jar包,在Maven中,这些jar就被称,为依赖,使用标签dependency来配置。而这种依赖的配置正是通过坐标来定位的,由此我们也不难看出, maven把所有的jar包也都视为项目存在了。
    properties(配置属性)properties用来定义一些配置属性,例如project.build.sourceEncoding,可以设置为UTF-8,防止中文乱码,也可定义相关构建版本号,便于日后统一升级

    build(构建)

    配置插件

    build表示与构建相关的配置,例如设置编译插件的jdk版本。

    插件可以在自己的项目中设置,最常使用的是maven编译插件。设置项目使用的jdk版本时通过编译插件指定。pom.xml文件<build>中设置。

    (2)坐标:唯一值, 在互联网中唯一标识一个项目的

    <groupId>公司域名的倒写</groupId>

    <artifactId>自定义项目名称</artifactId>

    <version>自定版本号</version>

    (3)packaging 

    项目的打包类型:pom、jar(默认)、war(web应用)

    packing默认是jar类型,

    <packaging>pom</packaging>   --------->   父类型都为pom类型 (springcloud父项目)

    <packaging>jar</packaging>      --------->   内部调用或者是作服务使用

    <packaging>war</packaging>    --------->   需要部署的项目

    扩展:pom(没有java代码,也不执行java代码,只是为了聚合工程传递依赖)

    所有的父级项目的packaging都为pom,作为父级项目,还有一个重要的属性,那就是modules,通过modules标签将项目的所有子项目引用进来,在build父级项目时,会根据子模块的相互依赖关系整理一个build顺序,然后依次build

    <project>
      <packaging>pom</packaging>
       <modules>
          <module>abcd-business</module><!-- pom -->
          <module>abcd-sms</module><!-- pom -->
       </modules>
    </project>

    各个module里面依赖的项目中,子项目pom里面依赖的jar,和war最终都会被maven管理好。

    (4)依赖    相当于java代码中的import

        即在pom.xml文件中,添加 <dependencies>  标签(一般添加在properties标签下面),粘贴搜索到的插件的jar包的坐标。下面以mysql jar包,log(日志)jar包,junit单元测试jar包为例。添加成功后,会在本地仓库中,找到对应的文件夹

    <dependencies>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>

    </dependencies>

    扩展:IDEA中查看依赖关系小技巧,在IDEA中,进入pom.xml配置文件,右键—Diagrams  即可看到图表版依赖关系

    扩展:<dependencyManagement> 

          其通常用在项目中对顶层的父POM中,它能让其所有子项目引用一个依赖而不用显式的列出版本号。此外,dependencyManagement 只是声明依赖,并不实现引入(像极了接口),子项目如果不声明依赖,则不会从父项目中继承下来。

    提供作用:子模块继承之后,可以锁定版本+子module不用写groupId和version。 

    注意:子模块如果不写,就用父项目的版本,子模块写了,就用自己的版本

    <dependencyManagement>
        <dependencies>
          <!--spring boot 2.2.2-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>

    (5)properties 

    ① 设置Maven的常用属性

    进入pom.xml   找到properties标签

    <properties>

    <project.build. sourceEncoding>UTF-8</project. build. sourceEncoding> //<!--maven构建项目使用的是utf-8 ,避免中文的乱码-->

    <maven. compiler. source>1.8</maven. compiler.source> //<!--编译java代码使用的jdk版本-->

    <maven. compiler.target>1.8</maven. compiler.target> //<!--你的java项目应该运行在什么样的idk版本-->

    </properties>

    一般应用场景:一般在父项目中写好常用版本号属性,就可以对子项目进行统一管理(需要子项目通过parent标签引入该父项目)

    ② Maven的全局变量设置

    • 自定义属性

        Ⅰ  在<properties>通过自定义标签声明变量(标签名就是变量名)

        Ⅱ  在pom.xml文件中的其他位置,使用${标签名}使用变量的值

    说明:自定义全局变量一般是定义,依赖的版本号,当你的项目中要使用多个相同的版本号,先使用全局变量,定义,再使用${标签名}使用属性值。

    exp:spring框架中,很多依赖的jar包都是同一个版本号,如果修改的话,一个一个改很麻烦,改掉了还会导致项目不成功。因此可以在<properties>中自定义属性,然后在<dependency>中使用这个自定义属性

    <properties>   //在properties标签中自定义<spring.version>属性

    ....

        <spring.version>5.2.0</spring.version>

    </properties>

    <dependency>  //在依赖中,直接调用spring.version属性的值,这样改动properties中的属性值,就可以修改所有依赖里面的属性值

    ....

        <version>${spring.version}</verision>

    </dependency>

    特别说明:如果子项目的某个依赖中A的某个内部依赖B(A依赖B),父项目也用了B,子项目中的B版本和父项目的B版本不一致,可以在properties中专门写B的版本,这样父子项目B依赖都会统一。

    (6)build: maven在进行项目的构建时的配置信息,例如编译java代码使用的jdk版本

    扩展: 资源搜索方法

    手动搜索资源的地址:https://mvnrepository.com(ps:谷歌浏览器才能打开),使用groupId或者artifactId作为搜索条件

    4.5 Maven的生命周期,Maven的命令,Maven的插件

    (1)生命周期

       就是Maven构建项目的过程,即清理,编译,测试,报告,打包,安装,部署

    (2)Maven的命令

        Maven通过使用命令,完成项目的生命周期的执行(即通过命令完成清理,编译,测试,报告,打包,安装,部署)

    (3)Maven的插件

    Maven命令执行时,真正完成功能的是插件,插件就是一些jar文件,即一些类。

    (4)单元测试  junit,junit是一个专门测试的框架(工具),用于测试类中的方法

               junit测试内容:测试的是类中的方法,每一个方法都是独立测试的。 类中的方法 是测试的基本单位(单元)

               maven借助单元测试,批量的测试类中的大量方法是否符合预期的。

    • junit 使用步骤:

    Ⅰ  在pom.xml加入单元测试依赖。 仓库里面去搜,用使用人数最多的就是了

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>

    Ⅱ  在maven项目中的  src/test/java 目录下,创建测试程序。

    Ⅲ  推荐的创建类和方法的提示:

    ①  测试类的名称 是:Test + 测试的类名

    ②  测试的方法名称 是:test + 方法名称

    exp:

    @Test    //必须要用测试注解

    public class TestHelloMaven{

        public void testAdd(){

            方法体;

        }

    }

    说明:

    ①  其中testAdd叫做测试方法,它的定义规则  

    ②  方法是public的,必须的

    ③  方法没有返回值,必须的

    ④  方法名称是自定义的,推荐是test+方法名称

    ⑤  方法上方加入@Test注解

    exp:测试  某工程/src./main/java/com/Huhaha   下的 HelloMaven.java 中的 public void add()方法

    在 Maven工程的test目录创建测试类的测试文件,注意包名,路径一致    某工程/src/test/java/com/Huhaha 创建测试类

    将测试类按建议规则命名:TestHelloMaven.java

    package com.Huhaha;  //测试类的路径

    import org.junit.Assert;  //导入测试包

    import org.junit.Test;

    public  class TestHelloMaven{

        @Test

        public void testAdd(){

        HelloMaven hello = new HelloMaven(); //构造测试类HelloMaven的对象hello

        int res = hello.add(10,20);  //对象来调用将要测试的方法add()

    //assertEquals(期望值,实际值),测试的类方法,如果测试通过,即两个值相等证明正确的。不通过就抛异常

        Assert.assertEquals(30,res);

        }

    }

    4.6 Maven的命令

    (1)清理 mvn clean 。 

        清理之前编译时,生成的target目录。

    操作步骤:

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn clean

    (2)编译主程序文件  mvn compile

    编译main/java/目录下的java为class文件,同时把class拷贝到target/classes目录下面

    把main/resources目录下的所有文件,都拷贝到target/classes目录下

    操作步骤

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn compile

    (3)编译测试文件 mvn test-compile

        编译test./java/目录下的class文件,并将其拷贝到target\test-classes\包  下面

    操作步骤:

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn test-compile

    (4)测试 mvn test 测试(会生成一个目录surefire-reports,保存测试结果)

       执行测试文件

       执行mvn test的时候,会把前面的清理-编译主程序-编译测试程序 三个环节都执行一遍。测试完成可以直接在cmd中看到报告,同时在target/surefire-reports生成一个txt测试报告

    操作步骤:

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn test

    测试完成,会直接在cmde中看到报告。

    (5)打包主程序  mvn package

    编译、编译测试、测试、并且按照pom.xml配置(即以配置文件中的坐标为依据命名,建立类的相关性)把主程序=打包成jar包或war包,并存放在target目录下

    jar文件中只包含 src/main中的所有内容,不包含测试文件

    操作步骤:

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn package

    (6)安装 mvn install

        安装主程序(会把本工程打包,并且按照本工程坐标保存到本地仓库中)

        安装以后,公司的其他程序员都可以用这个jar包了(将打包好的jar包从target文件夹保存到本地仓库,并做好相关配置)

    存放路径:groupId对应的包路径/模块名/版本号/jar包)

    比如:repository/com/Huhaha(groupId)/ch01-maven(模块名)/1.0-SNAPSHOT(版本号)/ch01-maven-1.0-SNAPSHOT.jar

    操作步骤:

    打开cmd,转到项目根目录下(pom.xml)所在位置。  输入 mvn install

    特别注意:执行mvn命令某个步骤的时候,都会把这个命令之前的所有命令都执行一遍。比如执行mvn install,会把前面的1-5步骤都自动执行了

    4.7 配置插件

            Maven中,实际完成上面项目构建的都是Maven插件,插件可以在自己的项目中设置。最常使用的是maven编译插件。设置项目使用的jdk版本时通过编译插件指定。pom.xml文件<build>中设置。

    操作步骤:

    进入 pom.xml   一般在最后,开始写build标签

    <!--控制配置maven构建项目的参数设置,设置jdk的版本-->

    <build>

        <!--配置插件-->

        <plugins>      // 配置具体的多个插件

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugink/artifactId>  //  <!--插件的名称-->

                <version>3.8.1</version>  //  <!--插件的版本-->

                <configuration>  //   <!--配置插件的信息->

                        <source>1.8</source>      //告诉maven我们的写的代码是在jdk1.8上编译

                        <target>1.8</target>   //告诉Maven此项目在jdk1.8的运行环境上运行

                    </configuration>

                </plugin>

            </plugins>

    </build>

    特别说明:plugin标签的内容都是直接从Maven的官网上复制来的,不用专门记忆。(直接百度 Maven 插件 进Maven官网即可找到)

    5、IDEA中使用Maven  (重点)

    5.1 IDEA中配置Maven

    IDEA中内置了Maven,但内置Maven配置不方便。都用自己下载的Maven。因此首先要在IDEA中设置我们自己的Maven

    设置步骤:

    进入 IDEA的两个目录设置,一个是 File-Settings(对当前工程有效) ,另一个是 File-Other Settings-Settings for NewProject(对以后的新建工程有效)。两个目录配置方法一模一样(这里以当前工程设置为例)

    Step1:设置Maven安装目录

    File-Settings-Build,Execution,Deployment-build tools-Maven

    Step2:进入Build Tools —Maven—Runner

    vm Options: -DarchetypeCatalog=internal  

    说明:Maven项目创建时,Maven会自动联网去外网下载模板文件,而且比较大,又是外网。效率就非常低。加入这个代码,可以让Maven不下载模板文件,创建项目就会非常快。(有的IDEA版本加了这个会报错,删掉就是了)

    JRE:选择jdk的版本

    5.3 IDEA中创建基于Maven的项目

    5.3.1 IDEA中创建JavaSE项目

    Step1:选择一个空工程并命名maven-course (便于以后添加不同技术的模块)

    New-Project-EmptyProject

    step2:使用模板创建项目

    Project Seetings 点击+(Add)-New Module   在Module中 选择左侧的Maven

    选择好自己的jdk版本,然后打钩使用模板,接着选择quickstart模板(比较靠后的模板)。这个模板用于创建普通的java项目

    最后

    项目创建完成

    说明: quick-start模板没有recourses文件夹,需要我们手动创建

    创建步骤:

    step1:点击main文件夹,右键 New-Directory   将文件夹取名Recourses(此时还只是普通文件夹)

    step2: 把recourses文件夹变成项目配置文件夹

    recourses文件夹 右键 Mark Directory as Resources Root

    IDEA中的Maven模块说明:

    5.3.2  IDEA中创建JavaWeb项目

    step1:仿照上面JavaSe的创建方法 New-Module-Maven (只是和javaSE用的模板不同而已)

    选择:maven-archetype-webapp模板

    step2:取项目名字,设置项目坐标(仿照前面的javase步骤)

    创建完成。

    step3:补充缺失目录。main下面补充java(设置为Sources Root),补充recourses(设置为Resources root)

    step4:(如果要做测试):补充test目录,test目录下再补充java(设置为Test Sources Root),补充recourses(设置为Test Resources root)

    step5 加入serlvet和jsp的依赖(听说serlvet和jsp已过时)

    step6 写serlvet代码,或jsp代码

    step7 配置Tomcat服务器

    (1)选择Edit Configuration

    (2)选择 Local 

    (3)取名字,并选择好端口号,然后进入部署页面(deployment)

    (4)deployment页面部署项目

    (5)给项目取名

    (6)启动Tomcat

    (7)通过本机浏览器,去访问页面

    5.4 IDEA中导入别人的maven项目

        选择IDEA主窗口右上角的工程结构,选择"+" ,Import Module,选择Module文件夹所在的目录(整个maven项目所在的根目录),点击“ok”,再次向IDEA确认是导入Maven项目,finish

    然后,在依赖界面(dependency),选择导入项目的JDK版本

    6、依赖管理

    (1) 依赖的范围

           依赖范围在<dependency>标签下用<scope>的值标签标识,表示依赖使用的范围,也就是在Maven构建项目的哪些阶段有效。

    <scope>标签的值有:compile、test、provided、默认采用compile(不写<scope>标签,就是默认<scope>compile</scope>标签)

    compile

    所有阶段都有效

    test

    只在测试阶段有效

    provided

    编译,测试有效。不参与打包

    对主程序是否有效
    对测试程序是否有效
    是否参与打包
    是否参与部署
    说明项目生成的jar包或者war包里面有个lib文件,专门放依赖的jar包项目生成jar包或者war包里,没有lib文件夹。依赖的其他jar包只在编译、测试的时候使用,但最终都不参与项目的打包

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>

        <scope>test</scope>   //说明junit只在测试时,这个依赖有效
    </dependency>

    <dependency>

    <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>

        <scope>provided</scope>   // 说明编译、测试时会使用,但生成项目的时候,不用这个jar包(Tomcat服务器都会再带serlvet类)
    </dependency>

    (2)排除传递的某些依赖  <exclusions>

           在mavenB项目中引入mavenA项目依赖,A项目中又有多个A相关的依赖,通过依赖传递,会将mavenA中的jar包传递进来,如果B中不需要A中的某个依赖(jar包)就可以使用以下标签

    <exclusions>
        <exclusion>
        <groupId></groupId>
        <artifactId></artifactId>
        </exclusion>
    </exclusions>

    exp:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
      <exclusions>
        <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
        </exclusion>
      </exclusions>
    </dependency>

    简便方法:

    ① 进入图表版依赖关系

         在IDEA中,进入pom.xml配置文件,右键—Diagrams  即可看到图表版依赖关系

    ② 选中不想要的依赖,右键—exclude

        

    7、资源插件

    (1)背景

            没有使用resources的时候,Maven执行编译代码时,会把src/main/resources目录中的文件直接拷贝到target/classes目录中。对于在src/main/java目录下的非java文件,都不会处理,不会将其拷贝到target/classes目录中去。

            但实际开发中,比如使用mybatis框架的时候,我们需要把一些文件放在src/main/java中,而且在执行java程序时,需要用这些文件,即需要将其拷贝到target/classes目录中去。此时就需要在pom.xml中的<build>标签加入<resources>,告诉maven该怎么拷贝

    (2)配置方法

    <build>

        <resources>

            <resource>

                <directory>src/main/java</directory> <!--要拷贝文件所在的目录-->

                <includes>   <!--该目录下的后缀名为.properties,.xml文件都会被拷贝-->

                    <include>**/*.properties</include>  

                    <include>**/*.xml</include> 

                </includes>

                <filtering>false</filtering>  //  <false指不启用过滤器, *.property已经过滤后缀名了-->

             </resource>

        </resources>

    </build>

    展开全文
  • FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上...
  • Tomcat面试题+http面试题+Nginx面试题+常见面试题

    千次阅读 多人点赞 2019-12-12 15:04:43
    Tomcat面试题 1、Tomcat的缺省端口是多少?怎么修改? 答:缺省端口是8080,若要修改,可以进入Tomcat的安装目录下找到conf目录下的server.xml文件,找到该文件中的Connector字段中的port。 2、Tomcat有哪几种...

    Tomcat面试题

    1、Tomcat的缺省端口是多少?怎么修改?
    答:缺省端口是8080,若要修改,可以进入Tomcat的安装目录下找到conf目录下的server.xml文件,找到该文件中的Connector字段中的port。
    2、Tomcat有哪几种connector运行模式(服务的请求方式)?
    答:三种。修改它的运行模式需要在主配置文件中找到connector字段中的protocol进行修改

    这三种不同运行模式的性能相差很大,具体如下:
    
    BIO:阻塞型I/O操作,一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7或以下,默认使用这种方式。
    NIO:基于缓冲区,能提供非阻塞I/O操作,和传统的BIO相比,具备更好的抗并发性能;
    APR(Apache portable run-time libraries):简单理解,就是从操作系统级别解决异步IO问题,大幅度的提高服务器的处理和相应性能,也是Tomcat运行高并发的首选模式,在Linux中需要安装APR动态库才可以使用这种模式。
    

    3、如何避免用户在访问一个不存在的页面时,Tomcat将其详细版本信息返回给用户。
    答:解决办法就是将404状态码进行重定向,以便我们自定义返回的页面信息。
    4、优化tomcat可以从哪些方面着手?

    答:
    1、内存优化;
    2、线程池的优化
    3、禁用DNS查询;
    4、开启日志切割功能;
    5、关闭404错误返回的版本信息;
    

    ————————————————————————————————————————————————————————————————————————————————————————————————————————

    httpd服务面试题

    1、请说一下你对httpd服务的了解?
    答:Apache是一个模块化服务,支持的模块比较多,采用servlet处理模型,同步阻塞模型,工作模式多变,对于高并发的场景处理速度会比较慢,运行稳定。支持异步读写,可以通过正则表达式做动静分离。

    2、httpd服务的三种工作模式你了解多少?
    答:httpd有三种工作模式。

    prefork:预派生子进程
    prefork模式可以算是很古老但是很稳定的模式。httpd服务在刚启动时,就会fork出一些子进程(默认为5个),一个子进程对应一个线程,然后等待request进来,并且总是试图保持一些空闲的子进程,之所以这样做,是为了减少频繁创建和销毁进程的开销。在同一个时间点内,一个线程只能处理一个进程。

    worker工作模式
    worker模式和prefork模式比起来,是使用了多进程+多线程的模式,它也是预先fork了几个子进程,每个子进程能够生成一些服务线程和一个监听线程,该监听线程及接入请求并传递给服务线程处理和应答。worker工作模式占用的内存较少,在高并发下表现还算优异。不过必须要考虑线程安全的问题,因为多个子进程是共享父进程的内存地址的。如果使用keep-alive的长连接方式,也许中间几乎没有请求,这是就会发生阻塞,线程被挂起,需要一直等待到超时才会被释放。如果过多的线程,就这样被占据,也会导致在高并发场景下的无服务线程可用。(该问题同样会发生在prefork模式)。

    event工作模式
    这是Apache最新的工作模式,它和worker模式很像,最大的区别在于,它解决了keep-alive场景下,线程被长期被占用的的资源浪费问题。

    event工作模式中,会有一个专门的线程来管理这些keep-alive类型的线程,当有真实请求过来的时候偶,将请求传递给服务线程,执行完毕后,又允许它释放。这样,一个线程就能处理多个请求了,实现异步非阻塞。

    event工作模式在遇到某些不兼容的模块时,它会失效,并退回到worker模式,一个工作线程处理一个请求。官方自带的模块,全部都是支持event工作模式的。

    3、可以从哪几个方面着手优化httpd?
    合理配置其进程及线程数;
    开启httpd的deflate压缩功能;
    开启expires缓存功能;
    禁止httpd进行目录遍历;
    隐藏httpd的版本信息;
    开启日志切割功能;
    配置防盗链;
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————

    Nginx面试题

    1、缺省安装的Nginx+php-fpm环境,假设用户浏览一个耗时的网页,但是却在服务端渲染页面的中途中关闭了浏览器,那么请问服务端的PHP脚本是继续执行还是退出执行?
    答:正常情况下,如果client异常退出了,Server端的程序还是会继续执行,直到与IO进行了两次交互操作。Server端发现client端已经断开连接,这个时候会出发一个User_abort,如果这个没有设置ignore_user_abort,那么这个php-fpm的程序才会被中断。

    2、nginx是如何实现高并发的?
    答:nginx之所以可以实现高并发,与它采用的epoll模型有很大的关系。epoll模型采用异步非阻塞的事件处理机制。这种机制可让nginx进程同时监控多个事件。

    简单来说,就是异步非阻塞,使用了epoll模型和大量的底层代码优化。如果深入一点的话,就是nginx的特殊进程模型和事件模型的设计,才使其可以实现高并发。

    进程模型

    它是采用一个master进程和多个worker进程的工作模式。
    1、master进程主要负责收集、分发请求。当一个请求过来时,master拉起一个worker进程负责处理这个请求。;
    2、master进程也要负责监控worker的状态,保证高可靠性;
    3、worker进程议案设置为和CPU核心数一致或者其二倍。nginx的worker进程和Apache的不一样。apache的进程在同一时间只能处理一个请求,所以它会开启很多个进程,几百甚至几千个。而nginx的worker进程在同一时间可以处理的请求数只受内存限制,因此可以处理更多请求。
    

    事件模型
    nginx是异步非阻塞的。

    一个master进程,多个worker进程,每个worker进程可以处理多个请求。每进来一个request,都会有worker进程去处理。但不是全程的处理,那么处理到的程度就是可能发生阻塞的地方,比如向后端服务器转发request,并等待请求返回。那么,在等待期间,这个处理的worker不会这么傻等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是它就去休息了,此时,如果再有request进来,它就可以很快再按这种方式处理。而一旦后端服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。
    由于nginx的的这个工作性质决定了每个请求大部分的生命都是在网络传输中,所以实际上花费在nginx 服务器上的时间并不多,这就是它几进程就能解决高并发的秘密所在。

    3、已知nginx和php-fpm安装在同一台服务器上,nginx连接php-fpm有两种方式:一种是类似127.0.0.1:9000的TCP socket,另一种是类似/tmp/php-fpm.sock的Unix domain socket,请问如何选择?需要注意什么?
    Unix domain socket的流程不会走到TCP那层,直接以文件的形式,以stream socket通信。如果是TCP Socket,则需要走到IP层。说的通俗一点,追求可靠性就是选择TCP(需要占用一个端口,更稳定,如:127.0.0.1:9000),追求高性能就是Unix Socket(不需要占用端口,更快,但可靠性不如TCP的方式)。

    4、nginx和Apache的区别?
    两者最核心的区别在于apache是同步多进程模型,一个request对应一个进程,而nginx是异步的,多个连接(万级别)可以对应一个进程。

    一般来说,需要性能的web服务,用nginx,如果不需要性能只求稳定,更考虑Apache,后者的各种模块实现的比前者好很多,epoll网络IO模型是nginx处理性能高的根本,但并不是所有情况下epoll大获全胜的,如果本身提供静态服务的只有几个文件,apache的select模型或许比epoll更高性能。当然,这只是一个假设,真正还需要实测了再说。

    更通用的方案是,前端nginx抗并发,后端apache集群,配合起来会更好。

    5、nginx的调度算法有哪些?

    sticky:通过nginx-sticky模块,来实现cookie黏贴的方式将来自同一个客户端的请求发送到同一个后端服务器上处理,这样一定程度上可以解决多个后端服务器的session会话同步的问题;
    round-robin(RR):轮询,每个请求按时间顺序依次分配到不同的后端服务器,如果后端某台服务器死机,自动剔除故障系统,使用户访问不受影响;
    weight:轮询权重,weight的值越大分配到的访问概率就越高,主要用于后端每台服务器性能不均衡的情况下,或者仅仅为在主从的情况下设置不同的权重,达到合理有效的利用主机资源。
    least_conn:请求被发送到当前活跃连接最少的realserver上,会考虑到weight的值;
    ip_hash:每个请求按照IP的哈希结果分配,使来自同一个IP的访客固定访问后端服务器,可以有效的解决动态网页存在的session共享问题。
    fair:比weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面的大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,相应时间短的优先分配。nginx本身不支持fair,如果需要使用这种调度算法,则必须安装upstream_fair模块。
    url_hash:按访问的URL的哈希结果来分配请求,使每个URL定向到后端服务器,可以进一步提高后端缓存服务器的效率。同样,nginx本身不支持url_hash,如果需要这种调度算法,则必须安装nginx的hash软件包。
    

    6、nginx负载均衡调度状态
    在nginx upstream模块中,可以设定每台后端服务器在负载均衡调度中的状态。

    常用的状态有:
    
    down:表示当前的server暂时不参与负载均衡;
    backup:预留的备份机器。当其他所有的非backup机器出现故障或者繁忙的时候,才会请求backup机器,因此这台机器的访问压力最低;
    max_fails:允许请求失败的次数,默认为1,当超过最大次数时,返回proxy_next_upstraem模块定义的错误;
    fail_timeout:请求失败超时时间,在经历了max_fails次失败后,暂停服务的时间。max_fails和fail_timeout可以一起使用。
    

    7、如何查看nginx已添加的模块?如果需要添加某个模块,应该如何实现?
    查看已添加的模块:nginx -V;
    如果需要添加某个模块,需要将工作目录切换至nginx的源码包中,执行“nginx -V”命令查看之前配置时的选项进行复制,然后增加需要添加的模块配置项,进行配置并编译,将新生成的nginx命令覆盖掉原有的nginx命令,然后重载nginx服务,即可实现在线添加模块。

    8、可以从哪些方面来优化nginx服务?

    配置nginx的proxy缓存;
    对静态页面开启压缩功能,如br压缩或者gzip压缩;
    调整nginx运行工作进程个数,最多开启8个,8个以上话性能就不会再提升了,而且稳定性变得更低,所以8个足够用了;
    调整nginx运行CPU的亲和力;
    修改nginx最多可打开的文件数,若超过系统限制的最多打开文件数(ulimit -n命令查看系统的最多打开文件数),还需要修改系统默认的文件数;
    修改单个worker的最大连接数;
    开启高效传输;
    设置连接超时时间,以便保护服务器资源,因为建立连接也是需要消耗资源的;
    优化fastCGI的一个超时时间,也可以根据实际情况对其配置缓存动态页面;
    expires缓存调优,主要针对图片、css、js等元素更改较少的情况下使用。
    配置防盗链;
    优化内核参数,如进程可以同时打开的最大句柄数;开启tcp重用机制,以便允许TIME_WAIT sockets重新用于新的TCP连接....还有好多,记不住。
    

    ————————————————————————————————————————————————————————————————————————————————————————————————

    Linux运维常见面试题

    1、什么是运维?什么是游戏运维?
    1)运维是指大型组织已经建立好的网络软硬件的维护,就是要保证业务的上线与运作的正常,
    在他运转的过程中,对他进行维护,他集合了网络、系统、数据库、开发、安全、监控于一身的技术
    运维又包括很多种,有DBA运维、网站运维、虚拟化运维、监控运维、游戏运维等等
    2)游戏运维又有分工,分为开发运维、应用运维(业务运维)和系统运维
    开发运维:是给应用运维开发运维工具和运维平台的
    应用运维:是给业务上线、维护和做故障排除的,用开发运维开发出来的工具给业务上线、维护、做故障排查
    系统运维:是给应用运维提供业务上的基础设施,比如:系统、网络、监控、硬件等等
    总结:开发运维和系统运维给应用运维提供了“工具”和“基础设施”上的支撑
    开发运维、应用运维和系统运维他们的工作是环环相扣的
    ——————————————————————————————————————————————————————————————————————————————————
    2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
    游戏运营要做的一个事情除了协调工作以外
    还需要与各平台沟通,做好开服的时间、开服数、用户导量、活动等计划
    ————————————————————————————————————————————————————————————————————————————————————————
    3、现在给你三百台服务器,你怎么对他们进行管理?
    管理3百台服务器的方式:
    1)设定跳板机,使用统一账号登录,便于安全与登录的考量。
    2)使用saltstark、ansiable、puppet进行系统的统一调度与配置的统一管理。
    3)建立简单的服务器的系统、配置、应用的cmdb信息管理。便于查阅每台服务器上的各种信息记录
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    4、简述raid0 raid1 raid5 三种工作模式的工作原理及特点
    RAID,可以把硬盘整合成一个大磁盘,还可以在大磁盘上再分区,放数据
    还有一个大功能,多块盘放在一起可以有冗余(备份)
    RAID整合方式有很多,常用的:0 1 5 10
    RAID 0,可以是一块盘和N个盘组合
    其优点读写快,是RAID中最好的
    缺点:没有冗余,一块坏了数据就全没有了
    RAID 1,只能2块盘,盘的大小可以不一样,以小的为准
    10G+10G只有10G,另一个做备份。它有100%的冗余,缺点:浪费资源,成本高
    RAID 5 ,3块盘,容量计算10*(n-1),损失一块盘
    特点,读写性能一般,读还好一点,写不好
    冗余从好到坏:RAID1 RAID10 RAID 5 RAID0
    性能从好到坏:RAID0 RAID10 RAID5 RAID1
    成本从低到高:RAID0 RAID5 RAID1 RAID10
    单台服务器:很重要盘不多,系统盘,RAID1
    数据库服务器:主库:RAID10 从库 RAID5\RAID0(为了维护成本,RAID10)
    WEB服务器,如果没有太多的数据的话,RAID5,RAID0(单盘)
    有多台,监控、应用服务器,RAID0 RAID5
    我们会根据数据的存储和访问的需求,去匹配对应的RAID级别
    —————————————————————————————————————————————————————————————————————————————————————————————————————————
    5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
    LVS: 是基于四层的转发
    HAproxy: 是基于四层和七层的转发,是专业的代理服务器
    Nginx: 是WEB服务器,缓存服务器,又是反向代理服务器,可以做七层的转发
    区别: LVS由于是基于四层的转发所以只能做端口的转发
    而基于URL的、基于目录的这种转发LVS就做不了
    工作选择:
    HAproxy和Nginx由于可以做七层的转发,所以URL和目录的转发都可以做
    在很大并发量的时候我们就要选择LVS,像中小型公司的话并发量没那么大
    选择HAproxy或者Nginx足已,由于HAproxy由是专业的代理服务器
    配置简单,所以中小型企业推荐使用HAproxy
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
    Squid、Varinsh和Nginx都是代理服务器
    什么是代理服务器:
    能当替用户去访问公网,并且能把访问到的数据缓存到服务器本地,等用户下次再访问相同的资
    源的时候,代理服务器直接从本地回应给用户,当本地没有的时候,我代替你去访问公网,我接
    收你的请求,我先在我自已的本地缓存找,如果我本地缓存有,我直接从我本地的缓存里回复你
    如果我在我本地没有找到你要访问的缓存的数据,那么代理服务器就会代替你去访问公网
    区别:
    1)Nginx本来是反向代理/web服务器,用了插件可以做做这个副业
    但是本身不支持特性挺多,只能缓存静态文件
    2)从这些功能上。varnish和squid是专业的cache服务,而nginx这些是第三方模块完成
    3)varnish本身的技术上优势要高于squid,它采用了可视化页面缓存技术
    在内存的利用上,Varnish比Squid具有优势,性能要比Squid高。
    还有强大的通过Varnish管理端口,可以使用正则表达式快速、批量地清除部分缓存
    它是内存缓存,速度一流,但是内存缓存也限制了其容量,缓存页面和图片一般是挺好的
    4)squid的优势在于完整的庞大的cache技术资料,和很多的应用生产环境
    工作中选择:
    要做cache服务的话,我们肯定是要选择专业的cache服务,优先选择squid或者varnish。
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    7、Tomcat和Resin有什么区别,工作中你怎么选择?
    区别:Tomcat用户数多,可参考文档多,Resin用户数少,可考虑文档少
    最主要区别则是Tomcat是标准的java容器,不过性能方面比resin的要差一些
    但稳定性和java程序的兼容性,应该是比resin的要好
    工作中选择:现在大公司都是用resin,追求性能;而中小型公司都是用Tomcat,追求稳定和程序的兼容
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    8、什么是中间件?什么是jdk?
    中间件介绍:
    中间件是一种独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源
    中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯
    是连接两个独立应用程序或独立系统的软件。相连接的系统,即使它们具有不同的接口
    但通过中间件相互之间仍能交换信息。执行中间件的一个关键途径是信息传递
    通过中间件,应用程序可以工作于多平台或OS环境。
    jdk:jdk是Java的开发工具包
    它是一种用于构建在 Java 平台上发布的应用程序、applet 和组件的开发环境
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    9、讲述一下Tomcat8005、8009、8080三个端口的含义?
    8005==》 关闭时使用
    8009==》 为AJP端口,即容器使用,如Apache能通过AJP协议访问Tomcat的8009端口
    8080==》 一般应用使用
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    10、什么叫CDN?
    即内容分发网络
    其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到
    最接近用户的网络边缘,使用户可就近取得所需的内容,提高用户访问网站的速度
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    11、什么叫网站灰度发布?
    灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式
    AB test就是一种灰度发布方式,让一部用户继续用A,一部分用户开始用B
    如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面 来灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    12、简述DNS进行域名解析的过程?
    用户要访问 www.baidu.com,会先找本机的host文件,再找本地设置的DNS服务器,如果也没有的话,就去网络中找根服务器,根服务器反馈结果,说只能提供一级域名服务器.cn,就去找一级域名服务器,一级域名服务器说只能提供二级域名服务器.com.cn,就去找二级域名服务器,二级域服务器只能提供三级域名服务器.baidu.com.cn,就去找三级域名服务器,三级域名服务器正好有这个网站www.baidu.com,然后发给请求的服务器,保存一份之后,再发给客户端

    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    13、RabbitMQ是什么东西?
    RabbitMQ也就是消息队列中间件,消息中间件是在消息的传息过程中保存消息的容器
    消息中间件再将消息从它的源中到它的目标中标时充当中间人的作用
    队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用
    消息队列不会保留消息,直到可以成功地传递为止,当然,消息队列保存消息也是有期限地
    ————————————————————————————————————————————————————————————————————————————————————————
    14、讲一下Keepalived的工作原理?
    在一个虚拟路由器中,只有作为MASTER的VRRP(虚拟路由冗余协议)路由器会一直发送VRRP通告信息,
    BACKUP不会抢占MASTER,除非它的优先级更高。当MASTER不可用时(BACKUP收不到通告信息)
    多台BACKUP中优先级最高的这台会被抢占为MASTER。这种抢占是非常快速的(<1s),以保证服务的连续性
    由于安全性考虑,VRRP包使用了加密协议进行加密。BACKUP不会发送通告信息,只会接收通告信息
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

    15、讲述一下LVS三种模式的工作过程?
    LVS 有三种负载均衡的模式,分别是VS/NAT(nat 模式) VS/DR(路由模式) VS/TUN(隧道模式)
    一、NAT模式(VS-NAT)
    原理:就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址
    并发至此RS来处理,RS处理完后把数据交给负载均衡器,负载均衡器再把数据包原IP地址改为自己的IP
    将目的地址改为客户端IP地址即可期间,无论是进来的流量,还是出去的流量,都必须经过负载均衡器
    优点:集群中的物理服务器可以使用任何支持TCP/IP操作系统,只有负载均衡器需要一个合法的IP地址
    缺点:扩展性有限。当服务器节点(普通PC服务器)增长过多时,负载均衡器将成为整个系统的瓶颈
    因为所有的请求包和应答包的流向都经过负载均衡器。当服务器节点过多时
    大量的数据包都交汇在负载均衡器那,速度就会变慢!
    二、IP隧道模式(VS-TUN)
    原理:首先要知道,互联网上的大多Internet服务的请求包很短小,而应答包通常很大
    那么隧道模式就是,把客户端发来的数据包,封装一个新的IP头标记(仅目的IP)发给RS
    RS收到后,先把数据包的头解开,还原数据包,处理后,直接返回给客户端,不需要再经过
    负载均衡器。注意,由于RS需要对负载均衡器发过来的数据包进行还原,所以说必须支持
    IPTUNNEL协议,所以,在RS的内核中,必须编译支持IPTUNNEL这个选项
    优点:负载均衡器只负责将请求包分发给后端节点服务器,而RS将应答包直接发给用户
    所以,减少了负载均衡器的大量数据流动,负载均衡器不再是系统的瓶颈,就能处理很巨大的请求量
    这种方式,一台负载均衡器能够为很多RS进行分发。而且跑在公网上就能进行不同地域的分发。
    缺点:隧道模式的RS节点需要合法IP,这种方式需要所有的服务器支持”IP Tunneling”
    (IP Encapsulation)协议,服务器可能只局限在部分Linux系统上
    三、直接路由模式(VS-DR)
    原理:负载均衡器和RS都使用同一个IP对外服务但只有DR对ARP请求进行响应
    所有RS对本身这个IP的ARP请求保持静默也就是说,网关会把对这个服务IP的请求全部定向给DR
    而DR收到数据包后根据调度算法,找出对应的RS,把目的MAC地址改为RS的MAC(因为IP一致)
    并将请求分发给这台RS这时RS收到这个数据包,处理完成之后,由于IP一致,可以直接将数据返给客户
    则等于直接从客户端收到这个数据包无异,处理后直接返回给客户端
    由于负载均衡器要对二层包头进行改换,所以负载均衡器和RS之间必须在一个广播域
    也可以简单的理解为在同一台交换机上
    优点:和TUN(隧道模式)一样,负载均衡器也只是分发请求,应答包通过单独的路由方法返回给客户端
    与VS-TUN相比,VS-DR这种实现方式不需要隧道结构,因此可以使用大多数操作系统做为物理服务器。
    缺点:(不能说缺点,只能说是不足)要求负载均衡器的网卡必须与物理网卡在一个物理段上。
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

    16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
    mysql的innodb如何定位锁问题:
    在使用 show engine innodb status检查引擎状态时,发现了死锁问题
    在5.5中,information_schema 库中增加了三个关于锁的表(MEMORY引擎)
    innodb_trx ## 当前运行的所有事务
    innodb_locks ## 当前出现的锁
    innodb_lock_waits ## 锁等待的对应关系
    mysql如何减少主从复制延迟:
    如果延迟比较大,就先确认以下几个因素:
    从库硬件比主库差,导致复制延迟

    主从复制单线程,如果主库写并发太大,来不及传送到从库

    就会导致延迟。更高版本的mysql可以支持多线程复制
    慢SQL语句过多

    网络延迟

    master负载
    主库读写压力大,导致复制延迟,架构的前端要加buffer及缓存层
    slave负载
    一般的做法是,使用多台slave来分摊读请求,再从这些slave中取一台专用的服务器
    只作为备份用,不进行其他任何操作.另外, 2个可以减少延迟的参数:
    –slave-net-timeout=seconds 单位为秒 默认设置为 3600秒
    #参数含义:当slave从主数据库读取log数据失败后,等待多久重新建立连接并获取数据
    –master-connect-retry=seconds 单位为秒 默认设置为 60秒
    #参数含义:当重新建立主从连接时,如果连接建立失败,间隔多久后重试
    通常配置以上2个参数可以减少网络问题导致的主从数据同步延迟
    MySQL数据库主从同步延迟解决方案
    最简单的减少slave同步延时的方案就是在架构上做优化,尽量让主库的DDL快速执行
    还有就是主库是写,对数据安全性较高,比如sync_binlog=1,innodb_flush_log_at_trx_commit
    = 1 之类的设置,而slave则不需要这么高的数据安全,完全可以讲sync_binlog设置为0或者关闭binlog
    innodb_flushlog也可以设置为0来提高sql的执行效率。另外就是使用比主库更好的硬件设备作为slave
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    17、如何重置mysql root密码?
    一、 在已知MYSQL数据库的ROOT用户密码的情况下,修改密码的方法:
    1、 在SHELL环境下,使用mysqladmin命令设置:
    mysqladmin –u root –p password “新密码” 回车后要求输入旧密码
    2、 在mysql>环境中,使用update命令,直接更新mysql库user表的数据:
    Update mysql.user set password=password(‘新密码’) where user=’root’;
    flush privileges;
    注意:mysql语句要以分号”;”结束
    3、 在mysql>环境中,使用grant命令,修改root用户的授权权限。
    grant all on . to root@’localhost’ identified by ‘新密码’;
    二、 如查忘记了mysql数据库的ROOT用户的密码,又如何做呢?方法如下:
    1、 关闭当前运行的mysqld服务程序:service mysqld stop(要先将mysqld添加为系统服务)
    2、 使用mysqld_safe脚本以安全模式(不加载授权表)启动mysqld 服务
    /usr/local/mysql/bin/mysqld_safe --skip-grant-table &
    3、 使用空密码的root用户登录数据库,重新设置ROOT用户的密码
    #mysql -u root
    Mysql> Update mysql.user set password=password(‘新密码’) where user=’root’;
    Mysql> flush privileges;
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    18、lvs/nginx/haproxy优缺点
    Nginx的优点是:
    1、工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构
    它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一
    Nginx单凭这点可利用的场合就远多于LVS了。
    2、Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势之一
    相反LVS对网络稳定性依赖比较大,这点本人深有体会;
    3、Nginx安装和配置比较简单,测试起来比较方便,它基本能把错误用日志打印出来
    LVS的配置、测试就要花比较长的时间了,LVS对网络依赖比较大。
    4、可以承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS相对小些。
    5、Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了
    如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满。
    6、Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器
    LNMP也是近几年非常流行的web架构,在高流量的环境中稳定性也很好。
    7、Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,可考虑用其作为反向代理加速器
    8、Nginx可作为中层反向代理使用,这一层面Nginx基本上无对手,唯一可以对比Nginx的就只有lighttpd了
    不过lighttpd目前还没有做到Nginx完全的功能,配置也不那么清晰易读,社区资料也远远没Nginx活跃
    9、Nginx也可作为静态网页和图片服务器,这方面的性能也无对手。还有Nginx社区非常活跃,第三方模块也很多
    Nginx的缺点是:
    1、Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些,这个是它的缺点
    2、对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测
    不支持Session的直接保持,但能通过ip_hash来解决
    LVS:使用Linux内核集群实现一个高性能、高可用的负载均衡服务器
    它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)
    LVS的优点是:
    1、抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生
    这个特点也决定了它在负载均衡软件里的性能最强的,对内存和cpu资源消耗比较低
    2、配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西
    所以并不需要太多接触,大大减少了人为出错的几率
    3、工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案
    如LVS+Keepalived,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived
    4、无流量,LVS只分发请求,而流量并不从它本身出去,这点保证了均衡器IO的性能不会收到大流量的影响。
    5、应用范围较广,因为LVS工作在4层,所以它几乎可对所有应用做负载均衡,包括http、数据库、在线聊天室等
    LVS的缺点是:
    1、软件本身不支持正则表达式处理,不能做动静分离
    而现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在
    2、如果是网站应用比较庞大的话,LVS/DR+Keepalived实施起来就比较复杂了
    特别后面有Windows Server的机器的话,如果实施及配置还有维护过程就比较复杂了
    相对而言,Nginx/HAProxy+Keepalived就简单多了。
    HAProxy的特点是:
    1、HAProxy也是支持虚拟主机的。
    2、HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导
    同时支持通过获取指定的url来检测后端服务器的状态
    3、HAProxy跟LVS类似,本身就只是一款负载均衡软件
    单纯从效率上来讲HAProxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的
    4、HAProxy支持TCP协议的负载均衡转发,可以对MySQL读进行负载均衡
    对后端的MySQL节点进行检测和负载均衡,大家可以用LVS+Keepalived对MySQL主从做负载均衡
    5、HAProxy负载均衡策略非常多,HAProxy的负载均衡算法现在具体有如下8种:
    ①roundrobin,表示简单的轮询,这个不多说,这个是负载均衡基本都具备的;
    ② static-rr,表示根据权重,建议关注;
    ③leastconn,表示最少连接者先处理,建议关注;
    ④ source,表示根据请求源IP,这个跟Nginx的IP_hash机制类似
    我们用其作为解决session问题的一种方法,建议关注;
    ⑤ri,表示根据请求的URI;
    ⑥rl_param,表示根据请求的URl参数’balance url_param’ requires an URL parameter name;
    ⑦hdr(name),表示根据HTTP请求头来锁定每一次HTTP请求;
    ⑧rdp-cookie(name),表示根据据cookie(name)来锁定并哈希每一次TCP请求。
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    19、mysql数据备份工具
    mysqldump工具
    mysqldump是mysql自带的备份工具,目录在bin目录下面:/usr/local/mysql/bin/mysqldump
    支持基于innodb的热备份,但是由于是逻辑备份,所以速度不是很快,适合备份数据比较小的场景
    Mysqldump完全备份+二进制日志可以实现基于时间点的恢复。
    基于LVM快照备份
    在物理备份中,有基于文件系统的物理备份(LVM的快照),也可以直接用tar之类的命令对整个数据库目录
    进行打包备份,但是这些只能进行泠备份,不同的存储引擎备份的也不一样,myisam自动备份到表级别
    而innodb不开启独立表空间的话只能备份整个数据库。
    tar包备份
    percona提供的xtrabackup工具
    支持innodb的物理热备份,支持完全备份,增量备份,而且速度非常快,支持innodb存储引起的数据在不同
    数据库之间迁移,支持复制模式下的从机备份恢复备份恢复,为了让xtrabackup支持更多的功能扩展
    可以设立独立表空间,打开 innodb_file_per_table功能,启用之后可以支持单独的表备份
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    20、keepalive的工作原理和如何做到健康检查
    keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。
    虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组
    这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip(该路由器所在局域网内
    其他机器的默认路由为该vip),master会发组播,当backup收不到vrrp包时就认为master宕掉了
    这时就需要根据VRRP的优先级来选举一个backup当master。这样就可以保证路由器的高可用了
    keepalived主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护
    及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式,vrrp模块是来实现VRRP协议的
    Keepalived健康检查方式配置
    HTTP_GET|SSL_GET
    HTTP_GET | SSL_GET
    {
    url {
    path /# HTTP/SSL 检查的url可以是多个
    digest # HTTP/SSL 检查后的摘要信息用工具genhash生成
    status_code 200# HTTP/SSL 检查返回的状态码
    }
    connect_port 80 # 连接端口
    bindto
    connect_timeout 3 # 连接超时时间
    nb_get_retry 3 # 重连次数
    delay_before_retry 2 #连接间隔时间
    }
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    21、统计ip访问情况,要求分析nginx访问日志,找出访问页面数量在前十位的ip
    cat access.log | awk ‘{print $1}’ | uniq -c | sort -rn | head -10
    ————————————————————————————————————————————————————————————————————————————————————————————————————————
    22、使用tcpdump监听主机为192.168.1.1,tcp端口为80的数据,同时将输出结果保存输出到tcpdump.log
    tcpdump ‘host 192.168.1.1 and port 80’ > tcpdump.log
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————
    23、如何将本地80 端口的请求转发到8080 端口,当前主机IP 为192.168.2.1
    iptables -A PREROUTING -d 192.168.2.1 -p tcp -m tcp -dport 80 -j DNAT-to-destination 192.168.2.1:8080
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    24、简述raid0 raid1 raid5 三种工作模式的工作原理及特点
    RAID 0:带区卷,连续以位或字节为单位分割数据,并行读/写于多个磁盘上,因此具有很高的数据传输率
    但它没有数据冗余,RAID 0 只是单纯地提高性能,并没有为数据的可靠性提供保证
    而且其中的一个磁盘失效将影响到所有数据。因此,RAID 0 不能应用于数据安全性要求高的场合
    RAID 1:镜像卷,它是通过磁盘数据镜像实现数据冗余,在成对的独立磁盘上产生互为备份的数据
    不能提升写数据效率。当原始数据繁忙时,可直接从镜像拷贝中读取数据,因此RAID1 可以提高读取性能
    RAID 1 是磁盘阵列中单位成本最高的,镜像卷可用容量为总容量的1/2,但提供了很高的数据安全性和可用性
    当一个磁盘失效时,系统可以自动切换到镜像磁盘上读写,而不需要重组失效的数据
    RAID5:至少由3块硬盘组成,分布式奇偶校验的独立磁盘结构,它的奇偶校验码存在于所有磁盘上
    任何一个硬盘损坏,都可以根据其它硬盘上的校验位来重建损坏的数据(最多允许1块硬盘损坏)
    所以raid5可以实现数据冗余,确保数据的安全性,同时raid5也可以提升数据的读写性能
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    25、你对现在运维工程师的理解和以及对其工作的认识
    运维工程师在公司当中责任重大,需要保证时刻为公司及客户提供最高、最快、最稳定、最安全的服务
    运维工程师的一个小小的失误,很有可能会对公司及客户造成重大损失
    因此运维工程师的工作需要严谨及富有创新精神
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    26、实时抓取并显示当前系统中tcp 80端口的网络数据信息,请写出完整操作命令
    tcpdump -nn tcp port 80

    ————————————————————————————————————————————————————————————————————————————————————
    27、如何优化 Linux系统(可以不说太具体)?
    不用root,添加普通用户,通过sudo授权管理
    更改默认的远程连接SSH服务端口及禁止root用户远程连接
    定时自动更新服务器时间
    配置国内yum源
    关闭selinux及iptables(iptables工作场景如果有外网IP一定要打开,高并发除外)
    调整文件描述符的数量
    精简开机启动服务(crond rsyslog network sshd)
    内核参数优化(/etc/sysctl.conf)
    更改字符集,支持中文,但建议还是用英文字符集,防止乱码
    锁定关键系统文件
    清空/etc/issue,去除系统及内核版本登录前的屏幕显示

    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    28、Linux系统中病毒怎么解决
    1)最简单有效的方法就是重装系统
    2)要查的话就是找到病毒文件然后删除
    中毒之后一般机器cpu、内存使用率会比较高
    机器向外发包等异常情况,排查方法简单介绍下
    top 命令找到cpu使用率最高的进程
    一般病毒文件命名都比较乱,可以用 ps aux 找到病毒文件位置
    rm -f 命令删除病毒文件
    检查计划任务、开机启动项和病毒文件目录有无其他可以文件等
    3)由于即使删除病毒文件不排除有潜伏病毒,所以最好是把机器备份数据之后重装一下
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    29、发现一个病毒文件你删了他又自动创建怎么解决
    公司的内网某台linux服务器流量莫名其妙的剧增,用iftop查看有连接外网的情况
    针对这种情况一般重点查看netstat连接的外网ip和端口。
    用lsof -p pid可以查看到具体是那些进程,哪些文件
    经查勘发现/root下有相关的配置conf.n hhe两个可疑文件,rm -rf后不到一分钟就自动生成了
    由此推断是某个母进程产生的这些文件。所以找到母进程就是找到罪魁祸首
    查杀病毒最好断掉外网访问,还好是内网服务器,可以通过内网访问
    断了内网,病毒就失去外联的能力,杀掉它就容易的多
    怎么找到呢,找了半天也没有看到蛛丝马迹,没办法只有ps axu一个个排查
    方法是查看可以的用户和和系统相似而又不是的冒牌货,果然,看到了如下进程可疑
    看不到图片就是/usr/bin/.sshd
    于是我杀掉所有.sshd相关的进程,然后直接删掉.sshd这个可执行文件
    然后才删掉了文章开头提到的自动复活的文件
    总结一下,遇到这种问题,如果不是太严重,尽量不要重装系统
    一般就是先断外网,然后利用iftop,ps,netstat,chattr,lsof,pstree这些工具顺藤摸瓜
    一般都能找到元凶。但是如果遇到诸如此类的问题
    /boot/efi/EFI/redhat/grub.efi: Heuristics.Broken.Executable FOUND,个人觉得就要重装系统了
    ————————————————————————————————————————————————————————————————————————————————————————————————————————
    30、说说TCP/IP的七层模型
    应用层 (Application):
    网络服务与最终用户的一个接口。
    协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP
    表示层(Presentation Layer):
    数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)
    格式有,JPEG、ASCll、DECOIC、加密格式等
    会话层(Session Layer):
    建立、管理、终止会话。(在五层模型里面已经合并到了应用层)
    对应主机进程,指本地主机与远程主机正在进行的会话
    传输层 (Transport):
    定义传输数据的协议端口号,以及流控和差错校验。
    协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层
    网络层 (Network):
    进行逻辑地址寻址,实现不同网络之间的路径选择。
    协议有:ICMP IGMP IP(IPV4 IPV6) ARP RARP
    数据链路层 (Link):
    建立逻辑连接、进行硬件地址寻址、差错校验等功能。(由底层网络定义协议)
    将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正
    物理层(Physical Layer):
    是计算机网络OSI模型中最低的一层
    物理层规定:为传输数据所需要的物理链路创建、维持、拆除
    而提供具有机械的,电子的,功能的和规范的特性
    简单的说,物理层确保原始的数据可在各种物理媒体上传输。局域网与广域网皆属第1、2层
    物理层是OSI的第一层,它虽然处于最底层,却是整个开放系统的基础
    物理层为设备之间的数据通信提供传输媒体及互连设备,为数据传输提供可靠的环境
    如果您想要用尽量少的词来记住这个第一层,那就是“信号和介质”
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————
    31、你常用的Nginx模块,用来做什么
    rewrite模块,实现重写功能
    access模块:来源控制
    ssl模块:安全加密
    ngx_http_gzip_module:网络传输压缩模块
    ngx_http_proxy_module 模块实现代理
    ngx_http_upstream_module模块实现定义后端服务器列表
    ngx_cache_purge实现缓存清除功能
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    32、请列出你了解的web服务器负载架构
    Nginx
    Haproxy
    Keepalived
    LVS
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    33、查看http的并发请求数与其TCP连接状态
    netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
    还有ulimit -n 查看linux系统打开最大的文件描述符,这里默认1024
    不修改这里web服务器修改再大也没用,若要用就修改很几个办法,这里说其中一个:
    修改/etc/security/limits.conf
    soft nofile 10240
    hard nofile 10240
    重启后生效
    ————————————————————————————————————————————————————————————————————————————————————————————————————————
    34、用tcpdump嗅探80端口的访问看看谁最高
    tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."KaTeX parse error: Expected 'EOF', got '}' at position 2: 4}̲'| sort | uniq …ip > /dev/null 2>&1
    if [ ? − e q 0 ] ; t h e n e c h o 192.168.1. ? -eq 0 ]; then echo 192.168.1. ?eq0];thenecho192.168.1.ip UP
    else
    echo 192.168.1.KaTeX parse error: Expected 'EOF', got '}' at position 12: ip DOWN fi }̲& done wait ———…(Shift+4)
    光标下插入一行:o
    复制5行:5yy
    删除10行:10dd
    替换::%s/jingfeng/jfedu.net/g
    ——————————————————————————————————————————————————————————————————————————————————————————————————
    4.查找linux系统下以txt结尾,30天没有修改的文件大小大于20K同时具有执行权限的文件并备份到/data/backup/目录下。
    答:
    find / -name *txt -mtime +30 -type f -size +20k -perma= x -exec cp {} /data/backup/ ;
    ————————————————————————————————————————————————————————————————————————————————————————————————————————
    5.当前test.txt所属的用户为root,组为abc,请将test.txt使拥有者为abc,组为root,写出命令。
    答:
    chown abc:root test.txt
    ——————————————————————————————————————————————————————————————————————————————————————————————————
    6.如何修改Linux启动级别为字符模式并永久生效,如何临时、永久关闭selinux及防火墙,请分别写出操作方法。
    答:
    更改字符模式:修改/etc/inittab一行为id:3:initdefault:
    临时关闭selinnuxsetenforce0
    临时关闭防火墙iptables-F
    永久关闭selinux修改/etc/selinux/config一行为SELINUX=permissive
    永久关闭防火墙 iptables -F; /etc/init.d/iptablessave
    ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    7.每次开机在/tmp目录下创建一个当天的日期文件夹(提示:当前日期表示的方法为:date+%Y%m%d)
    答:
    echo “mkdir/tmp/ date+%Y%m%d” >> /etc/rc.d/rc.local
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    8.如何查看文件内容,命令有哪些?查看文件第1行到3行,查看文件最后一行。
    答:
    查看文件内容:vim、cat、head、tail
    查看第1到行:head -3 file
    查看最后一行:tail -1 file
    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    9.查看linux服务器IP的命令,同时只显示包含ip所在的行打印出来。
    答:
    以eth0为例
    只打印所在的行:ifconfig eth0 | grep “inetaddr:”
    只打印ip:ifconfig eth0 | grep “inetaddr:” | awk -F: ‘{print$2}’ | awk -F ’ ’ ‘{print$1}’
    ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    10.将普通用户test加入root组的命令是?
    答:
    usermod -G root test

    展开全文
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是...Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的对比基础语法数据类型Java有哪些数据类型switc...

    Java面试总结(2021优化版)已发布在个人微信公众号【技术人成长之路】,优化版首先修正了读者反馈的部分答案存在的错误,同时根据最新面试总结,删除了低频问题,添加了一些常见面试题,对文章进行了精简优化,欢迎大家关注!😊😊

    【技术人成长之路】,助力技术人成长!更多精彩文章第一时间在公众号发布哦!

    文章目录

    Java面试总结汇总,整理了包括Java基础知识,集合容器,并发编程,JVM,常用开源框架Spring,MyBatis,数据库,中间件等,包含了作为一个Java工程师在面试中需要用到或者可能用到的绝大部分知识。欢迎大家阅读,本人见识有限,写的博客难免有错误或者疏忽的地方,还望各位大佬指点,在此表示感激不尽。文章持续更新中…

    序号内容链接地址
    1Java基础知识面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390612
    2Java集合容器面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588551
    3Java异常面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390689
    4并发编程面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104863992
    5JVM面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390752
    6Spring面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397516
    7Spring MVC面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397427
    8Spring Boot面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397299
    9Spring Cloud面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397367
    10MyBatis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/101292950
    11Redis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/103522351
    12MySQL数据库面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104778621
    13消息中间件MQ与RabbitMQ面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588612
    14Dubbo面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390006
    15Linux面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588679
    16Tomcat面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397665
    17ZooKeeper面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397719
    18Netty面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104391081
    19架构设计&分布式&数据结构与算法面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/105870730

    Java概述

    何为编程

    编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程。

    为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路、方法、和手段通过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完成某种特定的任务。这种人和计算机之间交流的过程就是编程。

    什么是Java

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

    jdk1.5之后的三大版本

    • Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
      Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为Java EE和Java ME提供基础。
    • Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
      Java EE 以前称为 J2EE。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java 应用程序。Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web2.0应用程序。2018年2月,Eclipse 宣布正式将 JavaEE 更名为 JakartaEE
    • Java ME(J2ME,Java 2 Platform Micro Edition,微型版)
      Java ME 以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。

    JVM、JRE和JDK的关系

    JVM
    Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

    JRE
    Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包

    如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

    JDK
    Java Development Kit是提供给Java开发人员使用的,其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等

    JVM&JRE&JDK关系图

    什么是跨平台性?原理是什么

    所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。

    实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。

    Java语言有哪些特点

    简单易学(Java语言的语法与C语言和C++语言很接近)

    面向对象(封装,继承,多态)

    平台无关性(Java虚拟机实现平台无关性)

    支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)

    支持多线程(多线程机制使应用程序在同一时间并行执行多项任)

    健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)

    安全性

    什么是字节码?采用字节码的最大好处是什么

    字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。

    采用字节码的好处

    Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

    先看下java中的编译器和解释器

    Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行,这就是上面提到的Java的特点的编译与解释并存的解释。

    Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。
    

    什么是Java程序的主类?应用程序和小程序的主类有何不同?

    一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()方法的类。而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。

    Java应用程序与小程序之间有那些差别?

    简单说应用程序是从主线程启动(也就是main()方法)。applet小程序没有main方法,主要是嵌在浏览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。

    Java和C++的区别

    我知道很多人没学过C++,但是面试官就是没事喜欢拿咱们Java和C++比呀!没办法!!!就算没学过C++,也要记下来!

    • 都是面向对象的语言,都支持封装、继承和多态
    • Java不提供指针来直接访问内存,程序内存更加安全
    • Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
    • Java有自动内存管理机制,不需要程序员手动释放无用内存

    Oracle JDK 和 OpenJDK 的对比

    1. Oracle JDK版本将每三年发布一次,而OpenJDK版本每三个月发布一次;

    2. OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全开源的;

    3. Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择Oracle JDK,因为它经过了彻底的测试和稳定。某些情况下,有些人提到在使用OpenJDK 可能会遇到了许多应用程序崩溃的问题,但是,只需切换到Oracle JDK就可以解决问题;

    4. 在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;

    5. Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;

    6. Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。

    基础语法

    数据类型

    Java有哪些数据类型

    定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。

    分类

    • 基本数据类型
      • 数值型
        • 整数类型(byte,short,int,long)
        • 浮点类型(float,double)
      • 字符型(char)
      • 布尔型(boolean)
    • 引用数据类型
      • 类(class)
      • 接口(interface)
      • 数组([])

    Java基本数据类型图

    switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上

    在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

    用最有效率的方法计算 2 乘以 8

    2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)。

    Math.round(11.5) 等于多少?Math.round(-11.5)等于多少

    Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。

    float f=3.4;是否正确

    不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。

    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);其中有隐含的强制类型转换。

    编码

    Java语言采用何种编码方案?有何特点?

    Java语言采用Unicode编码标准,Unicode(标准码),它为每个字符制订了一个唯一的数值,因此在任何的语言,平台,程序都可以放心的使用。

    注释

    什么Java注释

    定义:用于解释说明程序的文字

    分类

    • 单行注释
      格式: // 注释文字
    • 多行注释
      格式: /* 注释文字 */
    • 文档注释
      格式:/** 注释文字 */

    作用

    在程序中,尤其是复杂的程序中,适当地加入注释可以增加程序的可读性,有利于程序的修改、调试和交流。注释的内容在程序编译的时候会被忽视,不会产生目标代码,注释的部分不会对程序的执行结果产生任何影响。

    注意事项:多行和文档注释都不能嵌套使用。

    访问修饰符

    访问修饰符 public,private,protected,以及不写(默认)时的区别

    定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

    分类

    private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
    default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
    protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
    public : 对所有类可见。使用对象:类、接口、变量、方法

    访问修饰符图

    运算符

    &和&&的区别

    &运算符有两种用法:(1)按位与;(2)逻辑与。

    &&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

    注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

    关键字

    Java 有没有 goto

    goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。

    final 有什么用?

    用于修饰类、属性和方法;

    • 被final修饰的类不可以被继承
    • 被final修饰的方法不可以被重写
    • 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的

    final finally finalize区别

    • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表
      示该变量是一个常量不能被重新赋值。
    • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块
      中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
    • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调
      用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的
      最后判断。

    this关键字的用法

    this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

    this的用法在java中大体可以分为3种:

    1.普通的直接引用,this相当于是指向当前对象本身。

    2.形参与成员名字重名,用this来区分:

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    

    3.引用本类的构造函数

    class Person{
        private String name;
        private int age;
        
        public Person() {
        }
     
        public Person(String name) {
            this.name = name;
        }
        public Person(String name, int age) {
            this(name);
            this.age = age;
        }
    }
    

    super关键字的用法

    super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。

    super也有三种用法:

    1.普通的直接引用

    与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。

    2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分

    class Person{
        protected String name;
     
        public Person(String name) {
            this.name = name;
        }
     
    }
     
    class Student extends Person{
        private String name;
     
        public Student(String name, String name1) {
            super(name);
            this.name = name1;
        }
     
        public void getInfo(){
            System.out.println(this.name);      //Child
            System.out.println(super.name);     //Father
        }
     
    }
    
    public class Test {
        public static void main(String[] args) {
           Student s1 = new Student("Father","Child");
           s1.getInfo();
     
        }
    }
    

    3.引用父类构造函数

    3、引用父类构造函数

    • super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
    • this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。

    this与super的区别

    • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
    • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
    • super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
    • super()和this()均需放在构造方法内第一行。
    • 尽管可以用this调用一个构造器,但却不能调用两个。
    • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
    • this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
    • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

    static存在的主要意义

    static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法

    static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

    为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

    static的独特之处

    1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享

    怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】…我觉得我已经讲的很通俗了,你明白了咩?

    2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。

    3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!

    4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。

    static应用场景

    因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量

    因此比较常见的static应用场景有:

    1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包

    static注意事项

    1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。

    流程控制语句

    break ,continue ,return 的区别及作用

    break 跳出总上一层循环,不再执行循环(结束当前的循环体)

    continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)

    return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)

    在 Java 中,如何跳出当前的多重嵌套循环

    在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。例如:

    public static void main(String[] args) {
        ok:
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                System.out.println("i=" + i + ",j=" + j);
                if (j == 5) {
                    break ok;
                }
    
            }
        }
    }
    

    面向对象

    面向对象概述

    面向对象和面向过程的区别

    面向过程

    优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

    缺点:没有面向对象易维护、易复用、易扩展

    面向对象

    优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护

    缺点:性能比面向过程低

    面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

    面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

    面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。

    面向对象三大特性

    面向对象的特征有哪些方面

    面向对象的特征主要有以下几个方面

    抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

    封装

    封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。

    继承

    继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。

    关于继承如下 3 点请记住:

    1. 子类拥有父类非 private 的属性和方法。

    2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

    3. 子类可以用自己的方式实现父类的方法。(以后介绍)。

    多态

    所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

    在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

    其中Java 面向对象编程三大特性:封装 继承 多态

    封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。

    继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承可以提高代码复用性。继承是多态的前提。

    关于继承如下 3 点请记住

    1. 子类拥有父类非 private 的属性和方法。

    2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

    3. 子类可以用自己的方式实现父类的方法。

    多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。

    在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

    方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。

    一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:

    • 方法重写(子类继承父类并重写父类中已有的或抽象的方法);
    • 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

    什么是多态机制?Java语言是如何实现多态的?

    所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

    多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

    多态的实现

    Java实现多态有三个必要条件:继承、重写、向上转型。

    继承:在多态中必须存在有继承关系的子类和父类。

    重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

    向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

    只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

    对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

    面向对象五大基本原则是什么(可选)

    • 单一职责原则SRP(Single Responsibility Principle)
      类的功能要单一,不能包罗万象,跟杂货铺似的。
    • 开放封闭原则OCP(Open-Close Principle)
      一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
    • 里式替换原则LSP(the Liskov Substitution Principle LSP)
      子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
    • 依赖倒置原则DIP(the Dependency Inversion Principle DIP)
      高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
    • 接口分离原则ISP(the Interface Segregation Principle ISP)
      设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。

    类与接口

    抽象类和接口的对比

    抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。

    从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

    相同点

    • 接口和抽象类都不能实例化
    • 都位于继承的顶端,用于被其他实现或继承
    • 都包含抽象方法,其子类都必须覆写这些抽象方法

    不同点

    参数抽象类接口
    声明抽象类使用abstract关键字声明接口使用interface关键字声明
    实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现
    构造器抽象类可以有构造器接口不能有构造器
    访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者 protected
    多继承一个类最多只能继承一个抽象类一个类可以实现多个接口
    字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final 的

    备注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。

    现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。

    接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:

    • 行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量少用抽象类。
    • 选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能。

    普通类和抽象类有哪些区别?

    • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
    • 抽象类不能直接实例化,普通类可以直接实例化。

    抽象类能使用 final 修饰吗?

    不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

    创建一个对象用什么关键字?对象实例与对象引用有何不同?

    new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)

    变量与方法

    成员变量与局部变量的区别有哪些

    变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域

    成员变量:方法外部,类内部定义的变量

    局部变量:类的方法中的变量。

    成员变量和局部变量的区别

    作用域

    成员变量:针对整个类有效。
    局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)

    存储位置

    成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
    局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。

    生命周期

    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:当方法调用完,或者语句结束后,就自动释放。

    初始值

    成员变量:有默认初始值。

    局部变量:没有默认初始值,使用前必须赋值。

    使用原则

    在使用变量时需要遵循的原则为:就近原则
    首先在局部范围找,有就使用;接着在成员位置找。

    在Java中定义一个不做事且没有参数的构造方法的作用

    Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。

    在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?

    帮助子类做初始化工作。

    一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?

    主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。

    构造方法有哪些特性?

    名字与类名相同;

    没有返回值,但不能用void声明构造函数;

    生成类的对象时自动执行,无需调用。

    静态变量和实例变量区别

    静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

    实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

    静态变量与普通变量区别

    static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

    还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。

    静态方法和实例方法有何不同?

    静态方法和实例方法的区别主要体现在两个方面:

    1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
    2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制

    在一个静态方法内调用一个非静态成员为什么是非法的?

    由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。

    什么是方法的返回值?返回值的作用是什么?

    方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!

    内部类

    什么是内部类?

    在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致。

    内部类的分类有哪些

    内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类

    静态内部类

    定义在类内部的静态类,就是静态内部类。

    public class Outer {
    
        private static int radius = 1;
    
        static class StaticInner {
            public void visit() {
                System.out.println("visit outer static  variable:" + radius);
            }
        }
    }
    

    静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类(),如下:

    Outer.StaticInner inner = new Outer.StaticInner();
    inner.visit();
    
    成员内部类

    定义在类内部,成员位置上的非静态类,就是成员内部类。

    public class Outer {
    
        private static  int radius = 1;
        private int count =2;
        
         class Inner {
            public void visit() {
                System.out.println("visit outer static  variable:" + radius);
                System.out.println("visit outer   variable:" + count);
            }
        }
    }
    

    成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如下:

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();
    inner.visit();
    
    局部内部类

    定义在方法中的内部类,就是局部内部类。

    public class Outer {
    
        private  int out_a = 1;
        private static int STATIC_b = 2;
    
        public void testFunctionClass(){
            int inner_c =3;
            class Inner {
                private void fun(){
                    System.out.println(out_a);
                    System.out.println(STATIC_b);
                    System.out.println(inner_c);
                }
            }
            Inner  inner = new Inner();
            inner.fun();
        }
        public static void testStaticFunctionClass(){
            int d =3;
            class Inner {
                private void fun(){
                    // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
                    System.out.println(STATIC_b);
                    System.out.println(d);
                }
            }
            Inner  inner = new Inner();
            inner.fun();
        }
    }
    

    定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类(),如下:

     public static void testStaticFunctionClass(){
        class Inner {
        }
        Inner  inner = new Inner();
     }
    
    匿名内部类

    匿名内部类就是没有名字的内部类,日常开发中使用的比较多。

    public class Outer {
    
        private void test(final int i) {
            new Service() {
                public void method() {
                    for (int j = 0; j < i; j++) {
                        System.out.println("匿名内部类" );
                    }
                }
            }.method();
        }
     }
     //匿名内部类必须继承或实现一个已有的接口 
     interface Service{
        void method();
    }
    

    除了没有名字,匿名内部类还有以下特点:

    • 匿名内部类必须继承一个抽象类或者实现一个接口。
    • 匿名内部类不能定义任何静态成员和静态方法。
    • 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
    • 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

    匿名内部类创建方式:

    new/接口{ 
      //匿名内部类实现部分
    }
    

    内部类的优点

    我们为什么要使用内部类呢?因为它有以下优点:

    • 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
    • 内部类不为同一包的其他类所见,具有很好的封装性;
    • 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
    • 匿名内部类可以很方便的定义回调。

    内部类有哪些应用场景

    1. 一些多算法场合
    2. 解决一些非面向对象的语句块。
    3. 适当使用内部类,使得代码更加灵活和富有扩展性。
    4. 当某个类除了它的外部类,不再被其他的类使用时。

    局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?

    局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final呢?它内部原理是什么呢?

    先看这段代码:

    public class Outer {
    
        void outMethod(){
            final int a =10;
            class Inner {
                void innerMethod(){
                    System.out.println(a);
                }
    
            }
        }
    }
    

    以上例子,为什么要加final呢?是因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。

    内部类相关,看程序说出运行结果

    public class Outer {
        private int age = 12;
    
        class Inner {
            private int age = 13;
            public void print() {
                int age = 14;
                System.out.println("局部变量:" + age);
                System.out.println("内部类变量:" + this.age);
                System.out.println("外部类变量:" + Outer.this.age);
            }
        }
    
        public static void main(String[] args) {
            Outer.Inner in = new Outer().new Inner();
            in.print();
        }
    
    }
    

    运行结果:

    局部变量:14
    内部类变量:13
    外部类变量:12
    

    重写与重载

    构造器(constructor)是否可被重写(override)

    构造器不能被继承,因此不能被重写,但可以被重载。

    重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

    方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

    重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

    重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。

    对象相等判断

    == 和 equals 的区别是什么

    == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

    equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

    情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。

    情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

    举个例子:

    public class test1 {
        public static void main(String[] args) {
            String a = new String("ab"); // a 为一个引用
            String b = new String("ab"); // b为另一个引用,对象的内容一样
            String aa = "ab"; // 放在常量池中
            String bb = "ab"; // 从常量池中查找
            if (aa == bb) // true
                System.out.println("aa==bb");
            if (a == b) // false,非同一对象
                System.out.println("a==b");
            if (a.equals(b)) // true
                System.out.println("aEQb");
            if (42 == 42.0) { // true
                System.out.println("true");
            }
        }
    }
    

    说明:

    • String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
    • 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。

    hashCode 与 equals (重要)

    HashSet如何检查重复

    两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

    hashCode和equals方法的关系

    面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”

    hashCode()介绍

    hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。

    散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

    为什么要有 hashCode

    我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode

    当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

    hashCode()与equals()的相关规定

    如果两个对象相等,则hashcode一定也是相同的

    两个对象相等,对两个对象分别调用equals方法都返回true

    两个对象有相同的hashcode值,它们也不一定是相等的

    因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖

    hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

    对象的相等与指向他们的引用相等,两者有什么不同?

    对象的相等 比的是内存中存放的内容是否相等而 引用相等 比较的是他们指向的内存地址是否相等。

    值传递

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递

    是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的

    为什么 Java 中只有值传递

    首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。

    Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

    下面通过 3 个例子来给大家说明

    example 1

    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;
    
        swap(num1, num2);
    
        System.out.println("num1 = " + num1);
        System.out.println("num2 = " + num2);
    }
    
    public static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
    

    结果

    a = 20
    b = 10
    num1 = 10
    num2 = 20
    

    解析

    img

    在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。

    通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样,请看 example2.

    example 2

        public static void main(String[] args) {
            int[] arr = { 1, 2, 3, 4, 5 };
            System.out.println(arr[0]);
            change(arr);
            System.out.println(arr[0]);
        }
    
        public static void change(int[] array) {
            // 将数组的第一个元素变为0
            array[0] = 0;
        }
    

    结果

    1
    0
    

    解析

    img

    array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。

    通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。

    很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。

    example 3

    public class Test {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Student s1 = new Student("小张");
            Student s2 = new Student("小李");
            Test.swap(s1, s2);
            System.out.println("s1:" + s1.getName());
            System.out.println("s2:" + s2.getName());
        }
    
        public static void swap(Student x, Student y) {
            Student temp = x;
            x = y;
            y = temp;
            System.out.println("x:" + x.getName());
            System.out.println("y:" + y.getName());
        }
    }
    

    结果

    x:小李
    y:小张
    s1:小张
    s2:小李
    

    解析

    交换之前:

    img

    交换之后:

    img

    通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝

    总结

    Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。

    下面再总结一下Java中方法参数的使用情况:

    • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
    • 一个方法可以改变一个对象参数的状态。
    • 一个方法不能让对象参数引用一个新的对象。

    值传递和引用传递有什么区别

    值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。

    引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

    Java包

    JDK 中常用的包有哪些

    • java.lang:这个是系统的基础类;
    • java.io:这里面是所有输入输出有关的类,比如文件操作等;
    • java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
    • java.net:这里面是与网络有关的类;
    • java.util:这个是系统辅助类,特别是集合类;
    • java.sql:这个是数据库操作的类。

    import java和javax有什么区别

    刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。

    所以,实际上java和javax没有区别。这都是一个名字。

    IO流

    java 中 IO 流分为几种?

    • 按照流的流向分,可以分为输入流和输出流;
    • 按照操作单元划分,可以划分为字节流和字符流;
    • 按照流的角色划分为节点流和处理流。

    Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

    • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
    • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

    按操作方式分类结构图:

    IO-操作方式分类

    按操作对象分类结构图:

    IO-操作对象分类

    BIO,NIO,AIO 有什么区别?

    简答

    • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
    • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
    • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

    详细回答

    • BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
    • NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 SocketServerSocket 相对应的 SocketChannelServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
    • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

    Files的常用方法都有哪些?

    • Files. exists():检测文件路径是否存在。
    • Files. createFile():创建文件。
    • Files. createDirectory():创建文件夹。
    • Files. delete():删除一个文件或目录。
    • Files. copy():复制文件。
    • Files. move():移动文件。
    • Files. size():查看文件个数。
    • Files. read():读取文件。
    • Files. write():写入文件。

    反射

    什么是反射机制?

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    静态编译和动态编译

    • **静态编译:**在编译时确定类型,绑定对象
    • **动态编译:**运行时确定类型,绑定对象

    反射机制优缺点

    • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
    • 缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

    反射机制的应用场景有哪些?

    反射是框架设计的灵魂。

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

    举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

    Java获取反射的三种方法

    1.通过new对象实现反射机制 2.通过路径实现反射机制 3.通过类名实现反射机制

    public class Student {
        private int id;
        String name;
        protected boolean sex;
        public float score;
    }
    
    public class Get {
        //获取反射机制三种方式
        public static void main(String[] args) throws ClassNotFoundException {
            //方式一(通过建立对象)
            Student stu = new Student();
            Class classobj1 = stu.getClass();
            System.out.println(classobj1.getName());
            //方式二(所在通过路径-相对路径)
            Class classobj2 = Class.forName("fanshe.Student");
            System.out.println(classobj2.getName());
            //方式三(通过类名)
            Class classobj3 = Student.class;
            System.out.println(classobj3.getName());
        }
    }
    

    网络编程

    网络编程的面试题可以查看我的这篇文章重学TCP/IP协议和三次握手四次挥手,内容不仅包括TCP/IP协议和三次握手四次挥手的知识,还包括计算机网络体系结构,HTTP协议,get请求和post请求区别,session和cookie的区别等,欢迎大家阅读。

    常用API

    String相关

    字符型常量和字符串常量的区别

    1. 形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
    2. 含义上: 字符常量相当于一个整形值(ASCII值),可以参加表达式运算 字符串常量代表一个地址值(该字符串在内存中存放位置)
    3. 占内存大小 字符常量只占两个字节 字符串常量占若干个字节(至少一个字符结束标志)

    什么是字符串常量池?

    字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

    String 是最基本的数据类型吗

    不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。

    这是很基础的东西,但是很多初学者却容易忽视,Java 的 8 种基本数据类型中不包括 String,基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’,‘好’ 之类的,如果要描述一段文本,就需要用多个 char 类型的变量,也就是一个 char 类型数组,比如“你好” 就是长度为2的数组 char[] chars = {‘你’,‘好’};

    但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

    String有哪些特性

    • 不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。

    • 常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。

    • final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。

    String为什么是不可变的吗?

    简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下图所以:

    /** The value is used for character storage. */
    private final char value[];
    

    String真的是不可变的吗?

    我觉得如果别人问这个问题的话,回答不可变就可以了。 下面只是给大家看两个有代表性的例子:

    1) String不可变但不代表引用不可以变

    String str = "Hello";
    str = str + " World";
    System.out.println("str=" + str);
    

    结果:

    str=Hello World
    

    解析:

    实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。

    2) 通过反射是可以修改所谓的“不可变”对象

    // 创建字符串"Hello World", 并赋给引用s
    String s = "Hello World";
    
    System.out.println("s = " + s); // Hello World
    
    // 获取String类中的value字段
    Field valueFieldOfString = String.class.getDeclaredField("value");
    
    // 改变value属性的访问权限
    valueFieldOfString.setAccessible(true);
    
    // 获取s对象上的value属性的值
    char[] value = (char[]) valueFieldOfString.get(s);
    
    // 改变value所引用的数组中的第5个字符
    value[5] = '_';
    
    System.out.println("s = " + s); // Hello_World
    

    结果:

    s = Hello World
    s = Hello_World
    

    解析:

    用反射可以访问私有成员, 然后反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。但是一般我们不会这么做,这里只是简单提一下有这个东西。

    是否可以继承 String 类

    String 类是 final 类,不可以被继承。

    String str="i"与 String str=new String(“i”)一样吗?

    不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

    String s = new String(“xyz”);创建了几个字符串对象

    两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

    String str1 = "hello"; //str1指向静态区
    String str2 = new String("hello");  //str2指向堆上的对象
    String str3 = "hello";
    String str4 = new String("hello");
    System.out.println(str1.equals(str2)); //true
    System.out.println(str2.equals(str4)); //true
    System.out.println(str1 == str3); //true
    System.out.println(str1 == str2); //false
    System.out.println(str2 == str4); //false
    System.out.println(str2 == "hello"); //false
    str2 = str1;
    System.out.println(str2 == "hello"); //true
    

    如何将字符串反转?

    使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

    示例代码:

    // StringBuffer reverse
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer. append("abcdefg");
    System. out. println(stringBuffer. reverse()); // gfedcba
    // StringBuilder reverse
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder. append("abcdefg");
    System. out. println(stringBuilder. reverse()); // gfedcba
    

    数组有没有 length()方法?String 有没有 length()方法

    数组没有 length()方法 ,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

    String 类的常用方法都有那些?

    • indexOf():返回指定字符的索引。
    • charAt():返回指定索引处的字符。
    • replace():字符串替换。
    • trim():去除字符串两端空白。
    • split():分割字符串,返回一个分割后的字符串数组。
    • getBytes():返回字符串的 byte 类型数组。
    • length():返回字符串长度。
    • toLowerCase():将字符串转成小写字母。
    • toUpperCase():将字符串转成大写字符。
    • substring():截取字符串。
    • equals():字符串比较。

    在使用 HashMap 的时候,用 String 做 key 有什么好处?

    HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

    String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的

    可变性

    String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。

    线程安全性

    String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

    性能

    每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

    对于三者使用的总结

    如果要操作少量的数据用 = String

    单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

    多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

    Date相关

    包装类相关

    自动装箱与拆箱

    装箱:将基本类型用它们对应的引用类型包装起来;

    拆箱:将包装类型转换为基本数据类型;

    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

    Integer a= 127 与 Integer b = 127相等吗

    对于对象引用类型:==比较的是对象的内存地址。
    对于基本数据类型:==比较的是值。

    如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false

    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比较
        System.out.println(b == c); // true
    
        Integer a1 = 128;
        Integer b1 = 128;
        System.out.println(a1 == b1); // false
    
        Integer a2 = 127;
        Integer b2 = 127;
        System.out.println(a2 == b2); // true
    }
    

    常用工具类库

    单元测试

    日志

    展开全文
  • 若一个Dynamic Web project的java build path的projects中包括其他的project,发布此Dynamic Web project到Tomcat去的时候不会默认同时发布其他的被引用的project。 需要选择此Dynamic Web project的Properties中的...
    若一个Dynamic Web project的java build path的projects中包括其他的project,发布此Dynamic Web project到Tomcat去的时候不会默认同时发布其他的被引用的project。
    
    需要选择此Dynamic Web project的Properties中的Java EE Module Dependencies列出的引用project,选中的project将会打包成jar文件发布到lib文件夹中。
    展开全文
  • MyBatis面试题(2020最新版)

    万次阅读 多人点赞 2019-09-24 16:40:33
    提供对象关系映射标签,支持对象关系组件维护 能够与Spring很好的集成 缺点 SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求 SQL语句依赖于数据库,导致数据库移植性差...
  • 1.Maven常见的打包方式有:jar、war、pom pom工程一般都是父工程,管理jar包的版本、maven插件的版本、统一的依赖管理,是一个聚合工程。 jar工程,很显然就是pom工程的子工程,由pom工程来管理。 war工程,是web...
  • ## 之前我导入依赖都是直接在父工程的pom.xml文件里导入的。 ## 子工程不需要倒任何依赖,直接就可以写代码。 | ## 但是这次写了个 Spring Cloud Config 相关的程序, ## 一直报错。 | | # 做了多次的对比和...
  • 今天主要说说TomCat这个Web服务器,其实Web服务器有许多JBoss(Redhat红帽)、GlassFish(Orcale)、Resin(Caucho)不过Apache的免费开源用的人比较多,今天就具体说说TomCat安装、配置,以及使用Eclipse来搭建Web...
  • IDEA 2021版新建Maven、TomCat工程

    千次阅读 2021-04-29 09:39:37
    文章目录2021版IDEA中Maven、TomCat配置1.基于Webapp创建一个Maven项目1.1 新建项目模板1.2 指定名称1.3 指定信息1.4 指定Maven地址1.5 构建成功1.6 在本地仓库的路径中可以看到刚刚下载的包1.7 查看配置1.8 新建两...
  • eclipse tomcat发布eclipse tomcat发布依赖的maven项目  前言:  大家都知道,在进行J2EE项目的开发过程中,在调试阶段如果只是修改了页面是不需要重启应用服务器的,比如不需要重启Tomcat。只需要在...
  • Java框架总结

    万次阅读 多人点赞 2020-01-17 14:14:13
    【MyBatis 基础知识总结 1】SQL注入 【MyBatis 基础知识总结 2】MyBatis-Plus MyBatis常用标签和注解(绝对经典) MyBatis事务管理 MyBatis逆向工程(Example + Criteria简介) MyBatis xml配置文件详解 Spring ...
  • 简单来说,就是来帮助你管理项目的一个工具,用来管理项目中需要用到的jar包,和工程之间的项目之间的关系的工具。 能够解决什么问题呢: 项目的开发过程包括,编译,测试,运行,打包,部署等步骤,对于这些...
  • JAVA框架

    千次阅读 2019-10-15 10:42:43
    如果是对象类型,ref=“需要引用的id值”,因此实现了对象与对象之间依赖关系、赋值null“name” > < null/>< /property>、赋值空值“name” > < value>< /value> 、集合类型赋值proprety中使用< set> < list> 等...
  • 面试

    千次阅读 2018-08-14 14:28:10
    事务脚本类(封装了业务的流程)、数据访问对象(DAO,封装了持久化操作)、数据传输对象(DTO,封装了失血/贫血领域对象),三者之间的关系是事务脚本类组合(聚合)数据访问对象,这二者都依赖了数据传输对象 ...
  • maven

    千次阅读 多人点赞 2018-07-11 16:03:00
    Maven的核心功能便是合理叙述项目间的依赖关系,通俗点讲,就是通过pom.xml文件的配置获取jar包,而不用手动去添加jar包 什么是maven项目 包含pom.xml的项目就是maven项目。 maven项目...
  • Linux总结

    千次阅读 多人点赞 2020-01-14 20:36:45
    严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。 1.3、企业级与个人操作系统区别 常用的企业级操作系统有: ...
  • SpringCloud

    千次阅读 2019-11-18 08:54:06
    服务与服务之间依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。 Zuul [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9JGSQYH-...
  • springMvc

    千次阅读 2019-11-14 16:40:22
    springMVC基于java实现的MVC的设计模式,通过把model,view,controller分离,将web层进行解耦,将复杂的逻辑清晰化,简化代码开发,方便开发人员之间的配合. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来...
  • 消息中间件MQ与RabbitMQ面试题(2020最新版)

    万次阅读 多人点赞 2020-03-01 11:11:21
    不关注乱序的应用实际大量存在 队列无序并不意味着消息无序 所以从业务层面来保证消息的顺序而不仅仅是依赖于消息系统,是一种更合理的方式。 消息的重复问题 造成消息重复的根本原因是:网络不可达。 所以解决这个...
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    架构师,开发工程师写出《概要设计说明书》High-level design(HLD) 内容:系统程序中的模块,子模块和他们之间的关系和接口 测试的工作:对HLD进行测试和评审A集成测试计划《集成测试计划书》B集成测试设计《集成...
  • Springboot

    千次阅读 2018-12-06 11:09:34
    SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接...
  • JAVA面试笔记

    千次阅读 多人点赞 2019-03-07 17:52:40
    控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。 容器:Spring 包含...
  • 目前在部署工程时,遇到了一个问题,报错信息如下: See Servlet Spec 2.3, ...经检测,是工程包中含有javax.servlet包的JAR包,造成与Tomcat自身的servlet-api.jar的冲突。 1.问题的原因: tomcat 启动后先将...
  • Solr

    千次阅读 2019-12-23 15:45:34
    什么是solr Solr 是Apache下的一个顶级开源项目,采用Java开发,它是...Solr可以独立运行,运行在Jetty、Tomcat等这些Servlet容器中,Solr 索引的实现方法很简单,用 POST 方法向 Solr 服务器发送一个描述 Field...
  • 依赖管理:自动的对工程中的所有依赖jar包下载 一键构建:使用maven提供的一些列命令,完整项目的测试,编译,打包,部署,运行功能 1.1 Maven命令 clean compile test package install deploy : 将项目发布到私服...
  • JavaWeb

    千次阅读 多人点赞 2017-12-26 09:09:24
    数据库都是关系数据库:存的是实体之间的关系,实体之间有哪些关系? 一对多 多对多 一对一 多表的设计: 一对多建表原则:在多的一方添加外键,指向一的一方的主键 多对多建表原则:创建一张中间表,中间表至少有...
  • 史上最全面Java面试汇总(面试题+答案)

    万次阅读 多人点赞 2018-07-06 14:09:25
    跨域不同 抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a" 关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是...
  • Tomcat 专题Tomcat 专题一内容1.Tomcat 基础1.1 web 概念1.2 常见的web服务器1.2.1 概念1.2.2 常见web服务器软件1.3 Tomcat 历史1.4 Tomcat 安装1.4.1 下载1.4.2 安装1.5 Tomcat 目录结构1.6 Tomcat 启动停止1.7 ...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,435
精华内容 9,374
关键字:

tomcat工程之间依赖