Java基础知识汇总
Object类中有哪些方法
- equals():未被重写前,由==来实现,比较引用数据类型的引用地址是否相同
- HashCode():本地方法,未被重写前返回对象在堆上的唯一地址值,可以看作是对象的身份ID
- clone():实现了cloneable接口才可以调用该方法,实现对象的浅复制
- getClass():final修饰,获取运行时的类型
- toString():若参数为变量,则返回对应变量的string对象,若参数为一个对象,则返回堆内存对象的地址
- finalize():在GC准备释放对象所占用的内存空间之前,它将首先调用finalize()方法,finalize()方法中一般用于释放非Java 资源(如打开的文件资源、数据库连接等),或是调用native方法时分配的内存(比如C语言的malloc())。
- wait():使线程阻塞等待
- notify():唤醒等待的线程
- nofityAll():唤醒在该对象上等待的所有线程
JAVA的八大数据类型
可以分为四个大类:整型,字符型,浮点型,布尔型
- boolean:JVM中并没有提供boolean专用的字节码指令,在编译后会以int型来表示,4字节。boolean[]会以byte数组来表示,1字节
- char:可以赋值单字符以及整型数值,表示数字的取值范围为0~65536,2字节
- byte:范围为-128 - 128,1字节
- short:范围为:-32768-32768,2字节
- int:范围为:-2,147,483,648-2,147,483,647,4字节
- long:范围为;-2^63-2^63-1,8字节
- float:单精度浮点数,4字节
- double:双精度浮点数,8字节
接口和抽象类有哪些区别
相同点:
- 不能被实例化
- 可以将抽象类和接口类型作为引用类型
- 一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部实现
不同点:
- 抽象类中可以定义构造器,可以有抽象方法和具体方法,抽象类中可以定义成员变量,一个类只能继承一个抽象类,抽象类中可以包含静态方法,抽象类中的成员可以由private,protected,public修饰
- 接口中的成员全部都是由public修饰,不能定义构造器,只能有抽象方法,不能有静态方法,一个类可以实现多个接口
除了语法上的异同之外,两者还有语义上的不同。抽象类适合描述某一更具体的概念,比如狗是一种动物,而不能说狗实现了动物的接口。接口则用于描述多个事物的共同特征,比如鸟实现了flyable接口,这个flyable就是一种行为特征,当然也可以描述其他的特征。
String,StringBuilder,StringBuffer的区别
- String的底层是一个由final修饰的char型数组,String是静态只读的,当改变变量的值时,其实只是改变了引用对象的指向,指向了新创建的字符串,而原字符串仍存在于字符串常量池。
- StringBuffer(JDK1.0引入):引用对象指向一个空间,包含一个可自行扩容的char型数组和字符串长度计数变量Count,StringBuffer的所有方法均被synchronized修饰。扩容时会开辟一块新的空间用于创建更大的数组,并将原数据复制过去,并改变引用对象的指向。
- StringBuilder(JDK1.5引入):取消了synchronized方法修饰,所以效率更高,但是线程不安全。
Object o = new Object()
在内存中占用多少个字节?
一个对象在内存中的存储布局:markword
:8字节,锁信息+HashCode+GC信息;classPointer
:4字节;对齐:保证大小能被8整除;数据段:即对象内声明的变量
所以一个空对象最小为16字节
对象如何定位?
HotSpot
虚拟机默认使用直接定位:指针直接指向堆内存内的对象,对象内的classPointer
指向方法区内的class。优点:直接访问快;缺点:GC时,若需要移动对象,则指针也需要改变
句柄方式(间接方式):指针指向另一个结构体,该结构体内有两个指针,分别指向堆内存和方法区。优点:对象小,GC时无需改动指针。缺点:比直接访问更慢
对象的创建过程
new指令:申请内存空间,为成员变量设立默认值
invokespecial
汇编码:调用构造方法,为成员变量设定初始值
astore
汇编码:建立引用,让指针指向堆
面向对象有哪些特征
面向对象是一种编程思想,即万物皆可归类抽象,万物皆可对象;有三大特征
- 封装:类与外界的封装关系,即隐藏类内部的实现机制,对外部而言,它的内部细节是隐藏的,只暴露了自身的访问方法。使用者按照既定的方式来调用方法,不必关心方法的内部实现,便于使用,增强了代码的可维护性。
- 继承:类与类的关系,即从已有的类中派生出新的类,即子类与父类,也可以称作超类和基类。从多个类中抽象出一个基类,使其具备多个类的共同特性,使用extends关键字继承某个类后,就具备了父类的属性,并扩展新的属性。在父类中使用private关键字来限制不会被继承。
- 多态:多个类的关系,必备的三个要素:继承,重写,父类引用指向子类对象
ArrayList与LinkedList的区别
- ArrayList是基于索引的数据接口,底层是数组,可以在常数级的复杂度对元素进行随机访问。而LinkedList是基于Node对象列表的形式存储数据,底层是一个双向链表,查找元素是O(n)。因此LinkedList的插入,添加,删除操作,总体上会更快,因为不是数组,不需要移动元素,重新计算索引和大小,但是LinkedList更占内存,因为每一个node都会封装前驱指针和后继指针。
- 如果你需要经常随机访问数据,更加推荐使用ArrayList;如果需要经常插入删除元素,推荐使用LinkedList。
- 多提一嘴:其实总体上ArrayList性能其实更加优越一些。第一,LinkedList的每一个node都有指针,更占内存,第二:虽然LinkedList的头插效率很高,但是尾插效率却不见得十分高效,因为数组的尾插无需进行拷贝和移位,而链表则需要创建node对象。并且有人测试过,在数据量较大时,链表的中间插入仍会比ArrayList耗时更多。Joshua Bloch自己都不用LinkedList,以俺还是无脑选择ArrayList~
多线程环境下,操作long和double类型为什么不安全?
JAVA内存模型要求,变量的读取和写入必须是原子操作,但对于非volatile类型的long和double变量,JVM允许将64位的读操作或写操作分解成两个32位的操作。当读取一个非volatile类型的long时,如果读操作和写操作在不同的线程中执行,那么很可能读取到某个值的高32位和另一个值的低32位。就是说,在多线程环境下,使用共享且可变的long和double变量是不安全的,必须用关键字volatile声明或者用锁保护起来。但是如果在64bit的操作环境下,读写就可以是原子操作。
什么是线程安全?
当多个线程访问某个类时,这个类始终能表现出正确的行为,那么就称这个类是线程安全的。具体说,就是当多个线程访问某个类时,不管运行时环境采用何种调度方式将这些线程交替进行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类时线程安全的。
Int和Integer的区别
- Integer是int的包装类,int则是java的一种基本的数据类型;
- Integer变量必须实例化之后才能使用,而int变量不需要实例化;
- Integer实际是对象的引用,当new一个Integer时,实际上生成一个指针指向对象,而int则直接存储数值
- Integer的默认值是null,而int的默认值是0。
1 |
|
包装类的缓存机制
若使用valueOf方法,则会调用缓存IntegerCache,这是一个静态内部类,会直接缓存-127到128的Integer对象。
因此,在valueOf方法中,如果值在-127-128之间,都会直接返回缓存中的该对象而不会重新生成对象。
如果超过这个范围就会直接在堆上创建一个新的对象
1 |
|
Byte,Short,Long的缓存范围都是-128-127,Character的缓存范围是0-127,除了Integer,其他的缓存范围都是固定的
ALV树和红黑树有什么区别?
- AVL树是严格平衡二叉树,左右子树树高不超过1;而红黑树是弱平衡二叉树,红黑树确保没有一条路径会比其它路径长出两倍。所以在相同的节点下,AVL树的高度要低一些,低于红黑树
- AVL树和红黑树都是通过旋转来保持平衡,AVL旋转更加频繁,AVL树适合用于插入删除次数比较少,但查找多的情况。红黑树的旋转次数更少,所以对于搜索、插入、删除操作较多的情况下,使用红黑树
- 黑树通过它规则的设定,确保了插入和删除的时间复杂度是O(log N) ,每次插入和删除的平均旋转次数小于AVL树。但是AVL树的查找效率高于红黑树