文章目录
Java基础部分
重写与重载的区别
**重载:**发生在同一个类中,方法名必须相同,参数类型、个数、顺序,方法返回值和访问修饰符可以不同。
**重写:**发生在子类继承父类时,方法名参数列表必须相同。返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符大于等于父类;如果父类方法被private那么子类不能重写该方法。
接口和抽象类的区别
约束条件
- 抽象类可以存在普通成员函数,而接口只能存在public abstract方法。
- 抽象类中的成员变量可以是各种类型,接口中的成员变量只能是public static final类型的
- 抽象类只能继承一个,接口可以实现多个。
设计目的
接口的设计目的是对类的行为进行约束,准确的来说时规定了类有什么行为。但并不对如何实现进行限制。
抽象类的设计目的是代码复用,当大量的类具有相同行为时,抽象类可以抽取公共部分抽象成一个抽象类,让这些类继承这个抽象类。
总的来说,接口是对行为的描述,抽象类是对类本质的抽取
内部类
在Java中将一个类定义在另一个类的内部,被定义在里面的那个类叫做内部类,内部类有四种:成员内部类、匿名内部类、局部内部类、静态内部类。
成员内部类
当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
如果成员内部类中的方法的变量与成员内部类的成员变量发生冲突则需要
this.成员变量
外部类访问成员内部类则需要通过外部类创建一个内部类然后访问。
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
内部类的访问修饰符
修饰符 | 权限 |
---|---|
private | 只能在外部类内部访问 |
protected | 同一包或继承外部类的情况下访问 |
public | 任何地方都能访问 |
局部内部类
可以理解成局部变量,是定义在方法内部的类,没有访问修饰符。
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
匿名内部类
适用于只用到一次的内部类,直接new一个接口大括号接实现。
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
静态内部类
可以理解成静态变量,不需要通过外部类对象就可以直接访问。但是静态内部类不能使用外部类的非static成员变量或者方法。因为非静态变量和方法是随着对象的初始化而产生的,而静态内部类在类加载完成时就已经存在了。
内部类访问外部类时如何实现的?
1.编译器在内部类添加了一个用于指向外部类对象的引用的成员变量,此时引用为空。
2.编译器在内部类的构造方法中添加一个外部类类型的参数,在构造方法执行时为1中的成员变量赋值。
3.在内部类调用构造函数时会默认传入这个外部类的引用。
为什么局部内部类和匿名内部类只能访问 final 的局部变量?
因为内部类和外部类属于同一个级别,内部类不会因为方法执行结束就被销毁,但是定义在外部类方法中的局部变量,方法结束就会被销毁,这时如果内部类访问外部类的局部变量就会出现问题,为了解决这个问题,编译器在编译时复制了一份外部类的局部变量的值保存到内部类中,但是这样又会出现一个数据不一致的问题,所以这个变量必须被finial修饰,一经赋值不允许更改。
内部类的优点
1.内部类可以独立继承一个接口,无论外部类是否已经继承对内部类都没有影响,内部类的存在使得多继承的解决方案变得完善。
2.方便将有一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序。
4.方便编写线程代码。
多态的好处
多态的作用是让同一对象呈现不同的状态,从而做出不同的处理。多态的基础是继承。
多态的好处:
1. 消除类型之间的耦合关系
2. 可替换性
3. 可扩充性
4. 接口性
5. 灵活性
6. 简化性
ArrayList和LinkedList的区别
**ArrayList:**底层使用的是动态数组。会根据元素的个数进行动态的扩容。ArrayList初始长度默认为10,每次默认扩容1.5倍。由于是数组,所以对内存的要求较高,需要连续内存存储,适合根据下标访问元素。如果不是尾插还涉及到元素的移动。使用尾插并指定合适的初始容量(减少扩容次数)可以极大提升性能。甚至超过LinkedList。(LinkedList需要创建大量Node对象)
**LinkedList:**底层使用链表,适合做数据的插入和删除。不适合查询(遍历LinkedList必须用iterator迭代器不能使用for,因为for循环体内通过get方法获取每一个元素时都需要重新遍历链表,对性能消耗极大)
HashMap底层原理
数组+链表:
jdk8之后当链表高度达到8,数组长度超过64时,链表转变为红黑树,提高查询效率。链表长度低于6则将红黑树转回链表。元素以内部类Node节点存在。Node节点中存储了
key的hash值
key
value
next指针
- 计算两次key的hash值,然后把这个值对数组长度取模,得出一于数组下标。
- 如果该该位置没有存储数据就直接创建Node节点存入数组
- 如果产生hash冲突,先进行equals比较,如果相同则直接覆盖。如果不同就把该节点接在原来的链表的尾部。
- key为null时存在下标为0的位置。
hashmap是允许key和value为nul的,但是hashtable不可以。
hashtable每一个方法都是被synchronized修饰的,是线程安全的,安全性高,效率低。但hashmap不是。
I/O流
什么是I/O流?
I/O流本质是一种数据流。也可以理解成管道。在里面流动的水就是数据。
按照数据流向的不同分为输入流和输出流。输入流是从磁盘读取数据到内存,输出流是把内存数据写到磁盘。
按照操作的基本单元划分可以分成字符流和字节流。
字节流:以字节为单元,可操作任何数据【主要由InputStream和outPutStream作为基类】
字符流:以字符为单元,只能操作纯字符数据,比较方便【主要由Reader和Writer作为基类】
序列化与反序列化
- 序列化:以流的方式写进文件中保存
- 反序列化:把文件中的对象以流的方式读出来
- 被序列化的类必须实现Serializable接口(标记型接口)
- 被static或transient修饰的成员变量不能被序列化
Buffer
https://www.javazhiyin.com/89971.html
sleep和wait有什么区别
sleep():属于Thread类,任何场景都能调用,必须指时间,不释放锁。
wait():属于Object类,必须在同步代码块或同步方法中,可以不指定时间,也可以指定时间,释放锁。
线程的六种状态
New(新创建)
Runnable(可运行)
Blocked(被阻塞)
Waiting(等待)
Timed Waiting(计时等待)
Terminated(被终止)