抽象类和接口的区别
1.接口的方法默认是public,所有的方法在接口中不能有实现,而抽象类可以有非抽象方法。
2.接口中除了有static,final变量,不能有其他变量,而抽象类中则不一定。
3.接口的默认修饰符是public,抽象方法可以有public,protected和default这些修饰符。
4.一个类可以实现多个接口,但是只能实现一个抽象类。
final和static区别
成员变量:final修饰的成员变量表示常量,只能被赋值一次,赋值后不能被修改。
static修饰的变量可以被多次赋值。
类:final修饰的类不能被继承
static修饰的类,可以不用初始化就可以访问
方法:final修饰的方法可以被继承,但不能被子类重写。final不能修饰构造方法
static方法可以被继承,也不能被重写。
static在加载类的过程中完成静态变量的内存分配,可用类名直接访问。
static final组合使用修饰的变量为全局变量,一旦初始化就不能被修改,可以通过类名访问。修饰的方法不能被子类修改,可以被继承被调用。
Object中的方法
- getclass():用于返回当前运行时对象的 Class 对象
- toString():返回一个字符串
- equals():用于判断两个对象是否相等
- hashcode():用于返回该对象的哈希值,
- wait():暂停线程的执行
- notify():唤醒一个在此对象监视器上等待的线程。如果有多个线程在等待只会任意唤醒一个。
- notifyAll():唤醒所有在此对象监视器上等待的线程。
基本数据类型与包装类型
基本数据类型 | byte | short | int | long | float | double | boolean | char |
---|---|---|---|---|---|---|---|---|
包装类型 | Byte | Short | Integer | Long | Float | Double | Boolean | Character |
自动装箱就是java自动将基本类型值转换成包装类型值,比如将int变量转换成integer对象
自动拆箱是包装类型转换为基本类型,比如integer变量转换成int变量。
原理:
自动装箱时编译器调用valueOf将基本类型值转换成包装类型,自动拆箱时,编译器通过调用类似**intValue(),doubleValue()**这类方法将包装类型转换成原始类型
continue和break区别:
continue:指跳出当前的这一次循环,继续下一次循环
break:指跳出整个循环体,继续执行循环下面的语句
get和post请求区别:
1.get请求用来从服务器上获得资源,而post是用来向服务器提交数据。
2.get将表单中数据按照name = value的形式,添加到action所指向的URL后面,并且两者使用
"?”连接,而各个变量之间使用“&”连接;
post是将表单中的数据放在HTTP协议的请求头或者消息体中,传递到action所指向URL;
3.get传输的数据要收到URL⻓度限制,post可以传输大量的数据,上传文件通常使用post方式;
4.使用get时参数会暴露在地址栏中,如果这些数据不是敏感数据,那么可以使用get,反之,使用post。
5.get请求只能进行URL编码,post支持多种编码
6.get只接受ASCII字符,post没有限制
“==”和equals()区别:
1.对象类型不同:equals()是超类Object中的方法
“= =”是一个操作符。
2.比较对象不同:
equals():用来检测两个对象是否相等,即两个对象的内容是否相等
“= =”比较基础数据类型时,比较的是他们的值是否相等
“= =”比较引用数据类型时,比较的是引用的地址是否相等
浅拷⻉和深拷⻉
浅拷⻉:仅仅是指向被复制的地址,如果是地址发生改变,那么浅拷⻉出来的对象也会相应改变.如果是基本类型,拷⻉的就是基本类型的值,如果属性是引用类型,拷⻉的是内存地址,所以如果一个对象改变了,就会影响到另一个对象。
深拷贝:在计算机中开辟一块新的内存地址用于存放复制的对象。将一个对象从内存中完整的拷⻉一份出来,从堆内存中开辟一个新的区域存放新的对象,且修改对象不会影响原对象。
静态方法为什么不能直接访问非静态成员:
1.静态方法属于类,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
2.在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作.
“||”和“|”,“&&”和“&”的区别
“&”和“|”要对所有的条件进行判断,“&&”和“||”满足第一个条件,后面的条件就不再判断,
创建对象的四种方法
1.通过new方式创建对象
2.通过反射的方式创建对象
3.通过对象反序列化的方式来创建,这个类需要实现Serializable这个接口。
4.通过clone()的方式来创建,实现Cloneable接口。在内存中分配一个和原一模一样的空间,在此创建新的对象。
String,StringBuffer和StringBuild
1.可变性:
String不可变(String被声明为final,不可被继承。内部使用char数组存储数据,也是被final声明,内部没有改变数组的方法,因此不可变)。
StringBuffer和StringBuild可变
2.线程安全
String不可变,因此线程安全的
StringBuffer是线程安全的,内部使用synchronized进行同步
StringBuilder不是线程安全的
String类型安全的原因:
1.保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供修改这个字符串的方法。
2。String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变
HotSpot中字符串常量池保存在哪里?
JDK版本 | 是否有永久代,字符串常量池放在哪里 |
---|---|
JDK1.6及其以前 | 有永久代,运行时常量池(包含字符串常量池),静态变量存放在永久代上 |
JDK1.7 | 有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆里 |
JDK1.8及其之后 | 取消永久代,方法、常量保存在本地内存的元空间,但字符串常量池、静态变量还在堆中 |
重写和重载
重写:
存在继承体系中,指子类实现了一个与父类在方法声明上完全相同的方法。
子类方法的访问权限必须大于等于父类方法。
子类的返回类型必须是父类方法返回类型或为其子类型
重载:
存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数,个数,顺序至少有一个不同。(仅仅返回类型不同,不算重载)
final、finalize、 finally区别
final :是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。
finalize:在垃圾回收前调用该对象的finalize方法,回收资源。
finally: 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常
this和super的区别
1.属性:
this访问的是本类属性,如果本类没有该属性则在父类中继续查找。super访问的是父类的属性
2.方法:
this访问的是本类方法,如果本类没有该属性则在父类中继续查找。super访问的是父类的方法
3.构造器:
this访问的本类构造器,必须放在构造器首行。super调用父类构造,必须放在子类构造方法首行。
List、set、map区别
List是有序的,可重复的,可以有空值
set是无序的,不可重复的,可以有一个空值
map存放的是键值对。
泛型擦出
public class Test {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(123);
System.out.println(list1.getClass() == list2.getClass()); // true
}
}
我们定义了两个ArrayList数组,不过一个是ArrayList泛型类型的,只能存储字符串;一个是ArrayList泛型类型的,只能存储整数,最后,我们通过list1对象和list2对象的getClass()方法获取他们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下原始类型。
==原理:==在编译阶段,将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。
- <? extends Number>的类型参数被替换为Number
- <? super Number>被替换为Object。
问题
既然说类型变量会在编译的时候擦除掉,那为什么我们往 ArrayList 创建的对象中添加整数会报错呢?不是说泛型变量String会在编译的时候变为Object类型吗?为什么不能存别的类型呢?既然类型擦除了,如何保证我们只能使用泛型变量限定的类型呢?
答:Java编译器是通过先检查代码中泛型的类型,然后在进行类型擦除,再进行编译。
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的法的功能称为java语言的反射机制
用处
- 我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;
- Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性
在spring配置文件中,使用bean标签,添加对应属性,即可实现对象创建
<bean id="user" class="com.happy.learn.model.User"/>
<property name="age" value="12"/>
<property name="name" value="旺财"/>
</bean>
堆和栈的区别
堆和栈的区别主要有五大点,分别是:
1、申请方式的不同。栈由系统自动分配,而堆是人为申请开辟;
2、申请大小的不同。栈获得的空间较小,而堆获得的空间较大;
3、申请效率的不同。栈由系统自动分配,速度较快,而堆一般速度比较慢;
4、垃圾回收。栈不存在垃圾回收,堆存在垃圾回收。
5、底层不同。栈是连续的空间,而堆是不连续的空间。
数组和链表的区别
1.数组是静态分配内存的,链表是动态分配内存的
2.数组在内存中是连续的,链表不连续
3.数组元素在栈中,链表元素在堆中。