美文网首页
java 复习

java 复习

作者: dev晴天 | 来源:发表于2020-05-13 21:25 被阅读0次

    一、面向对象相关

    1、面向对象三大特征

    1、封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

    2、继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。

    3、多态:多态顾名思义“一种形式多种状态”说了等于白说。其实啥叫多态呢?或许可以这样说:子类对象持有父类或者接口类型的引用,在方法调用期间动态的改变。

    ps:参考文章1

    ps:参考文章2

    2、多态相关

    多态分类:

    1、编译时多态:方法重载2、运行时多态:方法重写(方法覆盖)

    方法重载:都是编译时多态。因为方法重载发生在一个类中。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。编译期就能确定,所以为编译期多态。

    方法覆盖:表现出两种多态性,当对象引用本类实例时(发生在一个类中例如:Dog dog = new Dog();dog调用本类方法。即使这个方法是覆盖父类中的。),为编译时多态,否则为运行时多态(Animal animal = new Dog() animal 运行时调用dog中覆盖父类中的方法)。

    ps:方法重写表现为两种多态性。

    多态的作用:

    消除类型之间的耦合关系。

    多态的发生条件:

    1、继承

    2、重写

    3、父类/接口引用指向子类对象

    多态好处:

    1、可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

    2、可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

    3、接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

    4、活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

    5、简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

    3、抽象类和接口区别

    1、默认的方法实现

    抽象类可以有默认的方法实现。接口完全是抽象的,接口根本不存在方法的实现

    2、实现

    抽象类的子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方抽象的方法的实现。接口子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现

    3、构造器

    抽象类可以有构造器,接口不能有构造器。(构造器就是为了初始化成员变量的)

    4、接口中不能定义构造器的理由:

    • 构造器用于初始化成员变量,接口没有成员变量
    • 类可以实现多个接口,若多个接口都有自己的构造器,则不好决定构造器链的调用次序
    • 构造器是属于类自己的,不能继承。因为是纯虚的,接口不需要构造器。

    5、和正常java类的区别

    抽象类除了你不能实例化抽象类之外,它和普通Java类没有任何区。接口是完全不同的类型

    6、访问修饰符

    抽象方法可以有public、protected和default这些修饰符。接口中方法默认public,你不可以使用其它修饰符。

    7、多继承

    抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。

    8、速度

    抽象类它比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

    9、添加新方法

    如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。

    4、父类的静态方法能否被子类重写

    不能:

    1、静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成对,不需要继承机制及可以调用。如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"(即使父类的静态成员和方法不是private的,子类中也有一样的静态方法,父类对象引用也调用不了,发生不了多态。所以父类的静态方法对子类来说是不能重写的这叫做隐藏)。如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是跟实例方法和属性不太一样,存在"隐藏"的这种情况。

    2、重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。

    答案参考

    5、方法重载和方法重写区别

    答案

    二、基础知识相关

    1、java中==和equals和hashCode的区别

    参考答案1

    答案2:为啥重写hashCode方法

    2、int、char、long各占多少字节数

    常见类型所占字节:

    byte 1

    short 2

    char 2

    int 4

    float 4

    long 8

    double 8

    boolean:理由是虽然编译后1和0只需占用1位空间,但计算机处理数据的最小单位是1个字节,1个字节等于8位,实际存储的空间是:用1个字节的最低位存储,其他7位用0填补

    3、int与integer的区别

    1、int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象

    2、int类型的变量初始为0.而Integer类的变量则初始化为null.

    3、int和Integer不能够互用,因为他们两种不同的数据类型(集合存数据时可以看出)

    4、如果我们定义一个int类型的数,只是用来进行一些加减乘除的运算or作为参数进行传递,那么就可以直接声明为int基本数据类型,但如果要像

    对象一样来进行处理,那么就要用Integer来声明一个对象,因为java是面向对象的语言,因此当声明为对象时能够提供很多对象间转换的方式,与一些常用的方法。自认为java作为一们面向对象的语言,我们在声明一个变量时最好声明为对象格式,这样更有利于你对面向对象的理解

    参考答案

    4、String、StringBuffer、StringBuilder区别

    1、String是final类,底层final char数组实现。不可变字符串序列。String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。

    2、StringBuffer :可变字符串序列,当对字符串修改时使用,线程安全,由于加了锁,导致效率低。

    3、StringBuild:可变字符串序列,效率高,不能保证线程安全。

    ps:总结:StringBuffer 和StringBuild的区别就是StringBuffer 的一些核心方法上加了锁。如果要操作少量的数据用 String;多线程操作字符串缓冲区下操作大量数据 StringBuffer;单线程操作字符串缓冲区下操作大量数据 StringBuilder。

    5、泛型中extends和super的区别

    参考1

    参考2:本章节的通配符介绍

    6、进程和线程的区别

    进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。进程包括线程。

    答案

    7、final,finally,finalize的区别

    答案

    8、序列化

    答案参考

    9、闭包和局部内部类的区别

    答案

    ps:闭包参考groovy中的闭包概念理解

    10、string 转换成 integer的方式及原理

    答案

    三、优点难度的

    1、垃圾回收机制处理

    1、那些内存需要被回收:垃圾对象回收之前要先进行对象搜索,然后再进行回收。搜索设计到了两个算法:引用计数算法(已启用)、可达性分析算法。

    • 虚拟机栈中引用的对象
    • 方法区中静态属性引用的对象
    • 方法区中常量引用的对象
    • 本地方法栈中JNI应用的对象

    2、垃圾回收算法

    • 标记—清除算法:包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶
    段紧随标记阶段,将标记阶段确定不可用的对象清除。标记—清除算法是基础的收集算法,标记和清除阶段的效率不高,而且清除后回产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间。
    
    • 复制算法:复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率不高。现在的 JVM 用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所以两块内存的比例不是 1:1(大概是 8:1)。
    • 标记—整理算法:标记—整理算法和标记—清除算法一样,但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存。标记—整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代。
    • 分代收集:分代收集是根据对象的存活时间把内存分为新生代和老年代,根据各个代对象的存活特点,每个代采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记—整理算法。垃圾算法的实现涉及大量的程序细节,而且不同的虚拟机平台实现的方法也各不相同。
    2、常见编码方式

    答案

    答案2

    3、静态代理和动态代理的区别,什么场景使用

    答案

    4、Java 中异常分为哪些种类

    按 照 异 常 需 要 处 理 的 时 机 分 为 :

    • 编 译 时 异 常 也 叫 CheckedException
    • 运 行 时 异 常 也 叫RuntimeException。
    只有 java 语言提供了 Checked 异常,Java 认为 Checked 异常都是可以被处理的异常,所以 Java 程序必须显式处理 Checked 异常。如果程序没有处理 Checked 异常,该程序在编译时就会发生错误无法编译。这体现了 Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。对 Checked 异常处理方法有两种:1 、当前方法知道如何处理该异常,则用 try...catch 块来处理该异常。
    
    
    
    2 、当前方法不知道如何处理,则在定义该方法是声明抛出该异常。运行时异常只有当代码在运行时才发行的异常,编译时不需要 try catch。Runtime 如除数是 0 和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。
    
    5、谈谈你对解析与分派的认识

    答案

    6、深拷贝浅拷贝认识
    7、Java深入源码级面试题

    四、java数据结构相关

    1、常用数据结构简介

    1、线性结构:

    • 数组、
    • 链表:
    单循环链表:单向循环链表比单链表多了一个尾节点的指针指向的是头结点.
    
    
    
    双向链表:双向链表的每个节点包含以下数据:上一个节点的指针,自己的数据,下一个节点的指针.尾节点没有下一个节点,所以指向null.这样的结构,比如我拿到链表中间的一个节点,即可以往前遍历,也可以往后遍历
    
    
    
    双向循环链表:双向循环链表的尾节点的下一个节点是头结点,头节点的上一个节点是尾节点.
    
    • 队列:普通队列、循环队列
    • 栈。

    2、非线性结构:

    • 树:二分搜索树、红黑树、B+树
    • 图:无向图、有向图、
    • 散列表:也叫作hash表
    2、列举java的集合以及集合之间的继承关系

    答案

    java容器类

    3、常见java集合源码分析

    1、ArrayList源码

    • 看扩容机制:主要在grow方法中,扩容的容量为原来容量的1.5倍(新容量=老容量+老容量>>1,右移一位代表除以2)
    • 留意增删的优缺点:增删慢,可能涉及到扩容、元素移位。查找快,数组的天生随机访问优点。

    2、LinkedList源码

    • 底层双向链表实现
    • 增删的优缺点:底层链表,插入删除比较快,只需修改要操作元素的指针即可(不考虑遍历时时,链表只需修改插入位置指针,数组还要移动。)。查询慢,需要从头遍历。
    • 尾结点的设计:这里为什么要存在一个成员变量尾节点?我感觉是为了方便,比如查找相应索引处元素+插入元素到最后.查找相应索引处元素时,先判断索引是在前半段还是在后半段,如果是在后半段,那么直接从尾节点出发,从后往前进行查找,这样速度更快.在插入元素到最后时,可以直接通过尾节点方便的进行插入.
    • 提供了push pop方法,具有栈的功能
    • add(int index E element)添加任意位置:这里的思想非常巧妙,如果index在链表的前半部分,那么从first开始往后查找否则,从last往前面查找
    • 了解思想即可。大致还是基于单链表的那一套。
    ?
    
    3、HahsMap源码
    hash函数:根据key值,计算出存储地址的位置。
    
    
    
    hash函数的设计:常用的是除留余数法:H(key)=key MOD p (p<=m m为表长)很明显,如何选取p是个关键问题。
    
    
    
    hash表:哈希表是基于哈希函数建立的一种查找表。
    
    
    
    hash冲突:不管hash函数设计的如何巧妙,总会有特殊的key导致hash冲突,特别是对动态查找表来说。 hash函数解决冲突的方法有以下几个常用的方法:
    

    解决hash冲突主要了解:

    1、链地址法:产生hash冲突后在存储数据后面加一个指针,指向后面冲突的数据

    2、再散列法:准备若干个hash函数,如果使用第一个hash函数发生了冲突,就使用第二个hash函数,第二个也冲突,使用第三个。。。重点了解一下开放定制法和链地址法

    • hash表的查找效率影响:
    > 1、选用的hash函数
    > 
    > 2、选用的处理冲突的方法
    > 
    > 3、hash表的饱和度,装载因子 α=n/m(n表示实际装载数据长度 m为表长)
    > 
    > ps:假设hash表是均匀的,在描述负载因子与查找成功的关系时,选择不同的处理方法会得到不同的数学公式,但是会得到类似的结论:
    > 
    > 无论哪个公式,装载因子越大,平均查找长度越大,那么装载因子α越小越好?也不是,就像100的表长只存一个数据,α是小了,但是空间利用率不高啊,这里就是时间空间的取舍问题了。通常情况下,认为α=0.75是时间空间综合利用效率最高的情况
    
    • 构造
    > 参数容量:默认16
    > 
    > 参数负载因子:默认0.75,当负载因子较大时,给hash表扩容的可能性就会减少,所以相对占用空间就会较少,但是每条entry链上(单链表)的元素会相对较多,查询的时间也会增长(时间上较多)。反之相反。所以负载因子是一个时间和空间上折中的说法。自己设计时看自己追求的是时间上还是空间上合理选择即可。一般使用默认0.75即可。
    
    • 注意点:HashMap如何put数据
    ?
    
    4、LinkedHashMap源码
    • LinkedHashMap是一个继承于HashMap,实现Map接口且有可预知迭代顺序的键值对存储列表。与HashMap的不同之处在于LinkedHashMap多维护了一个所有键值对的双向链表,而这个双向链表就定义了迭代顺序,和访问顺序。LinkedHashMap = HashMap + 双向链表。
    • lruCache算法的底层数据结构:无非就是对LinkedHashMap的增删改查做了封装。
    • 为啥有序
    4、二叉树的遍历

    深度优先遍历、广度优先遍历实现

    答案:这里以二分搜索树的栗子实现下

    5、堆

    堆的了解

    二叉排序树和堆的区别

    6、红黑树、B+树认识

    1、红黑树

    2、B+树

    7、对图的认识

    五、线程相关

    线程池使用及自定义线程池

    相关文章

      网友评论

          本文标题:java 复习

          本文链接:https://www.haomeiwen.com/subject/hxtanhtx.html