Java中的多态,子类调用父类方法
java
public static void main(String[] args) {
/* Child 继承于 Parent */
Parent parent = new Child(); // 只能调用父类和子类共有的方法,并且子类会覆盖父类的方法
Child child = new Child(); // 可以调用子类特有的方法
/*非静态方法的调用遵循动态绑定规则:运行时会根据引用变量所指向的 "实际对象类型" 来决定调用哪个类的方法
* 如果play方法是 static 修饰的,那么就会调用父类的 play 方法*/
parent.play(); // Calls Parent's play method
child.play2(); // child 调用自己独有而父类没有的方法 play2
}
下面演示了通过反射获取父类实例,然后调用play方法(play是私有的,子类重写了play方法):
java
Class<?> aClass = Class.forName("com.example.tipsdemo.classExtend.Parent");
System.out.println(aClass.getName());
Constructor<?> constructor = aClass.getConstructor();
Parent o = (Parent) constructor.newInstance();
o.sayHello();
// 通过反射访问父类中的私有方法,而不是子类中的私有方法,这一点要明确,因为我们反射的目标就是父类
Method play = aClass.getDeclaredMethod("play");
play.setAccessible(true);
play.invoke(o);
最终调用的还是父类的play()方法,因为我们反射的目标是父类,所以就会调用父类的play()方法
单例模式的饿汉和懒汉是什么
单例模式有两种实现方式,一种是饿汉一种是懒汉,他们的区别就是实例创建的时机不同,饿汉式类初始化的时候就会创建一个单例的对象,这个对象属于类信息。因为指挥创建一次所以也就避免了线程安全的问题。懒汉式是在使用的时候创建单例对象,存在线程安全问题,我们可以通过双重锁检查的方式避免并发问题,具体的代码如下:
java
// 饿汉
public class Singleton {
// 1. 私有静态变量:类加载时直接初始化实例
private static final Singleton INSTANCE = new Singleton();
// 2. 私有构造器:阻止外部通过 new 创建实例
private Singleton() {}
// 3. 公共静态方法:返回唯一实例
public static Singleton getInstance() {
return INSTANCE;
}
}
java
// 懒汉
public class Singleton {
// 1. 用 volatile 防止指令重排序导致的半初始化问题
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 2. 第一次检查:未加锁,提高效率
synchronized (Singleton.class) { // 加锁
if (instance == null) { //3. 第二次检查:防止多线程同时通过第一次检查
instance = new Singleton();
}
}
}
return instance;
}
}
为什么要进行第二次的锁检查? 比如有两个线程A和B,A和B在判断instance==null的时候都返回的是true,那么他们就都会进入同步代码块,比如A先进入synchronized代码块,然后B阻塞在synchronized代码块之外,当A创建完成实例之后就会释放锁,那么B就会进入synchronized代码块,此时已经有一个实例了,B不应该再次创建实例,但是如果我们不添加第二次检查,即instancee==null,就会再次创建实例,这是不期望的。所以应该在同步代码块中再加一次检查。
final、finally、finalizer
名称 | 类型 | 核心作用 | 常见场景 |
---|---|---|---|
final |
修饰符 | 限制类、方法、变量的可变性(不可继承 / 重写 / 修改) | 定义常量、禁止继承 / 重写、线程安全等 |
finally |
异常处理块 | 确保关键代码(如资源释放)必定执行 | 搭配 try/catch 释放文件、数据库连接等 |
finalize() |
实例方法 | 对象被 GC 前的清理操作(已过时) | 早期用于释放非 Java 资源(不推荐使用) |
两个线程交替执行
java
package com.example.tipsdemo.pool;
import ch.qos.logback.classic.pattern.ClassOfCallerConverter;
public class Poll2 {
public static void main(String[] args) {
Task01 task01 = new Task01();
Thread thread_1 = new Thread(task01,"thread_1");
Thread thread_2 = new Thread(task01,"thread_2");
thread_1.start();
thread_2.start();
}
static class Task01 implements Runnable {
private static final Object lock = new Object();
private static int sum = 0;
private static int count = 0; // 总执行次数计数器(控制总次数为1000)
private static boolean flag = true;
@Override
public void run() {
while(count<1000){
synchronized (lock){
while((flag && Thread.currentThread().getName().equals("thread_1")) || (!flag && Thread.currentThread().getName().equals("thread_2"))){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sum++;
System.out.printf("当前线程:"+Thread.currentThread().getName()+ ", count=" + count +"sum = " + sum + "\n");
flag = !flag;
count++;
lock.notify();
}
}
}
}
}
三个线程交替执行
java
package com.example.tipsdemo.pool;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Poll3 {
private static int count = 0;
static ReentrantLock lock = new ReentrantLock();
static Condition c1 = lock.newCondition();
static Condition c2 = lock.newCondition();
static Condition c3 = lock.newCondition();
static int turn = 1;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
runTask(1,c1,c2);
}, "A");
Thread thread2 = new Thread(() -> {
runTask(2,c2,c3);
}, "B");
Thread thread3 = new Thread(() -> {
runTask(3,c3,c1);
}, "C");
thread1.start();
thread2.start();
thread3.start();
}
public static void runTask(int myTurn, Condition curCondition, Condition nextCondition) {
while (count < 100) {
lock.lock();
try {
while (turn != myTurn) {
curCondition.await();
}
System.out.println("当前线程是:" + Thread.currentThread().getName() +",turn = " + turn + ",myTurn = " + myTurn);
count++;
turn = (turn + 1);
if(turn >3) turn =1;
nextCondition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}