java基础

1、List(线性结构)

    ArrayList Object[] 数组实现,默认大小为 10 ,支持随机访问,连续内存空间,插入末尾时间复杂度 o(1),插入第 i 个位置时间复杂度 o(n - i)。扩容,大小变为 1.5 倍,Arrays.copyOf(底层 System.ArrayCopy),复制到新数组,指针指向新数组。
    Vector 类似 ArrayList,线程安全,扩容默认增长为原来的 2 倍,还可以指定增长空间长度。
    LinkedList 基于链表实现,1.7 为双向链表,1.6 为双向循环链表,取消循环更能分清头尾。

2、Map(K,V 对)

    HashMap
        底层数据结构,JDK 1.8 是数组 + 链表 + 红黑树,JDK 1.7 无红黑树。链表长度大于 8 时,转化为红黑树,优化查询效率。
        初始容量为 16,通过 tableSizeFor 保证容量为 2 的幂次方。寻址方式,高位异或,(n-1)&h 取模,优化速度。
        扩容机制,当元素数量大于容量 x 负载因子 0.75 时,容量扩大为原来的 2 倍,新建一个数组,然后转移到新数组。
        基于 Map 实现。
        线程不安全。
    HashMap (1.7) 多线程循环链表问题
        在多线程环境下,进行扩容时,1.7 下的 HashMap 会形成循环链表。
        怎么形成循环链表: 假设有一 HashMap 容量为 2 , 在数组下标 1 位置以 A -> B 链表形式存储。有一线程对该 map 做 put 操作,由于触发扩容条件,需要进行扩容。这时另一个线程也 put 操作,同样需要扩容,并完成了扩容操作,由于复制到新数组是头部插入,所以 1 位置变为 B -> A 。这时第一个线程继续做扩容操作,首先复制 A ,然后复制 B ,再判断 B.next 是否为空时,由于第二个线程做了扩容操作,导致 B.next = A,所以在将 A 放到 B 前,A.next 又等于 B ,导致循环链表出现。
    HashTable
        线程安全,方法基本全用 Synchronized 修饰。
        初始容量为 11 ,扩容为 2n + 1 。
        继承 Dictionary 类。
    ConcurrentHashMap
        线程安全的 HashMap。
        1.7 采用分段锁的形式加锁;1.8 使用 Synchronized 和 CAS 实现同步,若数组的 Node 为空,则通过 CAS 的方式设置值,不为空则加在链表的第一个节点。获取第一个元素是否为空使用 Unsafe 类提供的 getObjectVolatile 保证可见性。
        对于读操作,数组由 volatile 修饰,同时数组的元素为 Node,Node 的 K 使用 final 修饰,V 使用 volatile 修饰,下一个节点也用 volatile 修饰,保证多线程的可见性。
    LinkedHashMap LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。
    TreeMap 有序的 Map,红黑树结构,可以自定义比较器来进行排序。
    Collections.synchronizedMap 如何实现 Map 线程安全? 基于 Synchronized ,实际上就是锁住了当前传入的 Map 对象。

3、Set(唯一值)

    HashSet 基于 HashMap 实现,使用了 HashMap 的 K 作为元素存储,V 为 new Object() ,在 add() 方法中如果两个元素的 Hash 值相同,则通过 equals 方法比较是否相等。
    LinkedHashSet LinkedHashSet 继承于 HashSet,并且其内部是通过 LinkedHashMap 来实现的。
    TreeSet 红黑树实现有序唯一。

5、synchronized

19、造方法、成员变量初始化以及静态成员变量三者的初始化顺序?

先后顺序:静态成员变量、成员变量、构造方法。 详细的先后顺序:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。

20、接口和抽象类的相同点和区别?

相同点:

不同点:

21、为什么Java语言不支持多重继承?

22、Java提供的多态机制?

Java提供了两种用于多态的机制,分别是重载与覆盖。

23、重载与覆盖的区别?

24、final、finally和finalize的区别是什么?

25、出现在Java程序中的finally代码块是否一定会执行?

当遇到下面情况不会执行。

其它情况下,在try/catch/finally语句执行的时候,try块先执行,当有异常发生,catch和finally进行处理后程序就结束了,当没有异常发生,在执行完finally中的代码后,后面代码会继续执行。值得注意的是,当try/catch语句块中有return时,finally语句块中的代码会在return之前执行。如果try/catch/finally块中都有return语句,finally块中的return语句会覆盖try/catch模块中的return语句。

26、Java语言中关键字static的作用是什么?

static的主要作用有两个:

具体而言static又可分为4种使用方式:

27、Java代码块执行顺序

28、Java中一维数组和二维数组的声明方式?

一维数组的声明方式:

二维数组的声明方式:

其中type为基本数据类型或类,arrayName为数组名字

29、String和StringBuffer有什么区别?

String用于字符串操作,属于不可变类。String对象一旦被创建,其值将不能被改变。而StringBuffer是可变类,当对象创建后,仍然可以对其值进行修改。

30、判等运算符==与equals的区别?

== 比较的是引用,equals比较的是内容。

31、为什么要把String设计为不变量?

32、序列化是什么?

序列化是一种将对象转换成字节序列的过程,用于解决在对对象流进行读写操作时所引发的问题。序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要的时候把该流读取出来重新构造成一个相同的对象。

33、简述Java中Class对象

java中对象可以分为实例对象和Class对象,每一个类都有一个Class对象,其包含了与该类有关的信息。

获取Class对象的方法:

34、Java反射机制是什么?

Java反射机制是指在程序的运行过程中可以构造任意一个类的对象、获取任意一个类的成员变量和成员方法、获取任意一个对象所属的类信息、调用任意一个对象的属性和方法。反射机制使得Java具有动态获取程序信息和动态调用对象方法的能力。可以通过以下类调用反射API。

  • 修饰代码块 底层实现,通过 monitorenter & monitorexit 标志代码块为同步代码块。
  • 修饰方法 底层实现,通过 ACC_SYNCHRONIZED 标志方法是同步方法。
  • 修饰类 class 对象时,实际锁在类的实例上面。
  • 单例模式
  •     偏向锁,自旋锁,轻量级锁,重量级锁
            通过 synchronized 加锁,第一个线程获取的锁为偏向锁,这时有其他线程参与锁竞争,升级为轻量级锁,其他线程通过循环的方式尝试获得锁,称自旋锁。若果自旋的次数达到一定的阈值,则升级为重量级锁。
            需要注意的是,在第二个线程获取锁时,会先判断第一个线程是否仍然存活,如果不存活,不会升级为轻量级锁。

    6、Lock

        ReentrantLock
            基于 AQS (AbstractQueuedSynchronizer)实现,主要有 state (资源) + FIFO (线程等待队列) 组成。
            公平锁与非公平锁:区别在于在获取锁时,公平锁会判断当前队列是否有正在等待的线程,如果有则进行排队。
            使用 lock() 和 unLock() 方法来加锁解锁。
        ReentrantReadWriteLock
            同样基于 AQS 实现,内部采用内部类的形式实现了读锁(共享锁)和写锁 (排它锁)。
        非公平锁吞吐量高 在获取锁的阶段来分析,当某一线程要获取锁时,非公平锁可以直接尝试获取锁,而不是判断当前队列中是否有线程在等待。一定情况下可以避免线程频繁的上下文切换,这样,活跃的线程有可能获得锁,而在队列中的锁还要进行唤醒才能继续尝试获取锁,而且线程的执行顺序一般来说不影响程序的运行。

    7、volatile

        Java 内存模型

    image.png

        在多线程环境下,保证变量的可见性。使用了 volatile 修饰变量后,在变量修改后会立即同步到主存中,每次用这个变量前会从主存刷新。
        禁止 JVM 指令重排序。
        单例模式双重校验锁变量为什么使用 volatile 修饰? 禁止 JVM 指令重排序,new Object()分为三个步骤:申请内存空间,将内存空间引用赋值给变量,变量初始化。如果不禁止重排序,有可能得到一个未经初始化的变量。

    1). New

    一个新的线程被创建,还没开始运行。
    2). Runnable

    一个线程准备就绪,随时可以运行的时候就进入了 Runnable 状态。

    Runnable 状态可以是实际正在运行的线程,也可以是随时可以运行的线程。

    多线程环境下,每个线程都会被分配一个固定长度的 CPU 计算时间,每个线程运行一会儿就会停止让其他线程运行,这样才能让每个线程公平的运行。这些等待 CPU 和正在运行的线程就处于 Runnable 状态。
    3). Blocked

    例如一个线程在等待 I/O 资源,或者它要访问的被保护代码已经被其他线程锁住了,那么它就在阻塞 Blocked 状态,这个线程所需的资源到位后就转入 Runnable 状态。
    4). Waiting(无限期等待)

    如果一个线程在等待其他线程的唤醒,那么它就处于 Waiting 状态。以下方法会让线程进入等待状态:

        Object.wait()
        Thread.join()
        LockSupport.park()

    5). Timed Waiting(有期限等待)

    无需等待被其他线程显示唤醒,在一定时间后有系统自动唤醒。

    以下方法会让线程进入有限等待状态:

        Thread.sleep(sleeptime)
        Object.wait(timeout)
        Thread.join(timeout)
        LockSupport.parkNanos(timeout)
        LockSupport.parkUntil(timeout)

    6). Terminated

    一个线程正常执行完毕,或者意外失败,那么就结束了。
    5、 wait() 与 sleep()

        调用后线程进入 waiting 状态。
        wait() 释放锁,sleep() 没有释放锁。
        调用 wait() 后需要调用 notify() 或 notifyAll() 方法唤醒线程。
        wait() 方法声明在 Object 中,sleep() 方法声明在 Thread 中。

    6、 yield()

        调用后线程进入 runnable 状态。
        让出 CPU 时间片,之后有可能其他线程获得执行权,也有可能这个线程继续执行。

    7、 join()

        在线程 B 中调用了线程 A 的 Join()方法,直到线程 A 执行完毕后,才会继续执行线程 B。
        可以保证线程的顺序执行。
        join() 方法必须在 线程启动后调用才有意义。
        使用 wait() 方法实现。

    9、线程使用方式

        继承 Tread 类
        实现 Runnable 接口
        实现 Callable 接口:带有返回值

    10、线程池
    1、分类

        FixThreadPool 固定数量的线程池,适用于对线程管理,高负载的系统
        SingleThreadPool 只有一个线程的线程池,适用于保证任务顺序执行
        CacheThreadPool 创建一个不限制线程数量的线程池,适用于执行短期异步任务的小程序,低负载系统
        ScheduledThreadPool 定时任务使用的线程池,适用于定时任务

    11、线程池的几个重要参数

        int corePoolSize, 核心线程数
        int maximumPoolSize, 最大线程数
        long keepAliveTime, TimeUnit unit, 超过 corePoolSize 的线程的存活时长,超过这个时间,多余的线程会被回收。
        BlockingQueue workQueue, 任务的排队队列
        ThreadFactory threadFactory, 新线程的产生方式
        RejectedExecutionHandler handler) 拒绝策略

    12、线程池线程工作过程

    corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略

    13、什么情况下可以用到 B 树索引

    (1) 定义有主键的列一定要建立索引。因为主键可以加速定位到表中的某行

    (2) 定义有外键的列一定要建立索引。外键列通常用于表与表之间的连接,在其上创建索引可以加快表间的连接

    (3) 对于经常查询的数据列最好建立索引。

    ① 对于需要在指定范围内快速或频繁查询的数据列,因为索引已经排序,其指定的范围是连续的,查询可以利用索引的排序,加快查询的时间

    ② 经常用在 where 子句中的数据列,将索引建立在 where 子句的集合过程中,对于需要加速或频繁检索的数据列,可以让这些经常参与查询的数据列按照索引的排序进行查询,加快查询的时间。

  • 14、事务隔离级别

        Read uncommitted 读未提交,可能出现脏读,不可重复读,幻读。
        Read committed 读提交,可能出现不可重复读,幻读。
        Repeatable read 可重复读,可能出现脏读。
        Serializable 可串行化,同一数据读写都加锁,避免脏读,。

  • 15、Bean 的作用域

    |:---|:---| | 类别 | 说明 | |singleton| 默认在 Spring 容器中仅存在一个实例 | |prototype| 每次调用 getBean() 都重新生成一个实例 | |request| 为每个 HTTP 请求生成一个实例 | |session| 同一个 HTTP session 使用一个实例,不同 session 使用不同实例 |
    2、Bean 生命周期

    简单来说四步:

            实例化 Instantiation
            属性赋值 Populate
            初始化 Initialization
            销毁 Destruction

    在这四步的基础上面,Spring 提供了一些拓展点:

        Bean 自身的方法: 这个包括了 Bean 本身调用的方法和通过配置文件中 %3Cbean %3E 的 init-method 和 destroy-method 指定的方法
        Bean 级生命周期接口方法: 这个包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法
        容器级生命周期接口方法:这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
        工厂后处理器接口方法: 这个包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

    16、Spring AOP

    实现方式两种:

        JDK 动态代理:带有接口的对象,在运行期实现
        CGlib 静态代理:在编译期实现。

    17、Spring 事务传播行为

    默认 PROPAGATION_REQUIRED ,如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

    18、简述Java访问修饰符

  • default: 默认访问修饰符,在同一包内可见
  • private: 在同一类内可见,不能修饰类
  • protected : 对同一包内的类和所有子类可见,不能修饰类
  • public: 对所有类可见
  • 都不能被实例化。
  • 接口的实现类或抽象类的子类需实现接口或抽象类中相应的方法才能被实例化。
  • 接口只能有方法定义,不能有方法的实现,而抽象类可以有方法的定义与实现。
  • 实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,只能继承一个抽象类。
  • 当子类和父类之间存在逻辑上的层次结构,推荐使用抽象类,有利于功能的累积。当功能不需要,希望支持差别较大的两个或更多对象间的特定交互行为,推荐使用接口。使用接口能降低软件系统的耦合度,便于日后维护或添加删除方法。
  • 为了程序的结构能够更加清晰从而便于维护。假设Java语言支持多重继承,类C继承自类A和类B,如果类A和B都有自定义的成员方法f(),那么当代码中调用类C的f()会产生二义性。Java语言通过实现多个接口间接支持多重继承,接口由于只包含方法定义,不能有方法的实现,类C继承接口A与接口B时即使它们都有方法f(),也不能直接调用方法,需实现具体的f()方法才能调用,不会产生二义性。
  • 多重继承会使类型转换、构造方法的调用顺序变得复杂,会影响到性能。
  • 重载:重载是指同一个类中有多个同名的方法,但这些方法有不同的参数,在编译期间就可以确定调用哪个方法。
  • 覆盖:覆盖是指派生类重写基类的方法,使用基类指向其子类的实例对象,或接口的引用变量指向其实现类的实例对象,在程序调用的运行期根据引用变量所指的具体实例对象调用正在运行的那个对象的方法,即需要到运行期才能确定调用哪个方法。
  • 覆盖是父类与子类之间的关系,是垂直关系;重载是同一类中方法之间的关系,是水平关系。
  • 覆盖只能由一个方法或一对方法产生关系;重载是多个方法之间的关系。
  • 覆盖要求参数列表相同;重载要求参数列表不同。
  • 覆盖中,调用方法体是根据对象的类型来决定的,而重载是根据调用时实参表与形参表来对应选择方法体。
  • 重载方法可以改变返回值的类型,覆盖方法不能改变返回值的类型。
  • final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、类不可继承。
  • finally作为异常处理的一部分,只能在try/catch语句中使用,finally附带一个语句块用来表示这个语句最终一定被执行,经常被用在需要释放资源的情况下。
  • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的finalize()方法。当垃圾回收器准备好释放对象占用空间时,首先会调用finalize()方法,并在下一次垃圾回收动作发生时真正回收对象占用的内存。
  • 当程序在进入try语句块之前就出现异常时会直接结束。
  • 当程序在try块中强制退出时,如使用System.exit(0),也不会执行finally块中的代码。
  • 为某种特定数据类型或对象分配与创建对象个数无关的单一的存储空间。
  • 使得某个方法或属性与类而不是对象关联在一起,即在不创建对象的情况下可通过类直接调用方法或使用类的属性。
  • 修饰成员变量。用static关键字修饰的静态变量在内存中只有一个副本。只要静态变量所在的类被加载,这个静态变量就会被分配空间,可以使用''类.静态变量''和''对象.静态变量''的方法使用。
  • 修饰成员方法。static修饰的方法无需创建对象就可以被调用。static方法中不能使用this和super关键字,不能调用非static方法,只能访问所属类的静态成员变量和静态成员方法。
  • 修饰代码块。JVM在加载类的时候会执行static代码块。static代码块常用于初始化静态变量。static代码块只会被执行一次。
  • 修饰内部类。static内部类可以不依赖外部类实例对象而被实例化。静态内部类不能与外部类有相同的名字,不能访问普通成员变量,只能访问外部类中的静态成员和静态成员方法。
  • 父类静态代码块(只执行一次)
  • 子类静态代码块(只执行一次)
  • 父类构造代码块
  • type arrayName[]
  • type[] arrayName
  • type arrayName[][]
  • type[][] arrayName
  • type[] arrayName[]
  • 如果变量是基础数据类型,== 用于比较其对应值是否相等。如果变量指向的是对象,== 用于比较两个对象是否指向同一块存储空间。
  • equals是Object类提供的方法之一,每个Java类都继承自Object类,所以每个对象都具有equals这个方法。Object类中定义的equals方法内部是直接调用 == 比较对象的。但通过覆盖的方法可以让它不是比较引用而是比较数据内容。
  • 节省空间:字符串常量存储在JVM的字符串池中可以被用户共享。
  • 提高效率:String会被不同线程共享,是线程安全的。在涉及多线程操作中不需要同步操作。
  • 安全:String常被用于用户名、密码、文件名等使用,由于其不可变,可避免黑客行为对其恶意修改。
  • Class.forName(“类的全限定名”)
  • 实例对象.getClass()
  • 类名.class
  • Class类:可获得类属性方法
  • Field类:获得类的成员变量
  • Method类:获取类的方法信息
  • Construct类:获取类的构造方法等信息
  • 父类构造函数
  • 子类构造代码块
  • 子类构造函数
  • 普通代码块

35简述Java异常的分类

40、简述自动装箱拆箱

对于Java基本数据类型,均对应一个包装类。

装箱就是自动将基本数据类型转换为包装器类型,如int->Integer

拆箱就是自动将包装器类型转换为基本数据类型,如Integer->int

41、简述重载与重写的区别

重写即子类重写父类的方法,方法对应的形参和返回值类型都不能变。

重载即在一个类中,方法名相同,参数类型或数量不同。

42、简述java的多态

Java多态可以分为编译时多态和运行时多态。

编译时多态主要指方法的重载,即通过参数列表的不同来区分不同的方法。

运行时多态主要指继承父类和实现接口时,可使用父类引用指向子类对象。

运行时多态的实现:主要依靠方法表,方法表中最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项,都被认作是父类的方法。因此可以实现运行时多态。

43、简述抽象类与接口的区别

抽象类:体现的是is-a的关系,如对于man is a person,就可以将person定义为抽象类。

接口:体现的是can的关系。是作为模板实现的。如设置接口fly,plane类和bird类均可实现该接口。

一个类只能继承一个抽象类,但可以实现多个接口。

44、简述==与equals方法的区别

对于==,在基本数据类型比较时,比较的是对应的值,对引用数据类型比较时,比较的是其内存的存放地址。

对于equals方法,在该方法未被重写时,其效果和==一致,但用户可以根据对应需求对判断逻辑进行改写,比如直接比较对象某个属性值是否相同,相同则返回true,不同则返回false。需保证equals方法相同对应的对象hashCode也相同。

45、简述Object类常用方法

46、简述内部类及其作用

47、简述String/StringBuffer与StringBuilder

String类采用利用final修饰的字符数组进行字符串保存,因此不可变。如果对String类型对象修改,需要新建对象,将老字符和新增加的字符一并存进去。

StringBuilder,采用无final修饰的字符数组进行保存,因此可变。但线程不安全。

StringBuffer,采用无final修饰的字符数组进行保存,可理解为实现线程安全的StringBuilder。

48、简述Java序列化与反序列化的实现

序列化:将java对象转化为字节序列,由此可以通过网络对象进行传输。

反序列化:将字节序列转化为java对象。

具体实现:实现Serializable接口,或实现Externalizable接口中的writeExternal()与readExternal()方法。

49、简述JAVA的List

List是一个有序队列,在JAVA中有两种实现方式:

ArrayList 使用数组实现,是容量可变的非线程安全列表,随机访问快,集合扩容时会创建更大的数组,把原有数组复制到新数组。

LinkedList 本质是双向链表,与 ArrayList 相比插入和删除速度更快,但随机访问元素很慢。

50、Java中线程安全的基本数据结构有哪些

HashTable: 哈希表的线程安全版,效率低 ConcurrentHashMap:哈希表的线程安全版,效率高,用于替代HashTable Vector:线程安全版Arraylist Stack:线程安全版栈 BlockingQueue及其子类:线程安全版队列

51简述JAVA的Set

Set 即集合,该数据结构不允许元素重复且无序。JAVA对Set有三种实现方式:

HashSet 通过 HashMap 实现,HashMap 的 Key 即 HashSet 存储的元素,Value系统自定义一个名为 PRESENT 的 Object 类型常量。判断元素是否相同时,先比较hashCode,相同后再利用equals比较,查询O(1)

LinkedHashSet 继承自 HashSet,通过 LinkedHashMap 实现,使用双向链表维护元素插入顺序。

TreeSet 通过 TreeMap 实现的,底层数据结构是红黑树,添加元素到集合时按照比较规则将其插入合适的位置,保证插入后的集合仍然有序。查询O(logn)

52、简述JAVA的HashMap

JDK8 之前底层实现是数组 + 链表,JDK8 改为数组 + 链表/红黑树。主要成员变量包括存储数据的 table 数组、元素数量 size、加载因子 loadFactor。 HashMap 中数据以键值对的形式存在,键对应的 hash 值用来计算数组下标,如果两个元素 key 的 hash 值一样,就会发生哈希冲突,被放到同一个链表上。

table 数组记录 HashMap 的数据,每个下标对应一条链表,所有哈希冲突的数据都会被存放到同一条链表,Node/Entry 节点包含四个成员变量:key、value、next 指针和 hash 值。在JDK8后链表超过8会转化为红黑树。

若当前数据/总数据容量>负载因子,Hashmap将执行扩容操作。 默认初始化容量为 16,扩容容量必须是 2 的幂次方、最大容量为 1<< 30 、默认加载因子为 0.75。

53、为何HashMap线程不安全

在JDK1.7中,HashMap采用头插法插入元素,因此并发情况下会导致环形链表,产生死循环。

虽然JDK1.8采用了尾插法解决了这个问题,但是并发下的put操作也会使前一个key被后一个key覆盖。

由于HashMap有扩容机制存在,也存在A线程进行扩容后,B线程执行get方法出现失误的情况。

54、简述java的TreeMap

TreeMap是底层利用红黑树实现的Map结构,底层实现是一棵平衡的排序二叉树,由于红黑树的插入、删除、遍历时间复杂度都为O(logN),所以性能上低于哈希表。但是哈希表无法提供键值对的有序输出,红黑树可以按照键的值的大小有序输出。

55、Collection和Collections有什么区别?

56、ArrayList、Vector和LinkedList有什么共同点与区别?

57、HashMap和Hashtable有什么区别?

58、如何决定使用HashMap还是TreeMap?

如果对Map进行插入、删除或定位一个元素的操作更频繁,HashMap是更好的选择。如果需要对key集合进行有序的遍历,TreeMap是更好的选择。

59、fail-fast和fail-safe迭代器的区别是什么?

60、HashSet中,equals与hashCode之间的关系?

equals和hashCode这两个方法都是从object类中继承过来的,equals主要用于判断对象的内存地址引用是否是同一个地址;hashCode根据定义的哈希规则将对象的内存地址转换为一个哈希码。HashSet中存储的元素是不能重复的,主要通过hashCode与equals两个方法来判断存储的对象是否相同:

  • Java异常分为Error(程序无法处理的错误),和Exception(程序本身可以处理的异常)。这两个类均继承Throwable。

    Error常见的有StackOverFlowError,OutOfMemoryError等等。

    Exception可分为运行时异常和非运行时异常。对于运行时异常,可以利用try catch的方式进行处理,也可以不处理。对于非运行时异常,必须处理,不处理的话程序无法通过编译。

    36、简述throw与throws的区别

    throw一般是用在方法体的内部,由开发者定义当程序语句出现问题后主动抛出一个异常。

    throws一般用于方法声明上,代表该方法可能会抛出的异常列表。

    37、简述泛型

    泛型,即“参数化类型”,解决不确定对象具体类型的问题。在编译阶段有效。在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型在类中称为泛型类、接口中称为泛型接口和方法中称为泛型方法。

    38、简述泛型擦除

    Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程被称为泛型擦除。

    39、简述Java基本数据类型

  • byte: 占用1个字节,取值范围-128 ~ 127
  • short: 占用2个字节,取值范围-2^15^ ~ 2^15^-1
  • int:占用4个字节,取值范围-2^31^ ~ 2^31^-1
  • long:占用8个字节
  • float:占用4个字节
  • double:占用8个字节
  • char: 占用2个字节
  • boolean:占用大小根据实现虚拟机不同有所差异
  • hashCode:通过对象计算出的散列码。用于map型或equals方法。 需要保证同一个对象多次调用该方法,总返回相同的整型值。
  • equals:判断两个对象是否一致。需保证equals方法相同对应的对象hashCode也相同。
  • toString: 用字符串表示该对象
  • clone:深拷贝一个对象
  • 成员内部类:作为成员对象的内部类。可以访问private及以上外部类的属性和方法。外部类想要访问内部类属性或方法时,必须要创建一个内部类对象,然后通过该对象访问内部类的属性或方法。外部类也可访问private修饰的内部类属性。
  • 局部内部类:存在于方法中的内部类。访问权限类似局部变量,只能访问外部类的final变量。
  • 匿名内部类:只能使用一次,没有类名,只能访问外部类的final变量。
  • 静态内部类:类似类的静态成员变量。
  • Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如List、Set等。
  • Collections是一个包装类,包含了很多静态方法、不能被实例化,而是作为工具类使用,比如提供的排序方法: Collections.sort(list);提供的反转方法:Collections.reverse(list)。
  • ArrayList、Vector和LinkedList都是可伸缩的数组,即可以动态改变长度的数组。
  • ArrayList和Vector都是基于存储元素的Object[] array来实现的,它们会在内存中开辟一块连续的空间来存储,支持下标、索引访问。但在涉及插入元素时可能需要移动容器中的元素,插入效率较低。当存储元素超过容器的初始化容量大小,ArrayList与Vector均会进行扩容。
  • Vector是线程安全的,其大部分方法是直接或间接同步的。ArrayList不是线程安全的,其方法不具有同步性质。LinkedList也不是线程安全的。
  • LinkedList采用双向列表实现,对数据索引需要从头开始遍历,因此随机访问效率较低,但在插入元素的时候不需要对数据进行移动,插入效率较高。
  • HashMap是Hashtable的轻量级实现,HashMap允许key和value为null,但最多允许一条记录的key为null.而HashTable不允许。
  • HashTable中的方法是线程安全的,而HashMap不是。在多线程访问HashMap需要提供额外的同步机制。
  • Hashtable使用Enumeration进行遍历,HashMap使用Iterator进行遍历。
  • fail-fast直接在容器上进行,在遍历过程中,一旦发现容器中的数据被修改,就会立刻抛出ConcurrentModificationException异常从而导致遍历失败。常见的使用fail-fast方式的容器有HashMap和ArrayList等。
  • fail-safe这种遍历基于容器的一个克隆。因此对容器中的内容修改不影响遍历。常见的使用fail-safe方式遍历的容器有ConcurrentHashMap和CopyOnWriteArrayList。
  • 如果两个对象的hashCode值不同,说明两个对象不相同。
  • 如果两个对象的hashCode值相同,接着会调用对象的equals方法,如果equlas方法的返回结果为true,那么说明两个对象相同,否则不相同。

61、文件IO流

FileInputStream 文件输入流

创建方法:

FileInputStream in = new FileInputStream("文件的完整路径");
FileInputStream in = new FileInputStream(File对象);

主要方法:

  • int read(byte[] buffer) 将文件数据读取到字节数组中,同时将文件指针向后移动,每次返回读取的长度,到文件末尾返回-1

  • void close() 关闭流

读取文件的步骤:

  1. 创建文件输入流

  2. 创建字节数组

  3. 循环将数据读取到字节数组中,直到返回-1

  4. 关闭流

62、迭代器 Iterator 是什么?

集合可以使用foreach方式进行遍历

迭代器接口,实现迭代器模式,目的是不用关注数据结构,就可以对任意数据结构进行遍历。

问题:

  1. 暴露了数据结构

  2. 不能使用通用的代码

63、ArrayList 和 Vector 的区别是什么?

  1. Vector是线程安全的,ArrayList是非线程安全的

  2. ArrayList性能高于Vector

  3. Vector的扩容量可以指定,如果不指定就扩容2倍;ArrayList扩容1.5倍

64、什么是反射?

Java中的一种高级技术,能够在程序运行时能够解析出任意类和对象的属性和方法,可以动态调用类和对象的所有属性和方法。

可以用于开发非常灵活和通用的代码

java.lang.reflect包

反射的步骤:

  1. 获得类的信息

  2. 获得类中的属性和方法

  3. 通过反射创建对象

  4. 通过反射调用属性和方法

###

反射首先需要获得类的信息 Class类的对象

三种方式:

  1. 类名.class

  2. 对象.getClass()

  3. Class.forName("包名+类名")

通过无参的构造方法创建对象

Object Class对象.newInstance()

通过构造方法创建对象

Constructor Class对象.getDeclaredConstructor
Object Constructor对象.newInstance

65、动态代理是什么?有哪些应用?

动态代理是在运行时,通过反射机制动态生成代理类。开发者不需要手动编写新的代理类。

Java的动态代理主要有两种实现:

1)JDK动态代理

2)CGLib动态代理

JDK自带的,前提是:被代理类必须实现过接口。

实现步骤

1) 实现InvocationHandler接口

2)实现invoke方法

3)通过Proxy.newProxyInstance方法返回代理对象

需要引入CGLib依赖,它的原理是:通过反射+继承机制动态生成被代理类的子类,所以被代理类不能是final的。

实现步骤

1)引入cglib

2)实现MethodInterceptor接口

3)实现intercept方法

4)通过Ehancer返回代理对象

66、怎么实现动态代理?

1) 当调用容器的getBean方法后,Spring查找对象后会判断该对象的方法是否被某个切面切中

2) 如果没有切中,就创建原有类的对象

3) 如果被切中了,再判断该类是否实现过任何接口

4) 如果实现过接口,则通过JDK动态代理生成代理类,并创建对象

5) 如果没有实现过接口,则通过CGLib动态代理生成代理类,并创建对象

67、为什么要实现克隆,如何实现对象克隆,深拷贝和浅拷贝的区别

浅复制

复制出来的对象,能复制所有基本类型以及String的属性,对于引用类型的属性只能复制地址

实现方式:clone

深复制

复制出来的对象,基本类型和引用类型的属性,都完全是不同的对象

实现方式:序列化和反序列化

68、jsp 和 servlet 有什么区别?

JSP的本质就是Servlet,JSP页面会转换为xxx_jsp.java的类,该类继承HttpJspBase类,HttpJspBase继承HttpServlet

JSP的执行过程

  1. 用户第一次访问JSP页面时,服务器会将JSP页面转换为Servlet类

  2. 创建Servlet类的实例,初始化

  3. 通过Servlet类的service方法将JSP中的HTML代码以流方式发送给浏览器

  4. 浏览器接收HTML代码后,解析出页面

Servlet是单实例多线程的,每个Servlet类在服务器中只会创建一个对象,每个用户访问时都会单独开一线程提供服务。

Servlet会存在线程安全问题,尽量不要在Servlet中定义成员变量,一定要定义也尽量不要修改。

Servlet的对象只会创建一次,默认在第一次被访问时创建

生命周期方法:

  • init 初始化(只执行一次)

  • service 服务(每次访问都会执行)

  • destory 销毁(服务器停止)

Servlet的生命周期过程:

1) 实例化(执行一次)

2) 执行初始化 init 方法(执行一次)

3) 用户每访问一次就调用service方法

4) 服务器停止后,自动调用destory方法

69、jsp 有哪些内置对象?作用分别是什么?

在jsp中定义的9个对象

四个域对象,可以在不同的范围内保存和读取数据

  • application ServletContext 应用程序上下文

    数据可以被任何用户访问,数据在服务器停止后释放

  • session HttpSession 回话对象

    数据可以被一个用户访问的多个Servlet和JSP共享,每个用户都有自己的session

  • request ServletHttpRequest 请求对象

    数据可以在一个请求中传递

  • pageContext PageContext 页面上下文

    数据只能在当前页面中访问

存:

setAttribute("名称",值)

取:

Object getAttribute("名称")

其它5个对象:

  • response ServletHttpResponse 响应对象

  • out JspWriter 输出流对象,向浏览器发送HTML数据

  • page 当前JSP对象,this

  • config ServletConfig 配置对象

  • exception Exception 异常对象 只能用于错误页 其它页面要指定errorPage

70、session 和 cookie 有什么区别?

  1. Session保存在服务器,Cookie保存在浏览器

  2. Session保存数据个数和大小没有限制,Cookie的个数和大小有限

  3. Session安全性高于Cookie

 

71、常见的异常类有哪些?

所有异常分为2种:

  • 运行时异常

    RuntimeException及其子类,属于非受检异常,程序不强制要求处理

  • 非运行时异常

    非RuntimeException及其子类,属于受检异常,程序强制要求处理

常见的运行时异常

  • ArrayIndexOutofBoundsException 下标越界异常

  • NullpointerException 空指针异常

  • ArithmeticException 数学异常

  • ClassCastException 类型转换异常

  • NumberFormatException 数字格式异常

  • ...

常见的非运行时异常

  • ParseException 日期格式解析异常

  • IOException 输入输出异常

  • SQLException 数据库异常

  • ...

72、如何实现跨域?

服务器自我保护的机制,会信任同一个服务器下的程序

协议://域名:端口

三个如果相同,则认为是一个域下,否则就是跨域

解决方案:

  1. 给服务器控制器加CrossOrigin注解,允许跨域

  2. 设置CORS规则

  3. JSONP

  4. IFrame

  5. ...

72、重写和重载的区别

重写和重载的区别

  1. 重写发生于子类和父类,重载是在一个类中

  2. 重写返回值类型,方法名,参数列表要完全相同;重载和返回值类型无关,方法名相同,参数列表不同

  3. 重写子类中方法的访问修饰符访问范围不能比父类低;重载和访问修饰符无关

  4. 作用不同,重写是子类改写父类的方法;重载是新增方法,让方法调用方便

73、MyBatis中#{}和${}的区别

#{}应用PreparedStatement的占位符?插入,能防止SQL注入

${}应用字符串的拼接,不能防止SQL注入

74、MyBatis缓存机制

MyBatis两级缓存

  1. 一级缓存

    范围:SqlSession

    同一个SqlSession对象访问的数据,可以被缓存,下次访问直接获得不用查数据库

    默认开启,Spring整合MyBatis默认是没有开启

    失效的情况:

    1)创建新的SQLSession

    2)对数据库中的对象进行修改

  2. 二级缓存

    范围:SQLSessionFactory

    同一个SqlSessionFactory创建的所有SQLSession能共享缓存对象

    默认开启

    1)cacheEnabled 配置为true

    2)在对应的映射文件上加<cache/>标签

    3)实体类需要序列化

75、arrayList扩容机制

每个ArrayList实例都有一个容量,该容量是指来存储列表元素的数组的大小,该容量至少等于列表数组的大小,随着ArrayList的不断添加元素,其容量也在自动增长,自动增长会将原来数组的元素向新的数组进行copy。如果提前预判数据量的大小,可在构造ArrayList时指定其容量。

1.ArrayList每次扩容是原来的1.5倍。

2.数组进行扩容时,会将老数据中的元素重新拷贝一份道新的数组中。

4.创建方式不同,容量不同。

76、SpringMVC获得页面参数值有几种方法?

1、参数直接绑定(直接定义和表单元素name相同的参数)

2、如果名称不一样,可以通过@RequestParam注解配置参数

3、通过对象也可以进行参数绑定

4、通过URL的路径也可以实现参数绑定,需要给参数添加@PathVariable注解

5、通过Map集合进行参数绑定

6、通过List集合进行参数绑定

77、SpringMVC将数据绑定页面有几种方法?

  1. 将数据保存到HttpServletRequest、HttpSession、ServletContext中

  2. 在参数中定义Model参数保存数据

  3. 在参数中定义Map参数保存数据

78、Linux的常用命令有哪些?

切换\查看目录

切换目录
cd 目录名
查看目录
ls 目录名(不写就是查看当前目录)
    -l  详细列表
    -a  所有文件
查看目录详情
ll 目录名

创建\删除目录

创建目录
mkdir 目录名
删除目录
rm    目录名
    -r  遍历所有子目录
    -f  强制删除

文件操作

CentOS自带vi命令来编辑文件

创建\打开文件
vi  文件名
三种模式:
    命令模式    能删除、复制、粘贴,无法编辑
    输入模式    编辑内容
    命令行模式  退出、保存文件
    操作方式:默认进入命令模式,按i进入输入模式,按esc回到命令模式,按:进入命令行模式
命令模式
    x   删除一个字符
    dd  删除一行
    yy  复制一行
    p   粘贴
    u   撤销
命令行模式
    wq  保存退出
    q   退出 (如果有修改,此方式退出会出错)
    q!  强制退出

查阅文件

cat  显示整个文件内容(不支持分页)
more 分页显示(只能向前分页查询)
less 分页显示,功能比more强大。(支持前后分页查询)
    支持文本查找,/查找内容  向下查询 ;  ?查找内容   向上查找内容
    退出less模式,点击q
    
    对比vi命令:cat、more、less仅仅是用来进行文本阅读命令,vi用来进行文本编辑的命令。
    
    查询当前文件中是否包含有java单词,如果包含有Java单词的所有行全部显示出来。
    cat 文件名 | grep 查询文字

查询文件或者文本内容

find 查找目录 -name 文件名称  
find 查找目录 | grep 名称  

查看命令所在目录

which 命令名称

移动/复制文件

移动文件
mv 原文件 目标文件
复制文件
cp 原文件 目标文件

压缩与解压缩

解压指令:tar -zxvf  
压缩指令:tar -zcvf 
-z:表示压缩和解压缩的格式为gz压缩文件(gzip)
-c::表示压缩
-x:表示解压缩
-v:表示显示压缩或者解压缩的详细过程。
-f:表示指定压缩或者解压缩的文件,只能放在命令的最后
tar -zcvf demo.tar.gz demo2.txt 
tar -cvf 压缩后的文件名称  待压缩的文件 
tar -xvf 待解压的解压包名 

查看端口和进程号

通过端口查看进程:netstat –apn | grep 8080
通过端口查看进程:lsof -i:3306
通过进程名称查询进程:ps -ef | grep redis
杀死进程:kill -9 PID(进程ID,-9表示强制杀死)

78、MySQL的索引是什么,有什么作用?

索引的作用

是一种数据,保存实际的数据的位置,能加快查询速度,用户查询时,先找索引,通过索引找到实际数据的位置,再直接定位到实际数据上。

索引的优缺点:

优点:

极大提高查询速度

缺点:

1. 也是数据,需要占存储空间
2. 降低增删改的速度
3. 创建索引也需要一定的时间

适合建索引的情况:

1. 表里面数据特别多
2. 建索引的列不能存在大量的重复,如:性别
3. 建索引的列不能频繁进行修改
4. 建索引的列不能存在大量的null值
5. 列经常用于做查询

索引分为:

  • 普通索引 没有约束效果

  • 主键索引 不能重复、不能为空、表中只能有一个

  • 唯一索引 不能重复

  • 全文索引 用于text长文本类型

  • 组合索引 在多个列建索引

索引失效的情况:

  1. 使用or关键字

  2. 模糊查询时,把%放前面,如: like '%张'

  3. 空值查询 is null 或 is not null

  4. 将列放到函数中 SUBSTR(stu_name,1) = '三'

  5. 组合索引,查询时没有包含第一列 (最左前缀原则:把最重要列放最左边)

-- 使用or连接条件,可能失效
explain select * from student where stu_name = '张三' or stu_age > 20;
-- 模糊查询时,%在前面会失效
explain select * from student where stu_name like '%张';
-- 做is not null 空值查询时,可能会失效
explain select * from student where stu_address is not null;
-- 将列放到函数中,可能会失效
explain select * from student where SUBSTR(stu_name,1) = '三';
-- 使用组合索引时,查询必须包含第一列(最左前缀原则:把最重要列,放最左边)
explain select * from student where stu_gender = '男';

索引的数据结构

索引的数据结构叫B-Tree,属于平衡搜索多叉树,可以进行二分查找,搜索效率高。

由多个节点组成,每个节点包含key和data,key是索引的键,data是键对应的数据,节点的两边还包含两个指针,指向其它索引的位置。

所有的键是排序过,使用二分查找,效率和树的高度相关,高度越高查找越慢。

B+Tree

B+Tree是B-Tree的升级,每个非叶子节点中不包含数据,将数据都存放在叶子节点中,每层包含更多键和指针,降低树的高度,从而提高查找效率。

80、Servelet的生命周期

Servlet是单实例多线程的,每个Servlet类在服务器中只会创建一个对象,每个用户访问时都会单独开一线程提供服务。

Servlet会存在线程安全问题,尽量不要在Servlet中定义成员变量,一定要定义也尽量不要修改。

(1)实例化(只执行一次)

(2)init 初始化(只执行一次)

(3)service 服务(每次访问都会执行)

(4)destory 销毁(服务器停止自动调用

81、会话跟踪的几种方式

什么是会话跟踪?

HTTP协议是无连接无状态的,服务器默认不会记录客户端的信息,有时候我们需要服务器保存客户端的信息,如:账号、浏览的商品、上次登录时间等

会话跟踪就是在服务器端保存用户的信息

怎么实现会话跟踪?

1) 隐藏表单域

将数据保存到隐藏域中,带到服务器端

<input type="hidden" name="名字" value="值">

2)URL重写

将数据保存到URL中,带到服务器

http://域名?参数名=值&参数名=值

3) Cookie

将数据保存到浏览器的Cookie中,带到服务器

4) Session

将数据保存到服务器的Session中

82、什么是Ajax,有什么作用,实现方式

Asynchornized JavaScript And Xml 异步的JavaScript和XML

是一种异步的前端通过JS和后端通信的技术

同步和异步的区别:

  • 同步通信是前端和后端通信的过程中,会产生阻塞,必须等待后端返回数据后,才能进行后续操作

缺点:用户会感觉卡顿,影响其它操作,体验不好

优点:编程相对容易

  • 异步通信不会产生阻塞,后端返回数据后会通知前端进行操作

    缺点:编程相对复杂

    优点:不卡顿、不影响其它操作、用户体验

84、JVM内存分配

本地方法栈 基本类型、局部变量、对象的引用

java堆 new出来的对象

方法区 类的信息、静态常量

本地方法区 本地方法(native)

计数器 记录当前线程的行数

85、软件开发的过程:

  1. 可行性分析(市场、技术、社会)

  2. 项目立项(启动大会,确定项目周期、团队、管理者)

  3. 需求分析(确定项目功能、界面等)

  4. 概要设计(架构设计、技术选型、数据库设计)

    数据库设计使用E-R图

    Entity-Relationship

  5. 详细设计(具体功能设计、接口设计、数据库设计)

    表的设计(表名、字段名、类型、约束、主外键关系)

    数据库字典

  6. 项目开发(数据库表的创建、代码的编写)

  7. 测试

  8. 上线

  9. 运维

86、SpringSecurity简介

安全框架,能够帮助实现权限控制,不同的用户能查看或操作不同的资源。

主流的安全框架:

  1. Shiro SSM配置少,容易上手

  2. SpringSecurity SpringBoot整合配置较少,强大

SpringSecurity是一个强大且高效的安全框架,能够提供用户验证和访问控制服务,能够很好地整合到以Spring为基础的项目中。 SpringBoot对SpringSecurity进行了大量的自动配置,使开发者通过少量的代码和配置就能完成很强大的验证和授权功能。

87、缓存机制

将数据库的数据保存到内存或磁盘上,查询数据时直接访问内存或磁盘,减少对数据库的访问。

缓存作用:

1)减少数据库的负担,因为数据库连接数有限,并发量大的情况下,数据库连接耗尽,造成用户长期等待或者数据库宕机。

2)提升性能,对数据库的访问是通过TCP/IP网络进行访问

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值