接口和抽象类的区别
接口
-
一个类实现了多个接口,那么必须实现接口中所有的抽象方法,如果方法相同,那么只需要Override一次。
-
所有接口中的默认方法也可以被继承,但是如果两个接口有重名的默认方法,类必须Override这个方法。
-
一个类,有基类,同时实现了接口,接口中有默认方法,且接口中的默认方法和基类的方法同名,那么会优先使用基类中的方法。
-
一个接口可以继承一个或多个接口,即接口是可以多继承的。
-
接口里不能有成员变量,构造函数,static静态代码块,不可以创建对象
-
接口里可以有常量:public static final
抽象类
-
抽象类用来描述一种类型应该具备的基本特征与功能, 具体如何去完成这些行为由子类通过方法重写来完成
- 如:猫和狗都属于动物类并且狗和猫都吃食物,但是吃的食物是不同的,所以动物类规定了有吃食物功能,但并不明确吃食物的细节。吃食物的细节应该由猫与狗这样的动物子类重写吃食物的方法具体实现。即抽象方法指只有功能声明,没有功能主体实现的方法。
-
具有抽象方法的类一定是抽象类,但是抽象类不一定包含抽象方法,抽象类可以有非抽象方法
-
抽象类,抽象方法的定义
-
public abstract 返回值类型 方法名(参数); 抽象类定义的格式: public abstract class 类名 { } 看如下代码: //员工 public abstract class Employee{ public abstract void work();//抽象函数。需要abstract修饰,并分号;结束 } //manager public class Teacher extends Employee { public void work() { System.out.println("正在赋予权限"); } } //customer public class Assistant extends Employee { public void work() { System.out.println("正在使用该系统"); } } //开发人员 public class Manager extends Employee { public void work() { System.out.println("正在维护此系统"); } }
-
-
抽象类无法直接创建对象,只能被子类继承后,创建子类对象。
- 子类需要继承抽象父类并完成最终的方法实现细节(即重写方法,完成方法体)。而此时,方法重写不再是加强父类方法功能,而是父类没有具体实现,子类完成了具体实现,我们将这种方法重写也叫做实现方法。
-
抽象类一定是个父类,因为抽象类是不断抽取共性需求而来的。
-
抽象类中是可以不定义抽象方法的,此时仅仅是不让该类创建对象,用于某些特殊的设计需要。
-
设计时由具体类抽取出抽象类,而开发阶段应该先定义抽象父类,再根据不同需求由父类定义子类。
接口与抽象类的区别
- 接口的默认方法是public,所有的方法在接口中不能有实现(JDK8开始接口方法可以有默认实现,JDK9的接口允许定义私有方法),而抽象类可以有非抽象的方法。
- 接口中除了static、final变量,不能有其他变量,而抽象类中不一定。
- 一个类可以实现多个接口,但只能实现一个抽象类,接口本身可以通过extends关键字拓展多个接口
- 接口方法默认修饰符是public,抽象方法可以有public、protected和default这些修饰符(抽象方法不能用private修饰)
- 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。
==与equals
==:
它的作用是判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。如果进行比较的两个操作数都是数值类型,即使他们的数据类型不相同,只要他们的值相等,也都将返回true.如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而且这两个引用必须指向同一个对象,才会返回true。
equals():
equals()方法是Object类中的方法,它的作用也是判断两个对象是否相等,我们知道所有的类都继承Object,而且Object中的equals()方法内部实际就是使用==进行比较的而且没有用final修饰,所以我们在使用equals()方法的时候需要关注的就是这个类有没有重写Object中的equals()方法。
如果没有重写,则通过equals()比较该类两个对象时,等价于通过==比较
如果面试官问你区别,你可以这么说
1)对于==,比较的是值是否相等
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
几点解释
有如下代码
public static void main(String[] args) {
//-128 ~ +127 之间
Integer a = 5;
int b = 5;
Integer c = new Integer(5);
Integer d = 5;
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a.equals(c));
System.out.println(a == c);
System.out.println(a == d);
//-128 ~ +127 之外
a = 128;
b = 128;
c = new Integer(128);
d = 128;
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a.equals(c));
System.out.println(a == c);
System.out.println(a == d);
}
结果
//-128 ~ +127 之间
true
true
true
false
true
//-128 ~ +127 之外
true
true
true
false
false
Process finished with exit code 0
疑问:
ystem.out.println(a == d); 同样的表达式,不同的值为什么结果不同
System.out.println(a == c); 与 System.out.println(a == d); 同样的对象类型,为什么复制方式不一样,比较结果不一样
System.out.println(a == c); 与 System.out.println(a.equals©); 不同的比较方式,结果为什么不同
解答:
首先我们看a,c,d三个变量的赋值方式,其中a和d的赋值方式都是直接赋值,没有调用new关键字,只有d的赋值方式调用了new关键字.然后我们在看赋值的具体数值,一组是在-128 ~ +127 之间,另一组是128在/-128 ~ +127 之外.我们可以通过已知的不同点去阅读源码.(其中不同的比较方式为什么结果不同,这个可以猜出一定是Integer重写了equals()方法.)
赋值方式中如果调用了new关键字,一定会在内存中给你分配一个新的地址
给Integer类型赋值的时候,如果没有调用new关键字,并且值在-128与+127之间,包括-128和+127,那么指向的都是同一个内存位置.
Integer类中重写了equals()方法,使用equals()方法进行比较的时候,实际上比较的内存中最终指向的值的内存位置,不是直接比较变量的内存位置.
重写的equals()方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
一点总结
【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer a = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,
推荐使用 equals 方法进行判断。
线程、程序、进程的基本概念以及之间的关系
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一款内存空间和一组系统资源,所以系统产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小很多,也正因为如此,线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或者其他数据存储设备中,也就是说程序是静态的代码。
进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程一般由程序,数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时所需要的数据和工作区;程序控制块包含进程的描述信息和控制信息是进程存在的唯一标志。
线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
为何不使用多进程而是使用多线程?
线程廉价,线程启动比较快,退出比较快,对系统资源的冲击也比较小。而且线程彼此分享了大部分核心对象(File Handle)的拥有权
如果使用多重进程,但是不可预期,且测试困难
回复【项目资料】领取各种项目全套资料
B站搜【Java小学堂】看数据结构与算法