- java基础知识
- java的四个基本特性(封装,继承,多态,抽象)
- 封装:数据和基于数据的操作封装在一起,对外提供接口。
- 继承:is-a 关系,子类继承唯一父类,符合里氏替换原则
- 多态:子类对父类的方法做多种不同形式的响应,子类继承父类,重写父类的方法,父类引用子类对象
- 抽象:一类对象的共同特征总结出来构造类的过程,比如动物类是猫和狗的抽象。
- 面向对象的6个原则
- 单一原则:一个类只负责一个责任
- 开放封闭:对扩展开放,对修改封闭
- 里氏替换:任何使用基类的地方都可以使用子类替换
- 接口隔离:接口力度最小化,对每个功能特别专一
- 依赖倒置:依赖于抽象不依赖于具体。面向接口编程
- 合成复用:优先使用合成或者复用的代码
- (覆盖,重写)和重载
覆盖,重写:是java多态性的不同表现方式,子类对父类的方法进行重写和覆盖。
重载:函数方法名相同,返回值相同,参数的个数,类型,顺序不同
重点!返回值类型可以相同也可以不相同,因为java中调用函数并不需要强制赋值。
- Java泛型,及其意义
参数化类型,明确指定集合元素的数据类型,该集合只能保存指定类型的元素。意义:避免的数据类型的强制转换导致的错误。
类型擦除:将泛型java代码转换为普通java代码,用顶级父类替换,移除类型参数
- Java访问权限修饰符和访问权限
Public:整个项目
Protected: 同一个类,同一个包,子类
default:同一个类,同一个包
Private: 同一个类
- Final与static
Final:声明数据为常量,不能被继承,不能被子类修改(覆盖)
Static:声明变量为静态变量,在类第一次实例化时运行一次
初始化顺序:父类(静态变量、静态初始化块)→子类(静态变量、静态初始化块)→父类(变量、初始化块)→父类(构造器)→子类(变量、初始化块)→子类(构造器)
- 抽象类和接口类的区别
方法:接口类中的必须是抽象的(不能写具体方法过程),抽象类中可以没有抽象方法
变量:接口类中的参数必须用final static修饰,必须被初始化,没有常量与变量。抽象类中可以有普通成员。
子类:接口可以继承多个父接口,抽象只能单继承
- 8种基本数据类型
1字节(byte,boolean),2字节(char,Short),4直接(int,float),8字节(long,double)
强制类型装换规则:①byte,short,char变量计算都会提升到int型,要强制转换。②基本数据类型不能和boolean类型进行装换③char类型装换成高级类型会变成对应的ASCII④高级类型装换成低级类型数据会丢失。
- String、StringBuffer和StringBuilder
可变不可变:string类型是不可变的(都会生成一个新的string对象,用+号链接字符串创建新对象),stringBuffer和StringBuilder是可变的。
线程安全:string和stringBuffer是线程安全的(同步锁),stringBuilder是不安全
Final:都是final类型不能被继承
初始化:stringBuffer和stringbuild都是用构造函数初始化,string可以用构造函数初始化也可以用赋值。
- Java和C++的区别
都是面向对象语言,支持封装,继承,多态
指针:java不提供指针来访问内存,更安全,C++提供指针
继承:java是单继承,c++是多重继承,java一个类实现多个接口
内存:java垃圾回收机制,不用管理内存的是用情况
- Object的通用方法
toString(),
finalize(),
clone(),
Equals(),hashCode()
Wait(),notify(),notifyAll()
getClass()
- JDK,JRE,JVM区别
JDK是java运行工具,包含JRE,
JRE:是java运行环境,提供了java程序的运行平台,包含JVM
JVM:java虚拟机,提供内存管理和垃圾回收机制等
- JDK中常用的包
Java.net java.util java.io java.sql java.lang
- Equals与==的区别
“==”:比较基本数据类型的值,比较对象存放的内存地址
Equals:可以用来对复合数据类型的值做比较,也能比较对象存放的内存地址
- Super与this的区别
Super:访问父类构造函数的父类方法,为保证在子类可以访问父类对象之前要完成对父类对象的初始化,必须要放在第一行
This:调用本类的构造函数,必须写在第一行
- 异常
- Throwable是java语言中所有错误和异常的超类(万物即可抛)。它有两个子类:Error、Exception
- Error:Error为错误,是程序无法处理的,如OutOfMemoryError、ThreadDeath等,出现这种情况你唯一能做的就是听之任之,交由JVM来处理,不过JVM在大多数情况下会选择终止线程。
- Exception:Exception是程序可以处理的异常
- 非检查异常(unckecked exception):Error和RuntimeException以及他们的子类。javac在编译时,不会提示和发现这样的异常。这样的异常发生的原因多半是代码有问题。如:除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
- 检查异常(checked exception):SQLException异常,IOException异常,ClassNotFoundException异常。 javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws),否则编译不会通过。这样的异常一般是由程序的运行环境导致的。
- 如果try语句里面有return,返回的是try语句块的变量值(返回值保存到局部变量->执行jsr指令跳到finally语句执行->执行完毕finally后,返回局部变量保存值);
- Finally块中的return将覆盖其他所有的return。
- Java的动态代理和反射机制
只要给定类的名字,就可以通过反射机制来获得该类的所有信息。
-
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理:
代理的好处:①隐藏委托类的实现 ②在不修改委托类代码的前提下对做一些额外的修改,实现解耦。
动态代理:代理类在程序运行时创建的代理方式被称为动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数
Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处理的逻辑的编写,这个公共代理类在运行的时候才能明确自己要代理的对象,同时可以实现该被代理类的方法的实现,然后在实现类方法的时候可以进行增强处理。
- hashcode与equal区别
Equal:逐个比较,特别是像set这样不能重复,用equal比较效率低下
Hashcode:实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其他地址上。
- 集合专题
- 常见的集合有哪些
总的分为Map接口与Collection接口
Map:HashMap,HashTable,concurrentHashMap,treeMap以及properties
Collection:分为List 与 Set接口
Set接口:HashSet,TreeSet,LinkedHashSet
List接口:ArrayList,LinkedList,vector,stack
扩展:List是元素有序的,可以重复;Set是元素无序的,不可以重复
- HashMap底层实现?
数组+链表
计算key的hashCode值,然后对哈希码再哈希(减少哈希冲突),然后把哈希码和(数组长度-1)进行按位与操作,得到存储的数组下标,如果该位置没有链表节点,那么直接把<key,value>的节点放入该位置。如果该位置又节点,就对链表进行遍历,如果有相同的key则进行替换,否则插入链表表头。
- HashMap的数组长度为什么是2的幂次方?
- 通过将key的hash值与length-1进行& 运算,实现了当前 Key 的定位,2 的幂次方可以减少冲突(碰撞)的次数,提高 HashMap 查询效率(length=2n);
- 如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;
- HashMap和Hashtable的区别有哪些?
线程安全:HashMap没有考虑同步是线程不安全的,HashTable是线程安全的
关键字:HashMap允许null作为键(一个)值(多个),HashTable不允许null作为键值。Get()方法返回null值,既可以表示hashmap中没有该键,也可以表示该键对应的值为null。所以hashmap用containsKey()判断是否存储某个键。
大小:hashmap中数组的默认大小是16,扩容后是之前数组的2倍。Hashtable默认大小11,扩容后是之前数组的2倍+1.
- ConcurrentHashMap和Hashtable的区别?
concurrentHashMap结合了hashMap和 hashTable的优势,是线程安全的且不允许null作为键和值。
concurrentHashMap应用了分段锁机制,分成16段,每次get,put,remove只锁当前用到的段。
hashTable是锁住整个结构
ConcurrentHashMap 的具体实现知道吗
该类包含两个静态内部类 HashEntry 和 Segment;前者用来封装映射表的键值对,后者用来充当锁的角色;
Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个 HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。
- HashMap和HashSet的区别?
HashMap | HashSet |
实现了Map接口 | 实现Set接口 |
存储键值对 | 仅存储对象
|
调用put()向map中添加元素 | 调用add()方法向Set中添加元素
|
HashMap使用键(Key)计算Hashcode
| HashSet使用成员对象来计算hashcode值, 对于两个对象来说hashcode可能相同, 所以equals()方法用来判断对象的相等性, 如果两个对象不同的话,那么返回false |
HashMap相对于HashSet较快,因为它是使用唯一的键获取对象 | HashSet较HashMap来说比较慢 |
不允许key重复 | 不允许元素重复 |
- HashMap和TreeMap的区别?
①实现方法:HashMap基于哈希表实现。TreeMap基于红黑树实现
②TreeMap能够把他保存的记录根据键排序
③HashMap:适用于在Map中插入,删除和查找元素
TreeMap:按自然顺序或自定义顺序遍历键
HashMap比TreeMap快一点
- List,set和map的初始容量和加载因子?
- List
ArrayList 的初始容量是 10;加载因子为 0.5; 扩容增量:原容量的 0.5 倍 +1;一次扩容后长度为 16。
Vector 初始容量为 10,加载因子是 1。扩容增量:原容量的 1 倍,如 Vector 的容量为 10,一次扩容后是容量为 20。
- Set
HashSet,初始容量为 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashSet 的容量为 16,一次扩容后容量为 32
- Map
HashMap,初始容量 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashMap 的容量为 16,一次扩容后容量为 32
- Comparable接口和comparator接口有什么区别?
前者简单,但是如果需要重新定义比较类型时,需要修改源代码。
后者不需要修改源代码,自定义一个比较器,实现自定义的比较方法。
- Java集合的快速失败机制“fail-fast”?
它是 java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。
每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。
解决办法:①在遍历过程中,所有涉及到改变 modCount 值得地方全部加上 synchronized;②使用 CopyOnWriteArrayList 来替换 ArrayList。
- ArrayList,LinkedList,Vector的区别和实现原理?
基于类型:ArrayList 和 Vector是基于数组的(方便查询,增加时尾部O(1),增加和删除操作是O(n)),LinkedList是基于链表的(方便删除,修改,增加,不方便查询)
线程安全:vector使用同步机制是线程安全的,ArrayList和LinkedList是线程不安全的
扩容机制:ArrayList初始容量10,一次扩容后是16。Vector初始初始10,一次扩容后是20