加载顺序
- 父类静态成员->父类静态代码块->
- 子类静态成员->子类静态代码块->
- 父类普通成员->父类代码块->父类构造函数->
- 子类普通成员->子类代码块->子类构造函数
- 只有类第一次加载的时候加载静态成员与代码块
面向对象的三大特性:封装、继承、多态
Java作为一种面向对象语言。支持以下基本概念:
类 对象 继承 静态 重载 多态 抽象 封装
- 对象是要研究的任何事物,类的实例
- 类是对象的模板,对一组有相同数据和相同操作的对象的定义
- Java的方法重载:就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法
- 重写:父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写。若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
extends 关键字
- 子类拥有父类非private的属性,方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java的继承是单继承
final 关键字
在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)
- 1.修饰类: 当用final修饰一个类时,表明这个类不能被继承。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
- 2.修饰方法: 把方法锁定,以防任何继承类修改它的含义;类的private方法会隐式地被指定为final方法。
- 3.修饰变量: 修饰变量是final用得最多的地方。对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
static 关键字:
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
- 1)static方法:
- static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。但是在非静态成员方法中是可以访问静态成员方法/变量的。静态方法属于类,是不能被重写,故而也不能实现多态
- 2)static变量: static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响
- 3)static代码块: static关键字还有一个比较关键的作用就是用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次
多态存在的三个必要条件
- 要有继承;
- 要有重写;
- 父类引用指向子类对象。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作
比如:List list1=new ArrayList();
List list2 = new LinkedList();
Set set1=new HashSet();
Set set2=new TreeSet();
但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了.
若子类重写了父类中的某些方法,在调用该些方法的时候,必定使用子类中定义的这些方法
接口与抽象类的相同部分:
- 接口与抽象类都必须有子类实例化才可使用。
- 接口与抽象方法的子类都必须重写全部抽象方法
- 抽象方法必须为public或者protected
抽象类的使用原则如下:
- 抽象类使用extends继承,一个子类只能继承一个抽象类;
- 它可以有默认的方法实现(非抽象方法)
接口的使用原则如下:
- 接口使用implements关键字实现多个接口;
- 接口方法全都是抽象方法
封装就是将属性私有化,提供公有的方法访问私有属性。
- 通过封装,可以实现对属性的数据访问限制,同时增加了程序的可维护性。
- 由于取值方法和赋值方法隐藏了实现的变更,因此并不会影响读取或修改该属性的类,避免了大规模的修改,程序的可维护性增强。
- 封装的实现:修改属性的可见性来限制对属性的访问。为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问。在赋值和取值方法中,加入对属性的存取的限制。
通过取模mod()方法计算出来的值都是非负数
通过%求余出来的数值,正数、负数、0都可以。
在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
- 堆排序、快速排序、希尔排序、直接选择排序不是稳定的排序算法
- 基数排序、冒泡排序、直接插入排序、归并排序是稳定的排序算法。
数组:
优点:使用方便 ,查询效率比链表高,内存为一连续的区域
缺点:大小固定,不适合动态存储,不方便动态添加
链表:
优点:可动态添加删除 大小可变
缺点:只能通过顺次指针访问,查询效率低
Java中short、int、long、float、double的取值范围:
字符与字节有什么区别:
- 字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。
- 字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()——+、等等。字符是语义上的单位,它是有编码的,一个字符可能编码成1个2个甚至3个4个字节。这跟字符集编码有关系,英文字母和数字是单字节,但汉字这些自然语言中的字符是多字节的。
int 的范围:2 的-31 次方到 2的31次方-1, -2147483648~2147483647
你熟悉什么数据结构
- 线性表 : 1.数组实现 ArrayList 2.链表 LinkedList
- 栈与队列
- 树与二叉树 1.树 2.二叉树 3.二叉查找树(二叉排序树) 4.平衡二叉树(AVL树) 5.红黑树
- 图
b 树和 hash 应用场景
- AVL树:Windows对进程地址空间的管理使用AVL树
- 红黑树:Map和Set都是红黑树实现的
- B/B+树:数据库索引
==和equals区别;
==:在8种基本数据类型中,比较的数据的值是否相等
equals:在引用数据类型中,比较的是内存中首地址是否相等,由于new出来的对象在堆上开辟了两个独立的空间,地址也当然是不同的,所以返回false。诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
字段和属性的区别:
- 字段通常是在类中定义的类成员变量
- 属性实现了字段的封装,属性有get、set 方法来控制字段。
关键字continue、break和return的区别:
- continue: 跳出本次循环继续下一次循环
- break: 跳出循环体,继续执行循环外的函数体
- return: 跳出整个函数体,函数体后面的部分不再执行
String,StringBuffer与StringBuilder的区别:
- String: 字符串常量,String 是不可变的对象, 因此在每次对 String类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,速度会变的相当慢。
- StringBuffer: 字符串变量,是线程安全的。对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。
- StringBuilder: 字符串变量,是非线程安全的。和StringBuffer用法一样,但是非线程安全,速度较快。
Java与C++的异同点总结:
1、Java为解释性语言,其运行过程为:程序源代码经过Java编译器编译成字节码,然后由JVM解释执行。而C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码,可直接执行。因此Java的执行速度比C/C++慢,但Java能够跨平台执行,C/C++不能。
2、Java是纯面向对象语言,所有代码(包括函数、变量)必须在类中实现,除基本数据类型(包括int、float等)外,所有类型都是类。此外,Java语言中不存在全局变量或者全局函数,而C++兼具面向过程和面向对象编程的特点,可以定义全局变量和全局函数。
3、与C/C++语言相比,Java语言中没有指针的概念,这有效防止了C/C++语言中操作指针可能引起的系统问题,从而使程序变得更加安全。
4、与C++语言相比,Java语言不支持多重继承,但是Java语言引入了接口的概念,可实现多个接口。由于接口也有多态特性,因此Java语言中可以通过实现多个接口来实现与C++语言中多重继承类似的目的。
5、在C++语言中,需要开发人员去管理内存的分配(包括申请和释放),而Java语言提供了垃圾回收器来实现垃圾的自动回收,不需要程序显示地管理内存的分配。在C++语言中,通常会把释放资源的代码放到析构函数中,Java语言中虽然没有析构函数,但却引入了一个finalize()方法,当垃圾回收器要释放无用对象的内存时,会首先调用该对象的finalize()方法,因此,开发人员不需要关心也不需要知道对象所占的内存空间何时被释放。
Java中 ++i 的操作是线程安全的么?为什么?如何使其线程安全呢?
当线程执行这个语句时, 会先从主存当中读取 i 的值, 然后复制一份到高速缓存当中, 然后 CPU 执行指令对 i 进行加 1 操作, 然后将数据写入高速缓存,最后将高速缓存中 i 最新的值刷新到主存当中。这个代码在单线程中运行是没有任何问题的, 但是在多线程中运行就会有问题了。 在多核 CPU 中, 每条线程可能运行于不同的 CPU 中, 因此每个线程运行时有自己的高速缓存。
可能存在如下情况:初始时, 两个线程分别读取 i 的值存入各自所在的CPU 的高速缓存当中, 然后线程 1 进行加 1 操作, 然后把 i 的最新值 1 写入到内存。 此时线程 2 的高速缓存当中 i 的值还是 0, 进行加 1 操作之后, i 的值为1, 然后线程 2 把 i 的值写入内存。最终结果 i 的值是 1, 而不是 2。 这就是著名的缓存一致性问题。 通常称这种被多个线程访问的变量为共享变量。
volatile不能解决这个线程安全问题。因为volatile只能保证可见性,不能保证原子性。
如何解决缓存一致性问题:通常来说有以下 2 种解决方法:
1) 通过在总线加 锁的方式,使用synchronized或者ReentrantLock都可以解决这个问题。
2) 通过缓存一致性协议
1. 只能有一个 CPU 能使用这个变量的内存。 如果一个线程在执行 i = i +1, 如果在执行这段代码的过程中, 在总线上发出了 LCOK锁的信号, 那么只有等待这段代码完全执行完毕之后, 其他 CPU 才能从变量 i所在的内存读取变量, 然后进行相应的操作。 这样就解决了缓存不一致的问题。由于在锁住总线期间, 其他 CPU 无法访问内存, 导致效率下。
2.缓存一致性协议。 该协议保证了每个缓存中使用的共享变量的副本是一致的。
它核心的思想是: 当 CPU 向内存写入数据时, 如果发现操作的变量是共享变量, 即在其他 CPU 中也存在该变量的副本, 会发出信号通知其他 CPU 将该变量的缓存行置为无效状态, 因此当其他 CPU 需要读取这个变量时, 发现自己缓存中缓存该变量的缓存行是无效的, 那么它就会从内存重新读取。
最后补上AtomicInteger。为什么AtomicInteger使用CAS完成?因为传统的锁机制需要陷入内核态,造成上下文切换,但是一般持有锁的时间很短,频繁的陷入内核开销太大,所以随着机器硬件支持CAS后,JAVA推出基于compare and set机制的AtomicInteger,实际上就是一个CPU循环忙等待。因为持有锁时间一般较短,所以大部分情况CAS比锁性能更优。
Java中的异常
Throwable
Throwable是Java异常的顶级类,所有的异常都继承于这个类。
Error,Exception是异常类的两个大分类。
Error
Error是非程序异常,即程序不能捕获的异常,一般是编译或者系统性的错误,如OutOfMemorry内存溢出异常等。
Exception
Exception是程序异常类,由程序内部产生。Exception又分为运行时异常、非运行时异常。
运行时异常
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过,运行时异常可处理或者不处理。运行时异常一般常出来定义系统的自定义异常,业务根据自定义异常做出不同的处理。
常见的运行时异常如NullPointException、ArrayIndexOutOfBoundsException等。
非运行时异常
非运行时异常是程序必须进行处理的异常,捕获或者抛出,如果不处理程序就不能编译通过。如常见的IOException、ClassNotFoundException等。
快速排序的特点,每n趟排序后至少有n个元素已经在其正确的位置上
Java:缓存还没更新到主存,服务器挂了怎么办?
持久化方面讲,现在都用缓存式服务器来加快速度。比方说REDIS的持久化,两种,RDB和AOF两个讲一讲