注:C++11 开始(2011 年的时候),C++就引入了多线程库,在 windows、linux、macos 都可以使用stdÇÉthread和stdÇÉasync来创建线程。参考链接:http://www.cplusplus.com/reference/thread/thread/?kw=thread
Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM 有针对不同系统的特定实现(windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。
什么是字节码?采用字节码的好处是什么?
Java 程序从源代码到运行一般有下面3步:
需要格外注意的是: .class -> 机器码 这一步。在这一步,JVM 类加载器首先会加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢;而且,有些方法和代码块是经常需要被重复调用的(也就是所谓的热点代码),所以后面引进了 JIT 编译器,而 JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。我们知道,机器码的运行效率是肯高于 Java 解释器的。这也解释了我们为什么会说 Java 是 编译与解释共存的语言。
HotSpot 采用了惰性评估(Lazy Evaluation)的做法,根据二八定律,消耗大部分系统资源的只有那一小部分的代码(热点代码),而这也就是 JIT 所需要编译的部分。JVM 会根据代码每次被执行的情况收集信息并相应地做出一些优化,因此执行的次数越多,它的速度就越快。JDK 9 引入了一种新的编译模式 AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了JIT 预热等各方面的开销。JDK 支持分层编译和 AOT 协作使用。但是,AOT 编译器的编译质量是肯定比不上 JIT 编译器的。
总结:
Java虚拟机(JVM)是运行Java字节码的虚拟机,JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java语言 “一次编译,随处可以运行”的关键所在。
JDK 是 Java Development Kit,它是功能齐全的Java SDK。它拥有 JRE 所拥有的的一切,还有编译器(javac)和 工具(javadoc 和 jdb)。它能够创建和编译程序。
JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括Java虚拟机(JVM),Java类库,Java 命令和 其它的一些基础构件。但是,它不能用于创建新程序。
如果你只是为了运行一下 Java 程序的话,那么你只需要安装 JRE 就可以了。如果你需要进行一些Java 编程方面的工作,那么你就需要安装 JDK 了。但是,这不是绝对的。有时,即使您不打算在计算机上进行任何 Java 开发,仍然需要安装 JDK。例如,如果要使用 JSP 部署 Web 应用程序,那么从技术上讲,您只是在应用程序服务器中运行 Java 程序。那你为什么需要 JDK 呢?因为应用程序服务器会将 JSP 转换为 Java servlet,并且需要使用 JDK 来编译 servlet。
对于 Java 7,没什么关键的地方。OpenJDK 项目主要基于 Sun 捐赠的 HotSpot 源代码。此外,OpenJDK 被选为 Java 7 的参考实现,由 Oracle 工程师维护。
问:OpenJDK 存储库中的源代码与用于构建 Oracle JDK 的代码之间有什么区别? 答:非常接近 - 我们的 Oracle JDK 版本构建过程基于 OpenJDK 7 构建,只添加了几个部分,例如部署代码,其中包括 Oracle 的 Java 插件和 Java WebStart 的实现,以及一些封闭的源代码派对组件,如图形光栅化器,一些开源的第三方组件,如 Rhino,以及一些零碎的东⻄,如附加文档或第三方字体。展望未来,我们的目的是开源 Oracle JDK 的所有部分,除了我们考虑商业功能的部分。
总结:
一个程序中可以有多个类,但只有一个类是主类。在Java应用程序中,这个主类的类是包含在main() 方法的类中。而在Java小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。
简单来说应用程序是从主线程启动(也就是main()方法)。applet小程序没有main()方法,主要是嵌在浏览器页面上运行(调用init()或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。
Constructor 不能被 Override(重写),但是可以overload(重载),所以你可以看到一个类中有多个构造函数的情况。
发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,也可以抛出不同的异常。
下面是《Java 核心技术》对重载这个概念的介绍:
综上所述:重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写
综上:重写就是子类对父类的重新改造,外部样子不能改变,内部逻辑可以改变。
区别 | 重载 | 重写 |
---|---|---|
发生范围 | 同一个类 | 子类中 |
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可修改 | 一定不能修改 |
异常 | 可修改 | 可以减少或删除,一定不能抛出新的异常或更广的异常 |
访问修饰符 | 可修改 | 一定不能做更严格的限制(可以降低限制) |
发生阶段 | 编译期 | 运行期 |
封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,我们能够很方便的复用以前的代码。
注意:
多态就是同一个行为具有多个不同表现形式或形态的能力;
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态的优点:
多态存在的三个必要条件:
在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中的同一方法)。
可变性:
简单的来说:String 类 中使用 final 关键字修饰字符数组来保存字符串,private final char value[]
,所以String对象是不可变的。
注:Java 9 之后,String类的实现改用 byte 数组存储字符串
private final byte value[]
而 StringBuffer 和 StringBuilder 都继承自 AbstractStringBuilder 类,在AbstactStringBuilder 中也是使用字符数组保存字符串char value[]
,但是没有用 final 关键字修饰,所以这两种对象是可变的。
线程安全性:
String 中的对象是不可变的,也就可以理解为常量,线程安全。
AbstactStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以线程时安全的。StringBuilder 并没有对方法进行加同步锁,所以是 非线程安全的。
性能:
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的String对象。StringBuffer 每次都会对 StringBuffer 本身进行操作,而不是生成新的对象并改变对象引用。相同条件下,使用 StringBuilder 相比 使用 StringBuffer 仅能获得10% ~ 15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结:
基本数据类型对应的包装器类型:
int (4字节) | Integer |
---|---|
byte (1字节) | Byte |
short (2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char (2字节) | Character |
boolean(未定) | Boolean |
装箱和拆箱是如何实现的?
在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。其他的也类似,比如Double、Character
因此可以用一句话总结装箱和拆箱的实现过程:
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。
关于装箱和拆箱的更多内容以及面试必记,请访问:深入解剖Java中的装箱和拆箱
由于静态方法可以不通过对象调用,因此在静态方法里面,不能调用其他非静态变量,也不可以访问非静态变量成员。
Java 程序在执行子类的构造方法之前,如果没有用super()
来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()
来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。
解决方法是:在父类中加上一个不做事且没有任何参数的构造方法。
刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来使用。然而随着时间的推移,javax 逐渐地扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java包确实太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准 API 的一部分。
所以,实际上 java 和 javax 没有区别。这都是一个名字。
注:
总结一下 jdk7 ~ jdk 9,Java中接口概念的变化:
new 运算符,new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)。
方法返回值:是指我们获取到的某个方法体中的代码执行后产生的结果(前提是该方法可能产生结果);
返回值的作用:接收出结果,使得它可以用于其他的操作。
主要作用是完成对类对象的初始化工作;
可以执行;
因为一个类即使没有声明构造方法,也会有默认的不带参数的构造方法。
对象相等,比的是内存中存放的内容是否相等;
而引用相等,比较的是他们指向的内存地址是否相等。
帮助子类做初始化工作。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。