1.JDK 和 JRE 有什么区别?
JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
2.== 和 equals 的区别是什么?
== 用来比较两个变量的值是否相同,也就是说,该运算符用于比较变量对应内存中值是否相同。对于 java 中的基本数据类型,变量是按值传递的,所以 == 就可以直接比较对应的值是否相等。但是如果变量指向的是对象,涉及到两块内存,一个是对象堆内存,该内存存储的是对象的值,而变量的内存中存储的是其指向对象内存的首地址,所以 == 操作符可以比较两个引用变量是否指向同一块内存空间,但是无法比较两个引用变量指向的对象内容是否相同。
equals 是 Object 类提供的方法之一,在 Object 的 equals 方法中是直接使用 == 比较的,所以如果类没用覆盖 Object 的 equals 方法,那么 == 和 equals 方法是一样的。equals 方法可以被覆盖以用来比较变量指向的对象内容,而不是引用。
3.如果两个对象的 hashCode() 相同,则 equals() 也一定为 true?
不一定。hashCode() 是 Object 提供的方法之一,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。关于 equals() 和 hashCode() 有两个规范,一是若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值,二是如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。根据这两个规范,可以得到如下推论:
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
2、如果两个对象不equals,他们的hashcode有可能相等。
3、如果两个对象hashcode相等,他们不一定equals。
4、如果两个对象hashcode不相等,他们一定不equals。
4.final、finally、finalize 在 java 中各有什么作用?
1.final 用于声明属性、方法和类,分别表示属性不可变,方法不可覆盖、类不可继承。被 final 修饰的变量不可变指的是引用不可变,而不关心指向对象内容的变化。final 参数表示参数在函数内部不允许被修改。一个类不能既被声明为 abstract 又被声明为 final。
2.finally 作为异常处理的一部分,只能用在 try/catch 语句中,finally 里的语句最终一定会执行。
3.finalize 是 Object 类的一个方法,gc 垃圾回收时会调用对象的 finalize 方法。
5.Java 中 Math.round(-1.5) 等于多少?
-1。
1.round 方法在原来数字的基础上增加 0.5 再向下取整。
2.ceil 方法是对操作数向上取整。
3.floor 方法是对操作数向下取整。
6.String 属于基础的数据类型吗?
不属于。java 中有八大基础数据类型:byte(8bit),short(16bit),int(32bit),long(64bit),float(32bit),double(64bit),char(2bit),boolean(4bit);
String 和以上八大基础类型的包装类属于不可变类,不可变类指创建这个类的实例后,就不允许修改它的值。实际上对 String 变量执行 += 字符串操作,并没有改变变量指向的 String 对象内容,而是使这个变量指向了另一个 String 对象。
引申1:String 对象的创建和存储机制:
(1)对于 String s1 = new String("abc") 和 String s2 = new String("abc") 会产生两个引用对象 s1,s2 ,分别指向两个内容都为 "abc" 的 String 对象,这两个String 对象在堆中,s1,s2 对象位于栈中。
(2)对于 String s1 = "abc" 和 String s2 = "abc" 语句,会首先在 JVM 的字符串常量池中利用 equals 方法查找是否有相同的字符串常量被定义,若有,则直接获取其引用,若没有,则创建这个 String 对象,将其放入字符串常量池,并返回其引用。
引申2:StringBuffer 和 StringBuilder
(1) StringBuffer 是可变类,即通过 StringBuffer 创建一个对象后,仍然可以对其值进行修改。当一个字符串经常需要被修改时,最好使用 StringBuffer 来实现;StringBuffer 只能通过构造函数来初始化。实际上 String 字符串修改的原理也是利用 StringBuffer 的 append 方法。
(2)StringBuilder 也是可以被修改的字符串,与 StringBuffer 类似,都是字符缓存区。但是不是线程安全的,在单线程里使用 StringBuilder 效率会更高一点。但是多线程中最后使用 StringBuffer。
7.抽象类必须要有抽象方法吗?
用 abstract 修饰的类就是抽象类,并不是说抽象类中必须有抽象方法,即使一个类中的方法全部实现过,也可以用abstract修饰为抽象类,所以抽象类不一定都有抽象方法。但有抽象方法的一定是抽象类。
引申1:普通类与抽象类有什么区别:
抽象类不能被实例化,但是可以创建一个对象指向具体子类的一个实例。抽象类的子类必须为父类中的所有抽象方法提供所有的实现,否则它也是抽象类。
引申2:抽象类和接口的异同
(1)接口和抽象类都是支持抽象类定义的两种机制。抽象类可以包含部分方法的实现,但是接口中的所有方法都是抽象的,都没有方法体,接口中的成员变量默认都是 static final 类型的,且只能有静态的数据成员,成员方法只能被 public abstract 修饰;抽象类不能实现多重继承,而接口可以有多个实现类。抽象类中的成员变量默认为 default (本包可见)类型;此外接口可以继承接口,抽象类也可以实现接口,抽象类可以继承具体类,抽象类可以有静态的 main 方法。
(2)接口和抽象类都不能被实例化;接口的实现类,抽象类的子类只有实现了接口或抽象类中的方法后才能被实例化。
8.Java 程序初始化顺序是什么样的?
Java 程序初始化一般遵循三个原则:
1.静态对象(变量)优先于非静态对象(变量),静态对象(变量)只能初始化一次,而非静态对象(变量)可能初始化多次。
2.父类优先于子类进行初始化。
3.按照成员变量定义的顺序进行初始化,即使变量定义散布于方法定义之中,它们依然在任何方法(包括构造函数)被调用之前先初始化。
Java 程序初始化可能在不同代码块中完成,顺序如下:父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类非静态变量,父类非静态代码块,父类构造器,子类非静态变量,子类非静态代码块,子类构造器。
9.什么是构造函数?
构造函数用来在对象实例化时初始化对象的成员变量。具有以下特定:
1.构造函数必须与类同名,并且不能有返回值,返回值也不能是 void。
2.一个类可以有多个构造函数,当没有提供构造函数,编译器会提供一个无参构造函数。
3.构造函数不能被继承,覆盖,但是能被重载。
4.子类可以利用 super 关键字显式调用父类的构造函数。若父类没有提供无参的构造函数,子类的构造函数中必须显式调用父类的构造函数,且在构造函数中必须为第一条语句。若父类提供无参的构造函数,子类的构造函数中就可以不显式调用父类的构造函数,编译器会默认调用父类的无参构造函数。
10.this 和 super 关键字有什么区别?
this 用来指向当前的实例对象,一个非常重要的作用就是用来区分对象的成员变量和方法的形参。super 可以用来访问父类的方法或成员变量。
11.Java 中 clone 方法有什么作用?
Java 在处理基本数据对象时是按值传递的(传递的是输入参数的复制),其他类型是按引用传递(传递的是对象的引用),所以如果需要创建与一个对象 A 具有相同状态的对象 B,并且对 B 的修改不会影响到 A,就无法通过赋值操作来实现 ,而 clone() 方法就能满足这个需求。使用 clone 方法的步骤:
1.实现 clone 的类需要继承 Cloneable 接口,该接口是一个标识接口,没有实现任何接口方法。
2.在类中重写 Object 类中 clone() 方法。
3.在 clone() 方法中调用 super.clone(),实现浅复制。
深复制:对对象调用 clone() 方法完成复制后,接着对对象中非基本类型的属性也调用 clone() 方法完成深复制。
12.volatie 有什么作用?
volatie 是一个类型修饰符,它被设计用来修饰被不同线程访问和修改的变量。被 volatie 类型定义的变量,系统每次用到它时都是直接从对应内存当中取,而不会利用缓存。在使用 volatie 修饰成员变量后,所有线程在任何时候所看到变量的值都是相同的。volatie 不能保证操作的原子性,不能替代 sychroized 关键字,而且会阻止编译器对代码的优化。尽量不要使用 volatie。