Java 平台的理解
码老湿,你是怎么理解 Java 平台呢?
Java 是一种面向对象的语言,有两个明显特性:
- 跨平台能力:一次编写,到处运行(Write once,run anywhere);
- 垃圾收集:
Java 通过字节码和 Java 虚拟机(JVM)这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现「一次编译,到处执行」的基础。
Java 通过垃圾收集器(Garbage Collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。
最常见的垃圾收集器,如 SerialGC、Parallel GC、 CMS、 G1 等,对于适用于什么样的工作负载最好也心里有数。
JVM、JRE、JDK关系
码老湿,能说下 JVM、JRE 和 JDK 的关系么?
JVM Java Virtual Machine
是 Java 虚拟机,Java 程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。
JRE Java Runtime Environment
包括 Java 虚拟机和 Java 程序所需的核心类库等。
核心类库主要是 java.lang
包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包
如果想要运行一个开发好的 Java 程序,计算机中只需要安装 JRE 即可。
JDK Java Development Kit
是提供给 Java 开发人员使用的,其中包含了Java 的开发工具,也包括了JRE。
所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe) 等。
Java 是解释执行么?
码老湿,Java 是解释执行的么?
这个说法不太准确。
我们开发的 Java 的源代码,首先通过 Javac 编译成为字节码(bytecode),在运行时,通过 Java 虚拟机(JVM)内嵌的解释器将字节码转换成为最终的机器码。
但是常见的 JVM,比如我们大多数情况使用的 Oracle JDK 提供的 Hotspot JVM,都提供了 JIT(Just-In-Time)
编译器。
也就是通常说的动态编译器,JIT 能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。
采用字节码的好处
什么是字节码?采用字节码的好处是什么?
字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。
采用字节码的好处:
众所周知,我们通常把 Java 分为编译期和运行时。这里说的 Java 的编译和 C/C++ 是有着不同的意义的,Javac 的编译,编译 Java 源码生成“.class”文件里面实际是字节码,而不是可以直接执行的机器码。Java 通过字节码和 Java 虚拟机(JVM)这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现“一次编译,到处执行”的基础。
基础语法
JDK 1.8 之后有哪些新特性
接口默认方法:Java8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可。
Lambda表达式和函数式接口:Lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码。
Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中),使用Lambda表达式使代码更加简洁,但是也不要滥用,否则会有可读性等问题,《EffectiveJava》作者JoshBloch建议使用Lambda表达式最好不要超过3行。
StreamAPI:用函数式编程方式在集合类上进行复杂操作的工具,配合Lambda表达式可以方便的对集合进行处理。
Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用StreamAPI对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用StreamAPI来并行执行操作。
简而言之,StreamAPI提供了一种高效且易于使用的处理数据的方式。
方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。
与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
日期时间API:Java8引入了新的日期时间API改进了日期时间的管理。Optional类:著名的NullPointerException是引起系统失败最常见的原因。
很久以前GoogleGuava项目引入了Optional作为解决空指针异常的一种方式,不赞成代码被null检查的代码污染,期望程序员写整洁的代码。
受GoogleGuava的鼓励,Optional现在是Java8库的一部分。
新工具:新的编译工具,如:Nashorn引擎jjs、类依赖分析器jdeps。
构造器是否可以重写
Constructor不能被override(重写),但是可以overload(重载),所以你可以看到⼀个类中有多个构造函数的情况。
wait() 和 sleep 区别
来源不同:sleep()来自Thread类,wait()来自Object类。
对于同步锁的影响不同:sleep()不会该表同步锁的行为,如果当前线程持有同步锁,那么sleep是不会让线程释放同步锁的。
wait()会释放同步锁,让其他线程进入synchronized代码块执行。
使用范围不同:sleep()可以在任何地方使用。wait()只能在同步控制方法或者同步控制块里面使用,否则会抛IllegalMonitorStateException。
恢复方式不同:两者会暂停当前线程,但是在恢复上不太一样。sleep()在时间到了之后会重新恢复;
wait()则需要其他线程调用同一对象的notify()/nofityAll()才能重新恢复。
&和&&的区别
&
运算符有两种用法:
- 按位与;
- 逻辑与。
&&
运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。
&&
之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。
注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
Java 有哪些数据类型?
Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。
分类
- 基本数据类型
- 数值型
- 整数类型(byte,short,int,long)
- 浮点类型(float,double)
- 字符型(char)
- 布尔型(boolean)
- 引用数据类型
- 类(class)
- 接口(interface)
- 数组([])
this 关键字的用法
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
this的用法在java中大体可以分为3种:
- 普通的直接引用,this相当于是指向当前对象本身。
- 形参与成员名字重名,用this来区分:
public Person(String name, int age) { this.name = name; this.age = age; }
- 引用本类的构造函数
class Person{ private String name; private int age; public Person() { } public Person(String name) { this.name = name; } public Person(String name, int age) { this(name); this.age = age; } }
super 关键字的用法
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
super也有三种用法:
- 普通的直接引用:与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。
- 子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分
lass Person{ protected String name; public Person(String name) { this.name = name; } } class Student extends Person{ private String name; public Student(String name, String name1) { super(name); this.name = name1; } public void getInfo(){ System.out.println(this.name); //Child System.out.println(super.name); //Father } } public class Test { public static void main(String[] args) { Student s1 = new Student("Father","Child"); s1.getInfo(); } }
- 引用父类构造函数;
成员变量与局部变量的区别有哪些
变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域。
成员变量:方法外部,类内部定义的变量。
局部变量:类的方法中的变量。
区别如下:
作用域
成员变量:针对整个类有效。 局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
存储位置
成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
生命周期
成员变量:随着对象的创建而存在,随着对象的消失而消失 局部变量:当方法调用完,或者语句结束后,就自动释放。
初始值
成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。