文章目录
- JDK、JRE和JVM的关系
- 栈和堆分别存的什么数据
- 异步和同步
- 线程和进程区别
- java的数据类型有哪些
- equals和HashCode重写的问题?
- 深拷贝和浅拷贝的区别
- ==和equals的区别
- 常见的运行时异常有哪些?
JDK、JRE和JVM的关系
JDK、JRE和JVM的关系:
- JDK(Java Development Kit)是Java开发工具包的缩写,包含了Java编译器、Java运行时环境(JRE)和其他开发工具。JDK是开发Java应用程序的必备工具,它提供了编写、编译、调试和运行Java程序所需的所有组件。
- JRE(Java Runtime Environment)是Java运行时环境的缩写,包含了Java虚拟机(JVM)和Java类库。JRE提供了Java程序运行的环境,包括了Java虚拟机和Java类库,可以让Java程序在任何支持Java虚拟机的操作系统上运行。
- JVM(Java Virtual Machine)是Java虚拟机的缩写,是Java程序执行的核心组件。JVM是一个虚拟计算机,它可以在任何支持Java虚拟机的操作系统上执行Java程序。JVM负责将Java源代码编译成字节码,并在运行时解释执行字节码。
因此,可以简单地将JDK看作是开发工具包,JRE看作是Java程序运行的环境,而JVM则是Java程序执行的核心组件。在实际使用中,通常需要安装JDK来开发Java应用程序,然后通过命令行或集成开发环境(IDE)来运行JRE来测试和调试Java程序,最终通过JVM来执行Java程序。
栈和堆分别存的什么数据
栈和堆是计算机内存中的两种数据结构,它们分别用于存储不同类型的数据。
-
栈(Stack):栈是一种后进先出(LIFO)的数据结构,也就是说最后进入栈的数据会最先被弹出。栈通常用于存储函数调用时的参数、局部变量、返回地址等数据。在Java中,基本类型数据(如int、float、char等)和对象引用都属于栈上数据,而数组元素也是栈上数据。
-
堆(Heap):堆是一种先进先出(FIFO)的数据结构,也就是说最先进入堆的数据会最先被弹出。堆通常用于存储动态分配的内存,比如Java中的new操作符创建的对象、数组等。在Java中,对象实例和数组元素都属于堆上数据。
补充:堆是一种树形数据结构,它可以动态地分配和回收内存,支持高效的插入、删除和排序等操作。
需要注意的是,Java中的垃圾回收机制会自动管理堆上的内存分配和释放,程序员不需要手动进行内存管理。
异步和同步
异步调用和同步调用都是指程序中不同组件之间的调用方式。
在同步调用中,**程序的某个组件会在调用另一个组件时等待该组件完成后,才会继续执行下一步操作。**也就是说,在同步调用过程中,程序的运行会阻塞等待被调用组件的响应结果。
而在异步调用中,程序的调用不会等待被调用组件返回结果,而是继续执行下一步操作。被调用组件会通过回调函数或事件通知的方式返回结果,程序在收到结果后再对其进行处理。也就是说,在异步调用过程中,程序的运行不会被阻塞,可以同时执行多个调用操作。
异步调用通常用于网络请求、GUI编程和其他需要同时处理多个任务的场景中,而同步调用通常用于需要依次处理任务的场景中。
线程和进程区别
线程和进程是操作系统中用于实现多任务处理的两个基本概念,它们有以下区别:
- 资源占用:一个进程可以独立占用系统资源,如内存、CPU等;而一个线程只能占用一定的系统资源,如栈空间、寄存器等。
- 调度:进程是操作系统中的独立实体,它可以被操作系统分配资源和调度执行;而线程是在进程内部的执行单元,它的调度由进程管理。
- 通信:由于进程之间是相互独立的,它们之间的通信需要通过进程间通信(IPC)机制来实现;而线程之间共享同一个进程的内存空间,因此可以直接进行通信。
- 数据保护:由于每个进程都有自己独立的内存空间,因此不同进程之间的数据是相互隔离的;而线程共享同一个进程的内存空间,因此需要注意数据保护的问题。
总之,线程和进程都是实现多任务处理的基本概念,它们各自具有不同的特点和优缺点,在实际应用中需要根据具体的需求选择合适的方式。
补充:**一个进程可以包含多个线程,这些线程共享同一个进程的内存空间和系统资源。**在Java中,一个进程可以包含多个线程,这些线程可以通过继承Thread类或实现Runnable接口来创建。
java的数据类型有哪些
类型 | 占用字节 | 取值范围 | 包装类 | 默认值 |
---|---|---|---|---|
byte(字节型) | 1 | -128~127(-2的7次方到2的7次方-1) | Byte | 0 |
short(短整型) | 2 | -32768~32767(-2的15次方到2的15次方-1) | Short | 0 |
int(整型) | 4 | -2147483648~2147483647(-2的31次方到2的31次方-1) | Integer | 0 |
long(长整型) | 8 | -9223372036854774808~9223372036854774807(-2的63次方到2的63次方-1) | Long | 0L |
float(浮点型) | 4 | 3.402823e+38~1.401298e-45(e+38 表示乘以10的38次方,而e-45 表示乘以10的负45次方 | Float | 0.0f |
double(双精度浮点型) | 8 | 1.797693e+308~4.9000000e-324(e+38 表示乘以10的38次方,而e-45 表示乘以10的负45次方 | Double | 0.0d |
boolean(布尔型) | 2 | true false | Boolean | false |
char(字符型) | 1 | 汉字字母都可以 | Character | \u0000 |
equals和HashCode重写的问题?
在Java中,Object类中提供了equals()和hashCode()方法用于比较对象是否相等以及生成对象的哈希码。默认情况下,equals()方法会比较对象的内存地址,而hashCode()方法则会根据对象的属性值计算出一个整数值作为哈希码。
重写equals方法后,即使两个对象的属性值完全相同,它们也被认为是相等的。这是因为equals方法比较的是对象是否相等,而不是对象的哈希码是否相等。
因此,如果我们不重写hashCode方法,那么即使两个对象相等,它们的哈希码也可能不同。这会导致在使用哈希表等数据结构时出现意外的结果。
另外,如果多个对象具有相同的属性值,那么它们可能会被认为相等,从而出现在哈希表中出现多次的情况。这会影响哈希表的性能和正确性。
因此,为了保证对象在哈希表中的正确性和性能,我们需要重写hashCode方法,确保每个对象都有唯一的哈希码。通常的做法是将每个属性的值取反后再进行求和,这样可以避免哈希冲突的问题。
一般情况下,我们保证,当两个对象的Hashcode相同的时候对象不一定相同,但是当两个对象的equals方法相同时,这两个对象一定相同。
**举例:**如果我们有1000万个对象,这个时候要找出外界输入的对象,判断和我们1000万个对象中哪个对象相等,这个时候我们会先调用hashcode方法,去大大的缩小范围,然后再使用equals方法,这样就可以大大提高我们寻找对象的速度。
深拷贝和浅拷贝的区别
**浅拷贝:**浅拷贝是指只复制对象本身的值,不复制它所引用的对象,因此新旧对象共享同一个引用对象。在 Java 中,可以通过实现 Cloneable 接口和覆盖 clone()
方法来实现浅拷贝。
**深拷贝:**深拷贝是指复制对象本身和所有它所引用的对象,因此新旧对象不共享任何引用对象。在 Java 中,可以通过实现 Serializable 接口和使用序列化/反序列化来实现深拷贝。例如:
==和equals的区别
-
== 既可以比较基本类型也可以比较引用类型,对于基本类型就是比较值,对于引用类型及时比较内存的地址
-
equals的话,他是属于java.lang.Object类里面的方法,如果该方法没有被重写过,默认也是== ,我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equasl是比较值的错误观点.
-
具体要看自定义类里面有没有重写Object的equals方法来判断
-
通常情况下,重写equals方法,会比较类中的属性是否相等
/**
* ==和equals的区别
*/
public class Test_01 {
public static void main(String[] args) {
/**
* 比较基本数据类型
*/
int a=1;
double b=1.0;
char c=1;
System.out.println(a==b); //true
System.out.println(a==c); //true
/**
* 引用数据类型
*/
Customer c1 = new Customer("小明", 20);
Customer c2 = new Customer("小明", 20);
System.out.println(c1 == c2); //false
System.out.println(c1.equals(c2)); //false
// String
String str1 = new String("sth");
String str2 = new String("sth");
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
// java中String new和直接赋值的区别
// 对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,
// 如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
String s1="123"; //在常量池中
String s2="123";
System.out.println(s1==s2); //true
String s3 = new String("123"); //存储在堆内存中
System.out.println(s1==s3);
/**
* Integer
*/
Integer i1=1;
Integer i2=1;
System.out.println(i1==i2); //true
Integer i3=128;
Integer i4=128;
System.out.println(i3==i4); //false
System.out.println(i3.equals(i4));
}
}
class Customer {
private String namg;
private int age;
public Customer(){
}
public Customer(String namg, int age) {
this.namg = namg;
this.age = age;
}
public String getNamg() {
return namg;
}
public void setNamg(String namg) {
this.namg = namg;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
常见的运行时异常有哪些?
ArithmeticException(算术异常)
ClassCastException(类转换异常)
IllegalArgumentException(非法参数异常)
IndexOutOfBoundsException(下标越界异常)
NullPointerException(空指针异常)
SecurityException(安全异常)