面向对象三个特征:封装、继承、多态。 首先注意接口与抽象之间的区别
实现与继承的区别
表面的区别就是单继承多实现
继承:如果多个类的某个部来分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。
实现:如果多个类处理的目标是一源样的,但是处理的方法方式不同,那么就定义一个接口,也就是一个标准,让他们的实现这个接口,各自实现自己具体知的处理方法来处理那个目标
第一、联系
继承和接口都能实现代码重用,提高开发效率。提现了实物的传递性,继承关系达到复用的目的。
对于继承和实现的区别主要体现在继承式子类与父类百的继承,实现是接口的实现。
使用继承,可以减少代码量,常用方度法可以不必定义,而是直接继承父类定义好了的方法,提高编程效率问。体现了软件的三特性之一的可复用性。
使用接口,答只定义方法,没有具体的方法体,实现该接口的类可以对接口中回的方法灵活的根据实际情况定义,很好的是程序具有灵活、复用的特性答。
两者区别:
1、修饰不同
不同的修饰符修饰;实现:implements,继承:extends;
2、数量不同
Java只支持“接口”的多继承,不支持“类“”的多继承;而继承在java中具有单根性,子类只能继承一个父类。
总结为:单继承,多实现。
3、属性不同
在接口中只能定义全局常量(static final),和无实现的方法;而在继承中可以定义属性方法,变量,常量等。
4、调用不同
某个接口被类实现时,在类中一定要实现接口中的抽象方法;而继承想调用那个方法就调用那个方法。
总结:
接口是:对功能的描述(方法/行为),接口传达的意思是:拥有某种功能,能干嘛,比如:Serializable代表可序列化的。
继承是:什么是一种什么,继承传达的意思是:is-a,比如:猫 是一个 动物,猫就是动物的子类。
Runnable将数据共享这一特点完美诠释。
首先一定要明确的是,使用我们的Runnable接口与Thread类相比,解决了单继承的定义局限,所以在优先级上已经确定使用Runnable接口。
首先看jdk源码中Thread类定义:
public class Thread extends Object implements Runnable
发现Thread类实现了Runnable接口,那么这样一来就变为了以下形式。
image.png
我们可以看出,Runnable接口实现多线程其实很像代理模式的应用。很好的起到了设计模式中原则中的迪米特原则。之所以是"像",因为如果是代理设计模式,那么客户端调用的应该是接口里面提供的run()方法。
除了以上联系之外,使用Runnable接口可以比Thread类更好的描述出数据共享这一个概念,此时的数据共享指的是多个线程访问同一资源的操作。
范例:观察代码(每一个线程对象都必须通过start()启动)
package TestDemo;
class MyThread extends Thread{
private int ticket=10;//这里的变量会压入局部变量表 因为并没有用static声明
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(this.ticket>0){
System.out.println("sell,ticket="+this.ticket--);
}
}
}
}
public class TestDemo{
public static void main(String[] args) {
MyThread thread1=new MyThread();
MyThread thread2=new MyThread();
MyThread thread3=new MyThread();
thread1.start();
thread2.start();
thread3.start();
}
}
image.png
结果三个thread类都在卖各自的10张票,这是由于我们并没有给ticket设置为static变量,所以这个数据没有被录入元数据区,而被压入了局部变量表,在执行实例化操作后,各自生成了一块堆内存指向,此时并不存在数据共享这一概念。
在JVM内存模型基础上,我们可以看这张基于多线程的内存模型。
image.png
也很好的诠释了这一点。而Runnable就完美实现了这张内存模型图,我们可以把主存看作是MyThread类中的元数据,三个new Thread类匿名内部类对象实例看作3块工作内存。
范例:利用Runnable实现。
package TestDemo;
class MyThread implements Runnable{
private int ticket=10;//这里的变量会压入局部变量表 因为并没有用static声明
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(this.ticket>0){
System.out.println("sell,ticket="+this.ticket--);
}
}
}
}
public class TestDemo{
public static void main(String[] args) {
MyThread mt=new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
image.png
原理分析:这是由于三个不同的栈都指向了同一块堆内存对象,确保了他们操作的是同一个实例化对象。
因而当多个线程访问同一资源时候,我们使用Runnable更好的描述了数据共享这个概念(本质上是JVM虚拟栈是否指向同一块堆内存)
总结:请解释Thread类与Runnable接口实现多线程的区别(请解释多线程两种实现方式区别)?
Thread类是Runnable接口的子类,使用Runnable接口实现多线程可以避免单继承的局限性。
Runnable接口实现的多线程可以比Thread类实现的多线程更加清楚的描述数据共享的概念(本质上是JVM虚拟栈是否指向同一块堆内存)
可以将JVM内存布局以及基于多线程的内存模型画出来。
以及将两种多线程实现方式,白板编程出来。