java根类Object的方法
toString()、equals(Object obj)、hashcode()、clone()、finalize()、wait()、notify()、notifyAll()、Class<?> getClass()
-
Object是类层次结构的根类,所有的类都直接或间接的继承自Object
-
Object类的构造方法只有一个,并且是无参构造方法。
(子类构造方法默认访问父类的无参构造方法) -
toString()
返回对象的字符串表示,默认是 类的全路径+‘@’+哈希值的十六进制表示。一般都会重写该类 -
equals(Object obj)
比较对象是否相同。默认比较地址值。
重写需要满足等价关系即自反性、对称性、传递性和一致性,且x.equals(null)必须返回false。
一般重写的规律:
1、==检查是否相同的对象引用。
2、instanceof检查是否正确的类型。
3、把参数强转为正确的类型。
4、检查参数中的域是否与该对象的域相匹配。
instanceof在第一个操作数为null时返回false,所以没有必要单独对参数进行非null判断。 -
hashCode()
返回对象的hashcode。
为了散列集合正常运作,重写equals时必须重写hashCode(),确保equals相等时hashcode也相等。
虽然equals不等hashcode不一定要相等,但是给不相等的对象产生不同的hashcode能够提高散列表的性能。 -
clone()
Java提高篇——对象克隆(复制)
protected且是native方法。-
因为java程序是运行在jvm虚拟机上面的,要想访问到比较底层的与操作系统相关的只能有靠近操作系统的语言来实现(C、C++等)所以有了native方法。clone方法是底层实现的,比手动拷贝快。
-
System.arraycopy() 浅拷贝,本地方法
-
要调用clone需要实现Clonenable接口,该接口为标记接口(不含任何方法),不实现的话在调用clone方法会抛出CloneNotSupportedException异常。
-
protected使该方法不能在类外访问,只有子类能调用父类的clone方法,所以需要重写,提升访问控制级别为public。
-
-
一般需要保证拷贝对象有新的内存地址分配。
-
浅拷贝:不拷贝引用类型的成员变量。只复制引用。
-
深拷贝:拷贝所有的引用类型的成员变量。所有的引用都有新的内存空间。
-
泛型和Object的区别,泛型可由编译器来保证类型安全,如果使用Object在强转时可能会出现类型转换异常。
-
finalize()
可在垃圾回收时复活对象或释放资源,不建议使用,没有必要用它。
对象只能调用一次。
在GC第一次标记时会检查对象是否用过了finalize,用过了就标记,没用过就将对象放进一个队列里,另起一个线程执行这个队列里的对象的finalize方法。 -
wait()
释放锁,同时当前线程休眠等待被唤醒。
建议把wait调用放在一个循环中,以避免在公有可访问对象上的意外或恶意的通知。或者notifyAll的时候所有被唤醒的线程能够先判断条件是否满足。(《Effective Java》第69条) -
notify()
拿到锁前提下,随机唤醒一个休眠的线程,退出同步块才释放锁。
被唤醒的线程需要等待锁被释放后才能继续执行。
一般优先使用notifyAll。 -
notifyAll()
唤醒所有的等待线程。
必须与synchroized一起使用,因为只有获得锁后才能wait和notify,否则抛出异常java.lang.IllegalMonitorStateException。
可以使用wait和notify函数来实现线程间通信,但是在java.util.concurrent包中提供了更高级的工具,没有必要使用wait和notify。
生产者消费者问题中,应该被synchronized的对象是缓冲区队列。
如果缓冲区队列满了,那么生产者线程应该等待。
如果缓冲区队列为空,那么消费者线程应该等待。
Producter
synchronized(list) {
while(list.size()==maxSize){
try{
list.wait();
} catch(Exception e) {
e.printStackTrace();
}
}
list.add(new Random().nextInt());
list.notifyAll();
}
Consumer
synchronized(list) {
while(list.isEmpty()){
try{
list.wait();
} catch(Exception e) {
e.printStackTrace();
}
}
list.remove();
list.notifyAll();
}
使用阻塞队列LinkedBlockingQueue解决生产者消费者问题。
BlockingQueue接口 是一个线程安全的可用于存取对象的队列。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class Producer implements Runable {
protected BlockingQueue<Object> queue;
Producer(BlockingQueue<Object> queue) {
this.queue = queue;
}
public void run() {
try {
while(true) {
queue.put(new Object()); //队列满了会阻塞当前线程直到消费者线程从队列中取走资源
}
} catch(InterruptedException e) {
System.out.println("Producer interrupted");
}
}
}
class Consumer implements Runable {
protected BlockingQueue<Object> queue;
Consumer (BlockingQueue<Object> queue) {
this.queue = queue;
}
public void run() {
try {
while(true) {
queue.take(); //队列为空会阻塞当前线程直到生产者线程生产资源
}
} catch(InterruptedException e) {
System.out.println("Producer interrupted");
}
}
}
public class ProducerConsumerExample {
public static void main(String[] args) throws InterruptedException {
int numProducers = 4;
int numConsumers = 3;
BlockingQueue<Object> myQueue = new LinkedBlockingQueue<>(20);
for (int i = 0; i < numProducers; i++) {
new Thread(new Producer(myQueue)).start();
}
for (int i = 0; i < numConsumers; i++) {
new Thread(new Consumer(myQueue)).start();
}
// Let the simulation run for, say, 10 seconds
Thread.sleep(10 * 1000);
}
}
- getClass()
返回字节码Class对象
反射机制