Java的一些知识点记录~
1,Java 的优势和劣势是什么?
首先,Java的优势,我记得跨平台应该是一个大点,因为JVM的存在,一次编写到处运行。然后面向对象,这个可能也是优势,不过现在很多语言都支持面向对象,但是Java的设计从一开始就是OOP的。还有强大的生态系统,比如Spring框架,Hibernate,各种库和工具,社区支持大,企业应用广泛。另外,内存管理方面,自动垃圾回收机制,减少了内存泄漏的问题,对开发者友好。还有多线程支持,内置的线程机制,方便并发编程。安全性方面,Java有安全模型,比如沙箱机制,适合网络环境。还有稳定性,企业级应用长期使用,版本更新也比较注重向后兼容。
劣势的话,性能可能是一个,虽然JVM优化了很多,但相比C++或者Rust这种原生编译语言,还是有一定开销。特别是启动时间,比如微服务场景下,可能不如Go之类的快。语法繁琐,比如样板代码多,之前没有lambda的时候更麻烦,现在有了但比起Python还是不够简洁。内存消耗,JVM本身占内存,对于资源有限的环境可能不太友好。还有面向对象过于严格,有时候写简单程序反而麻烦,虽然Java8引入了函数式编程,但不如其他语言自然。还有开发效率,相比动态语言如Python,Java需要更多代码,编译过程也可能拖慢开发节奏。
2,java为什么是跨平台的?
Java 能支持跨平台,主要依赖于 JVM 关系比较大。
JVM也是一个软件,不同的平台有不同的版本。我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。
而这个过程中,我们编写的Java程序没有做任何改变,仅仅是通过JVM这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。
JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。
编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。
所以,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你将Java程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。
跨平台的是Java程序,不是JVM。JVM是用C/C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。
3,Java中的堆和栈的区别是什么?分别放的是什么数据?
Java中的堆和栈的区别如下:
存储内容:栈用于存放局部变量和方法调用的上下文信,。局部变量涵盖基本数据类型变量以及对象引用变量。堆用来存储对象实例和数组,不管是通过new关键字创建的对象,还是数组,都会在堆上分配内存。
内存分配与回收:栈内存的分配和回收由系统自动完成。在方法调用时,会为该方法分配栈帧,方法执行结束后,栈帧会被自动弹出,释放内存。堆内存的分配和回收由垃圾回收器(GC)负责,当对象不再被引用时,GC 会在合适的时候回收该对象占用的内存。
访问速度:栈访问速度快,因为栈内存是连续分配的,并且栈指针的移动操作简单高效。堆访问速度相对较慢,因为堆内存的分配是动态的,需要进行内存查找和管理。
空间大小:栈每个线程都有自己独立的栈空间,栈空间一般较小,通常只有几 MB。堆堆内存是所有线程共享的,空间较大,可通过 JVM 参数进行调整。
下是一个简单的 Java 代码示例,用于说明堆和栈中存储的数据:
public class Example {
private static String staticVar = "Static"; // 堆(方法区)
private int instanceVar = 10; // 堆(对象实例内)
public void method() {
int localVar = 20; // 栈(局部变量)
Object obj = new Object(); // obj 引用在栈,Object 实例在堆
int[] arr = new int[5]; // arr 引用在栈,数组在堆
}
}
4,String a = new String(“123”)有哪些对象?
会创建一个或两个 String 对象,具体情况如下:
字符串常量池中的对象:当代码里出现字符串字面量 “123” 时,Java 会先去字符串常量池查看是否已有值为 “123” 的对象。要是没有,就会在字符串常量池中创建一个 String 对象来存储 “123”;若已有,就直接使用该对象。
堆内存中的对象:new String(“123”) 语句会在堆内存里创建一个新的 String 对象,此对象会复制字符串常量池中 “123” 对象的值。
比如下面的代码:
public class StringObjectCreation {
public static void main(String[] args) {
// 字符串常量池中的对象
String constantPoolStr = "123";
// 堆内存中的对象
String heapStr = new String("123");
// 比较常量池中的对象和堆内存中的对象
System.out.println(constantPoolStr == heapStr); // 输出 false,因为它们是不同的对象
// 比较内容
System.out.println(constantPoolStr.equals(heapStr)); // 输出 true,因为它们的内容相同
}
}
代码里的 “123” 会在字符串常量池中创建一个 String 对象。
new String(“123”) 会在堆内存中创建一个新的 String 对象。
== 运算符用于比较对象的引用,所以 constantPoolStr == heapStr 结果为 false。
equals 方法用于比较对象的内容,所以 constantPoolStr.equals(heapStr) 结果为 true。
所以,String a = new String(“123”);
一般会创建两个 String 对象,一个在字符串常量池中,另一个在堆内存中。不过,若字符串常量池中已经存在 “123” 对象,那就只会在堆内存中创建一个新的 String 对象。
5,String是不可变的对吧,有什么好处?
String 类是不可变的,也就是一旦一个 String 对象被创建,它的内容就不能被改变。主要的好处是:
由于 String 对象不可变,所以多个线程能够同时访问同一个 String 对象,不用担心数据被修改。这使得 String 在多线程环境下使用时无需额外的同步机制,保证了线程安全。
String 类重写了 hashCode() 方法,并且会在创建对象时缓存其哈希码。因为 String 不可变,所以它的哈希码不会改变,这就避免了重复计算哈希码,提高了在哈希集合(如 HashMap、HashSet)中的使用效率。
Java 的字符串常量池利用了 String 的不可变性。当多个字符串字面量具有相同的值时,它们会引用常量池中的同一个 String 对象,从而节省了内存空间。
TODO…