Java 基础累积
1. Java中对象在堆中,引用和原生数据类型在栈中,string对象在堆中和栈(字符串池)中都有。
2. 在堆中生成同一类的对象时,无论多少个对象,方法是共享的(没考虑静态属性和方法)。
3. 关于String类型,
1)String str = new String("str"); 若字符串池(位于栈中)没有“str”对象则在堆中和池中都生成“str”对象。
若字符串池中有“str”对象,则在堆中生成“str”对象。
2)String str = “str”; 若字符串池没有“str”对象,则在池中生成“str”对象,
若字符串池中有,则str直接指向“str”对象。
4. Person person = new Person(); 依次做了三件事
(1) 为Person对象开辟内存空间;
(2) 调用构造方法;
(3) 将对象的地址返回(返回给person引用)。
5. Java继承中
(1) 生成子类对象的时候,默认调用父类不带参数的构造方法生成父类对象(也可以用super关键字调用指定的父类构造方法,
但是必须调用父类方法生成父类对象)
(2) 父类的方法和属性都可以被继承(也可以重写)
(3) static方法不能被重写(只能被隐藏。)Parent p = new Son(); p.go(); 若go()方法是static的,则执行Parent类的go()方法。
6. Java多态
Class Parent { public void run(){} }
Class Son extends Parent { public void run(){} }
Parent p = new Son();
p.run(); 调用子类的run()方法(若Parent类没有run()方法,会发生编译时错误)。
7. final关键字
final修饰的属性,有两种赋值方式。一是定义的时候赋值,二是在所有的构造方法中为它赋值。
8. static{}静态代码块(写在类中,不是方法中,也是完成初始化工作),是当该类的.class文件加载到java虚拟机
的时候执行(这时候还没有创建对象,且只执行一次)。
9. 集合
1)ArrayList
ArrayList是可变数组(Object[],数组中放的是对象的引用,无法放原生数据类型)初始长度为10
(可用ArrayList(int a)指定初始长度);
当长度不够的时候将数组的长度增加到1.5倍+1;
在ArraList中间插入元素,则需要把后面的元素全部往后移动,所以在ArrayList中插入元素代价很高。
2)LinkedList
链表(双向循环链表,每一个对象中,包含了值、上一个对象、下一个对象。
或则说抽象一点就是本身和上一个的地址和下一个的地址)。
注:对比ArrayList和LinkedList,ArrayList更适合搜索,LinkedList更适合插入删除。
3)TreeSet
TreeSet是排序的Set想在TreeSet中添加对象,通常需要使用TreeSet set = new TreeSet(comparator); 构造方法。
在implements Comparator类的compare方法中定义比较规则。
4)Map
对于HashSet和HashMap都是无序的,set是不能重复(重复无法放入),map是key不能重复(重复了直接覆盖)。
keySet返回key的集合(Set类型,不可重复),values返回值的集合(Collection类型,可重复)。
HashSet是使用HashMap实现的,当使用add方法将对象添加到Set当中时,
实际上是将该对象作为底层所维护的Map对象的key,而value则都是同一个Object对象(该对象我们用不上)
5)HashMap维护着一个Entry[],HashMap的结构是数组+链表,当put一个值的时候,它会根据put的key的hashCode
计算出一个位置(准备放Entry对象的位置),如果该位置没有对象存在,就将此对象直接放进数组当中;
如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找
(Entry类有一个Entry类型的next成员变量,指向了该对象的下一个对象),
如果此链上有对象的话,再去使用equals方法进行比较,如果对此链上的某个对象的equals方法比较为false,
则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。
10. 数据结构
一、线性表结构
1)数组(有索引)
2)链表(双向循环链表:每一个元素都有该元素的数据、下一个元素、上一个元素)
3)栈(Stack),后进先出(跌书)
4)队列(Queue),先进先出(排队上车)
11. null
可以把null强制转化为任意类型,不会报错。
12. 泛型(避免类型转化异常)
当使用如Person<?> 或 Person<? extent Foot>的引用时,只能取得或移除引用指向的对象的属性,不能增加
(否则就违背了泛型避免类型转化异常的初衷)
13. Integer i = 100;
Integer i2 = 100;
i == i2 是true(如果赋值为200则为false),因为Integer会缓存 -128至127之间的数,这些数赋给Integer(不是new)
则不会生成新的对象。
14. 可变参数
可变参数如: String...(实际上是一个String[]) 一个方法最多只能有一个可变参数,且只能作为最后一个参数。
15. 枚举类型enum
1)枚举和class是一个级别的,每个定义的枚举类都继承Enum。
2)每个枚举的成员其实就是您定义的枚举类型的一個实例,用“,”隔开。
3)枚举的成员是固定个数的,在定义枚举的时候就指定,而且都是public static final的。
4)枚举也有构造方法(只能私有)和属性。
16. Class
一个类的对应的Class对象是该类加载到虚拟机的时候自动生成的,Class类没有公开的Constructor(构造方法)。
17. finalize()方法
JVM在准备释放某个类的内存的时候,会先调用finalize()方法。但是JVM回收内存是不定时的,
所以通常不要把回收资源的操作卸载finalize()方法中,这样可以避免内存不能及时回收。
18. 内部类
1)静态内部类:只能访问外部类的静态属性或方法(无论是private还是public)。
生成方式:Outer.Inner iner = new Outer.Inner();
2)成员内部类:可以访问外部类的所有方法和属性。
生成方式: Outer.Inner iner = new Outer().new Inner();
3)局部内部类:方法中的类,访问方法中定义的变量时,该变量必须为final,只能在方法中生成实例(运用较少)。
4)匿名内部类:通常作为实参传入方法,用于回调。
如调用go(Date date)方法:
go(new Date() {}); 此时实参为一个继承了Date的匿名内部类。若“Date”是一个interface,
则实参为一个实现了 该接口的匿名内部类。
19. 多线程
线程分为4个状态,创建、可运行、运行、消亡(Create、Runable、Running、Destroy)。
多线程中结束该线程不能使用stop()方法,应该是等待run()方法运行完毕(可用return控制)。
多线程同步:
Java中每一个对象都有一个锁(lock)或则叫监视器(monitor))
1)synchronized成员方法:当一个线程访问一个对象的synchronized成员方法时,会将该对象锁住,
其他线程无法访问该对象的所有synchronized成员方法,直到方法访问结束。
2)synchronized静态方法:一个类只有唯一一个Class对象,当一个线程访问该类的synchronized静态方法时,会将
该类的Class对象锁住,其他线程无法访问该类的所有synchronized静态方法,直到方法访问结束。
3)synchronized块:synchronized(obj){}
表示将obj上锁,当obj处于上锁状态的时候,则其他线程无法执行{}中的代码,直到obj(解锁,及执行完毕)。
通常使用方法3),因为方法3)可以写在方法内部,更加细腻。
20. 序列化
定义:将对象转化为字节流保存起来,并在以后还原这个对象。(Java中的标识性接口,Serializable接口)
serialVersionUID:
当对象被序列话到本地文件中的时候,对应的类发生了改变(如增加属性等),在被还原的时候就会出现异常。
这时候如果加上了serialVersionUID,那么就可以正常还原,多出来的属性会添加缺省值。所以,serialVersionUID
的作用就是保证类的向后兼容。
对象序列化:
当对象被序列化的时候,只会序列化非静态的成员变量(不能保存静态变量和方法),成员变量也可以
是对象(但是必须也实现了Serializable接口,否则抛出NotSerializableException,当然可以用transient关键字
标识该对象引用变量,那么序列化的时候就会忽略它)。
ObjectOutput、ObjectInput接口:
ObjectOutputStream、ObjectInputStream分别是两个接口实现类,两个类的write方法和read方法可以将对象写、读
到指定位置。两个类会封装节点流,从而写、读节点流的具体位置。
当实现了Serializable接口的序列化类中定义了以下两个方法,那么就可以更细致的控制序列化了。
private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
21. clone(克隆)
浅克隆:只可能对象中的非引用类型的变量,引用类型变量指向以前的对象。
深克隆:克隆所有变量。
浅克隆实现:某个类想要被浅克隆,则需要实现Cloneable接口,并且重写clone方法(并且把修饰符改为public)
深克隆的实现:利用序列化。
class Parent implements Serializable {
private static final long serialVersionUID = -9084900055110218109L;
public String name = "Parent";
public int age = 40;
public Son son = new Son();
/**
* 利用序列化深克隆
*/
public Parent copy() {
Parent newParent = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
newParent = (Parent) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return newParent;
}
}
class Son implements Serializable {
private static final long serialVersionUID = 5736736634035541535L;
public String name = "son";
}