前言
主要讲解java的一些基础知识以及容易混淆的概念
实时更新汇总
如果想补充一些细节概念或者知识点可看
java零基础从入门到精通(全)
javaSE从入门到精通的十万字总结(全)
java语言有哪些特点?
面向对象、可靠性、安全性、支持多线程(c++调用操作系统的的多线程)、支持网络编程、编译与解释并存
1. JDK、JRE和JVM区分
JVM是不能独立安装的。
JRE和JDK都是可以独立安装的
层层嵌套
JDK = JRE + 开发工具集(例如Javac编译工具等)
JRE = JVM + Java SE 标准类库
- JRE:java运行环境
- JDK:Java开发工具箱
- JVM:java虚拟机
主要讲解jdk与jre的区别
jdk(Java Development Kit):java 开发工具包
jre(Java Runtime Environment):java 运行环境
层层嵌套主要记住,==jvm包括jdk,jdk包括jre==即可
而且主要的区分点是看你用在什么方面
在编写java程序的时候,jdk很适合,因为要开发工具箱
如果在编译java的时候,jre很适合,因为需要java的运行环境
2. == 和 equals 的区别
java常考的面试中也有一个这个
主要是容易混淆并且记乱
主要的区分度是
- == 在基本类型中是值比较,对于引用类型是地址比较
- equals 是引用比较,但在多数类中(比如String、Integer 等)重写equals方法,导致很多都是值比较
equals( )∶它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。
情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。使用的默认是0bject类equals()方法。
情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
为了更好的显示这种区分度,下面以代码展示演示
先展示==的代码比较
注意下面的代码区分度
新建的空间比较不同是因为开辟了新空间,而且比较的时候比较的是引用类型(记住)
String x = "A";
String y = "A";
String z = new String("A");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
equals中比如在新建对象的时候,两个相同的数据对象为fasle
ceshi c1 = new ceshi("A");
ceshi c2 = new ceshi("A");
System.out.println(c1.equals(c2)); // false
//查看其源码
public boolean equals(Object obj) {
return (this == obj);
}
而String改写了equals方法
所以比较的时候是比较值
String s1 = new String("A");
String s2 = new String("A");
System.out.println(s1.equals(s2)); // true
//查看其源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
3. 抽象类和接口类细节区分
先回顾其两者特点:
抽象类是类和类之间的共同特征,将这些共同特征进一步形成抽象类,由于类本身不存在,所以抽象类无法创建对象。
类到对象是实例化,对象到类是抽象
抽象方法不能被 final 修饰,因为抽象方法就是被子类实现的
- 采用 abstract 关键字定义的类就是抽象类,采用 abstract 关键字定义的方法就是抽象方法
- 抽象的方法只需在抽象类中,提供声明,不需要实现
- 如果一个类中含有抽象方法,那么这个类必须定义成抽象类。抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中
- final和abstract不能同时同时使用,这两个关键字是对立的
- 抽象类的子类可以是抽象类。也可以是非抽象类
- 一个非抽象的类,继承抽象类,必须将抽象类中的抽象方法进行覆盖/重写/实现
接口是特殊的抽象类,类与类是继承extends,类与接口是实现implements,其实都是继承
- 接口是一种“引用数据类型”,完全抽象的,支持多继承,且一个接口可以继承多个接口,只有常量+抽象方法
- 所有的元素都是public修饰的,抽象方法的public abstract可以省略,常量的public static final可以省略,方法不能有方法体
通过其特点也可以讲述其不同
比如
- 抽象类可以有构造函数;接口不能有
- 类可以实现很多个接口;抽象类只能继承一个
- 接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符
4. final关键字
- final 修饰的类不能被继承
- final 修饰的方法不能被覆盖
- final 修饰的变量不能被修改
- 构造方法不能被 final 修饰
变量在没有赋值的时候可以定义可以声明
但如果输出变量就必须给予定义以及赋值
5. String类细节
String不是基本数据类型,String属于引用类型
String类是一个final类,因此不能被继承
6. String、StringBuffer 和 StringBuilder 区别
String是一个final类表示的类容不可改变
StringBuffer表示的内容可以修改
StringBuffer 和 StringBuilder 区别:
StringBuffer是线程安全的可以在多线程中使用
StringBuilder是线程不安全的,但是运行效率非常高
具体详细的区别可看
探秘Java中的String、StringBuilder以及StringBuffer
7. super和this对比
this:
- this 是一个引用,保存内存地址指向自己
- this 不能出现在静态方法中
- this 大部分情况下可以省略,在方法中区分实例变量和局部变量的时候不能省略
- “this(实际参数列表)”出现在构造方法第一行,通过当前的构造方法去调用
本类当中其它的构造方法
super:
super 代表了当前对象中从父类继承过来的那部分特征。this 指向一个独立的对象
super与this共有的
- super 和 this 都可以使用在实例方法当中
- super 不能使用在静态方法当中,因为 super 代表了当前对象上的父类型特征,静态方法中没有 this,肯定也是不能使用 super 的
- super 也有这种用法:“super(实际参数列表);”,这种用法是通过当前的构造方法调用父类的构造方法
==this 和 super 都是无法使用在静态方法当中的==
8. static与this对比
static和this指针的结合代码演示
static 的方法中不能直接访问实例变量,要访问实例变量必须先自己创建一个对象,通过“引用”可以去访问,不能通过 this 访问,因为在 static 方法中是不能存在 this 的
public class ThisTest {
int i = 10;
public static void main(String[] args) {
//这肯定是不行的,因为 main 方法带有 static,不能用 this
//System.out.println(this.i);
//可以自己创建一个对象
ThisTest tt = new ThisTest();
//通过引用访问
System.out.println(tt.i);
}
}
方法也同理,需要用对象去调用
实例方法必须先创建对象,通过引用去调用,在以上的 main 方法中并没有创建对象,更没有 this。
//错误代码示列:
public class ThisTest {
public static void main(String[] args) {
doSome();
}
public void doSome(){
System.out.println("do some...");
} }
正确代码示列:
public class ThisTest {
public static void main(String[] args) {
ThisTest tt = new ThisTest();
tt.doSome();
}
public void doSome(){
System.out.println("do some...");
} }
总结:
this 不能使用在 static 的方法中,可以使用在实例方法中,代表当前对象,多数情况下 this 是可以省略不写的,但是在区分局部变量和实例变量的时候不能省略,在实例方法中可以直接访问当前对象实例变量以及实例方法,在 static 方法中无法直接访问实例变量和实例方法
9. 重写和重载对比
重写是⼦类对⽗类的允许访问的⽅法的实现过程进⾏重新编写, 返回值和形参都不能改变。即 外壳不变,核⼼重写!重写⽅法不能抛出新的检查异常或者⽐被重写⽅法申明更加宽泛的异常。
重载是在⼀个类⾥⾯,⽅法名字相同,⽽参数不同。返回类型可以相同也可以不同。
- 重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
- 重写:发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。
1.返回值类型、方法名、参数列表必须相同,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
2.如果父类方法访问修饰符为private/final/static则子类就不能重写该方法,但是被static修饰的方法能够被再次声明。
3.构造方法无法被重写
10. 静态方法和实例方法对比
- 在外部调⽤静态⽅法时,可以使⽤"类名.⽅法名"的⽅式,也可以使⽤"对象名.⽅法名"的⽅式。(调⽤静态⽅法可以⽆需创建对象。)
实例⽅法只有"对象名.⽅法名"这种⽅式。
- 静态⽅法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态⽅法), ⽽不允许访问实例成员变量和实例⽅法;实例⽅法则⽆此限制
11. 静态变量和实例变量对比
静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有⼀份,在类的加载过程中,JVM只为静态变量分配⼀次内存空间。
实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象 的,在内存中,创建⼏次对象,就有⼏份成员变量
12. final、finally与finalize对比
- final是一个关键字。表示最终的。不变的
- finally也是一个关键字,和try联合使用,使用在异常处理机制中
- finalize()是Object类中的一个方法。作为方法名出现,finalize是标识符。这个方法是由垃圾回收器GC负责调用的
hashcode()与equals()
hashCode()的作用是获取哈希码,也称为散列码;它实际上是返回一个int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。散列表存储的是键值对(key-value),它的特点是:能根据“键"快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
为什么重写equals()也要重写hashcode()方法
如果两个对象相等,则hashcode一定也是相同的。两个对象相等,对两个对象分别调用equals方法都返回true。但是,两个对象有相同的hashcode值,它们也不一定是相等的。因此,equals方法被覆盖过,则hashCode方法也必须被覆盖。
以"HashSet如何检查重复”为例子来说明为什么要有hashCode?
当把对象加入HashSet时,HashSet 会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals ()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。
深拷贝与浅拷贝
- 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
- 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。