1.Java语言有哪些优势 ?
1.面向对象(封装,继承,多态);
2.平台无关性(Java虚拟机实现了平台无关性) ;
3.可靠性;
4.安全性;
5.支持多线程;
6.支持网络编程;
7.执行方式采用了解释执行 + 编译执行并存的方式;
8.实践应用案例很丰富。
2.什么是JVM,JRE,JDK ?
JVM
JVM是Java虚拟机(Java Virtual Machine) 的缩写,用于运行Java字节码文件(*.class文件)。JVM针对不同的操作系统都有特性的实现(例如Windows,Linux,nacOC),目的是使用相同的字节码啊,在不同操作系统运行结果相同,是Java实现跨平台的核心机制。Java中默认虚拟机为HotSpot VM,除此之外还有JRockit(BEA),j9(IBM),TaoBaoVM(淘宝)等虚拟机;
JRE
JRE全称Java Runtime Environment(Java运行时环境)。JRE包括Java虚拟机和Java程序我所需要的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
JDK
JDK是Java开发工具包(Java Development Kit)的缩写,是提供给Java开发人员使用的,JDK中包含JRE以及开发,调节和监视应用程序的工具,编译工具(javac.exe),打包工具(jar.exe),Java监控和管理平台(jConsole,jvisualvm)等,
JDK包含JRE,JRE包含JVM。 所以JDK > JRE > JVM。
3.Java中常见的基本数据类型有哪些 ?
Java中的基本数据类型共有8种,分别是:
数值类型:
整型:
1.byte 字节型,内存中占1个字节。
2.short 短整型,内存中占2个字节。
http://3.int 整型,内存中占4个字节。
4.long 长整型,内存中占8个字节。
浮点型:
5.float 单精度浮点型,内存中占4个字节。
6.double 双精度浮点型,内存中占8个字节。
非数值类型:
1.char 字符型,内存中占两个字节。
2.boolean 布尔型(在Java虚拟机里采用8位二进制数表示布尔值,00000001表示true,00000000表示false)。boolean类型被编译成int类型来使用,占4个byte。boolean数组被编译成byte数组,每个boolean数组成员占1个byte。
4.Java中的浮点数为什么不精确 ?
计算机使用二进制运算,程序中1的十进制数先转换成二进制,再进行运算。Float和Double的小数部分在转换成二进制时容易产生无线循环的情况,通常都是取无限接近于原值的近似值,所以导致出现精度丢失的情况。(在金融,建筑,工程,科学等领域,对计算数值的精度要求一般比较高,为了避免计算结果不精准,往往采用BigDecimal + 字符串来解决精度丢失的问题。)
例如:
BigDecimal d1 = new BigDecimal("0.1");
BigDecimal d2 = new BigDecimal("0.2");
BigDecimal d3 = d1.mutiply(d2); //计算0.1 × 0.2的精确值。
double result = d3.doubleValue(); //获取double类型的结果。
5. & 和 && 有什么区别呢 ?
"&按位与" 运算 当位运算符时,a & b时把a和b都转换成二进制数,然后再逐位进行"与运算",同时为1结果为1,否则为0;
int result;
result = 9 & 8; //9 & 8 = 1001(9) & 1000(8) = 1000(8).
System.out.println(result); //result = 8
"&不断路与"运算符 当逻辑运算符时,当执行"表达式1 & 表达式2"时,表达式1等于true或者false,都会继续执行表达式2,执行不会中断。
int i = 3;
if(i++ > 5) & (i++ < 9){
System.out.println("if语句执行啦"); //该语句未执行
}
System.out.println(i); //结果输出i = 5,说明执行了两个i++
"&&短路与"运算 当逻辑运算符,当执行"表达式1 && 表达式2"时,表达式1等于false,执行会中断,表达式2不会执行。
int i = 3;
if((i++ > 5) && (i ++ < 9)) {
System.out.println("if语句执行啦");
}
System.out.println(i); //输出 i = 4,说明 i++只执行了一次。也就说明if语句只判断了 i++ > 5, 结果weifalse,退出if判断语句。
6. 什么是数组 ?
1.数组时一种引用数据类型,用于保存一组相同类型的数据结构,长度固定;
2.使用连续的内存空间进行存储,所以元素有序,遍历速度较快。
3.下标从0开始,尾下标为长度-1,引发ArrayIndexOutOfBoundsException数组下标越界异常;
7. 谈谈你对Arrays工具类的理解 ?
1.Arrays类时JDK提供专门用来操作数组的工具类,该类提供了大量的静态方法完成对于数据的常见的操作。
2.static List asList(T...a) //按照动态参数,创建一个ArrayList集合(内部类)
3.static void sort(int[] a) //数组排序(快速排序算法)
4.static int binarySearch(Object[] a , Object key) //搜索(二分查找算法)
8. == 和 equals() 的区别 ?
- ==是运算符
1.基本数据类型 == 用于比较值。
2.引用数据类型 == 用于比较内存地址。
- equals()是Object类中的方法
1.基本数据类型不能使用equals()
2.引用数据类型如果没有重写equals() ,会默认使用Object类的equals() , 在该方法中采用 == 进行比较内存地址,所以引用数据类型会重写equals() ,可以进行值或内容的比较。例如String类。
9.hashCode() 或HashCode的作用是什么 ?
1.hashCode()是Object类中的native本地方法,底层使用c/c++语言实现,用于获取对象的HashCode哈希码。
2.HashCode哈希码是该对象的内存地址通过哈希hash算法计算出的一个整数值,代表该对象在哈希表中的位置,作用主要是为了提高查找对象的快捷性,通过HashCode可以快速定位对象的存储地址,
3.两个对象进行比较,先通过HashCode比较,如果HashCode相等,再条用equals()方法比较,提高效率;
10. 为什么要有 hashCode() ? (以"HashSet如何检查重复"为例子来说明为什么要有hashCode)
1.当你把对象加入HashSet时,HashSet会先获取该对象的hashCode值,来计算该对象加入的位置,同时与其他已经加入的对象的hashcode值作比较。
2.如果没有重复的hashCode,HashSet会假设对象没有重复出现,正常添加。
3.如果发现有相同hashCode值的对象,这时会条用equals()方法来检查hashCode相等的对象是否真的相同。
4.如果两个相同,HashSet就不会其加入操作成功。
5.如果两者不同,就会重新散列到其他位置。
6.这样就大大减少了equals()的执行次数,相应就提高了执行速度。
11.为什么重写equals()时必须重写hahsCode()方法 ?
equals() 方法和hashCode()方法之间的关系应符合。
1. 如果两个对象相同(即:用equals比较返回true),那么它们的hashCode值一定要相同。
2. 如果两个对象的hashCode相同,他们并不一定相同(用equals比较)。
综上所述,在每个覆盖了equals()方法的类中,也必须覆盖hashCode()方法,如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致HashSet和HashTable等集合。另外,可以避免equals()被频繁调用,减少性能开销。
12. 什么是装箱和拆箱 ?
- 装箱:将基本类型转换成它们对应的引用类型,例如:Integer i = 666;
- 拆箱:将包装类型转换成基本数据类型,例如:int n = i;
13. 基本类型的包装器类型有哪些 ?
1. byte(1字节) : Byte类
2.short(2字节): Short类
http://3.int(4字节): Integer类
4.long(8字节): Long类
5. float(4字节): Float类
6. double(8字节): Double类
7.char(2字节): Character类
8.boolean(未定): Boolean类
14.包装类中的常量池技术有什么作用 ?
1. Byte,Short,Integer,Long创建范围在[-128 , 127]的缓存数据;
2.Character创建范围在[ 0 , 127]的缓冲数据;
3.如果数据处于缓存范围,不必重新创建对象,直接从缓存中获取,减少对象重复创建所带来的内存与性能开销;
4.如果数据超出缓存范围,才会创建新的对象。
例如:
//使用常量缓存池,同一内存地址,输出true
//强调一下Integer是引用数据类型,== 比较基本类型比较值,比较引用类型比较地址
Integer n1 = 33;
Integer n2 = 33;
System.out.println(n1 == n2);
//超出常量缓存池范围,重新分配内存地址,输出false
Integer n3 = 130;
Integer n4 = 130;
System.out.println(n3 == n4);
// n5从常量缓存池取,n6使用new关键字创建,非同一内存地址,输出false
Integer n5 = 40;
Integer n6 = new Integer(40);
System.out.println(n5 == n6);
15. 什么是字符串常量池(String Pool) ?
1.JVM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间,用于保存常量字符串,即字符串常量池(String Pool),JDK1.7以后,字符串常量池从方法区移到Heap堆区;
2.字符串常量池的优点(String Pool):避免了相同内容字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能。
16.Java是按值传递还是按引用传递 ?
- 值传递(pass by value):
值传递是指在调用方法时,按实际参数的值或内存地址复制一份传递到方法中。
- 引用传递(pass by reference):
引用传递是指在调用方法时,将实际传输的内存地址直接传递到方法中(不创建参数值或者内存地址的副本)。
在Java中,都是值传递,如果参数时基本类型,复制参数的值,传递给方法。如果参数时引用类型,复制对象参数的Heap堆中内存地址值,传递给方法。
17. 重载和重写的区别 ?
- 重载:
1.重载发生在编译期,是同一个类中,多个同名方法根据不同传参,执行不同的逻辑处理;
2.重载发生范围在同一个类中;
3.方法的参数列表必须不一致(类型不同,个数不同,顺序不同);
4.方法的返回值和访问修饰符可以不同;
5.构造方法可以被重载;
- 重写:
1.重写发生在运行期,是子类对父类方法的内部逻辑重新改造,外部定义不能改变;
2.重写发生范围在子类中;
3.参数列表必须与弗雷方法完全一致;
4.方法名,参数列表必须相同,返回值类型和抛出的异常范围小于等于父类,访问权限修饰符范围大于等于父类;
5.如果父类方法访问权限修饰符为private/final/static,则子类就不能重写该方法;
6.构造方法不能被重写;
18. 什么是浅拷贝,什么是深拷贝 ?
浅拷贝(Shallow Copy):
拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用所指向的对象,实现方式是实现Cloneable接口,重写clone()方法。
深拷贝(Deep Copy):
深拷贝不仅拷贝对象本身,而且还需要拷贝对象所包含的引用指向的所有对象(层层拷贝),实现方式有两种。
方式一:
为拷贝的对象包含的每个引用的类型去实现Cloneable接口,重写clone()方法(实现的步骤很繁琐,但是执行效率高)。
方式二:
用对象序列化来实现深拷贝。(实现起来相对简单,但是执行效率较低)。
19.成员变量与局部变量的区别有哪些 ?
1. 从语法形式上来说:
成员变量是定义在类中的,而局部变量是在代码块或者方法中定义的变量或者是方法的参数,成员变量可以被public,private,static等修饰符修饰,局部变量不能被访问控制修饰符以及static修饰,但是成员变量和局部变量都可以被final修饰符修饰。
2. 从内存中的存储方式来说:
如果成员变量是使用static修饰的,那么这个成员变量是属于类的,如果没有使用static修饰,那么这个成员变量是属于对象。而对象存在于堆内存,局部变量则是存在于栈内存。
3. 从变量在内存中的生存时间来说:
成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
4.从是否被赋初始值:
成员变量如果没有被赋初始值,则会自动以类型的默认值而赋初始值,如果该成员变量被final修饰则必须显式的赋初值,而局部变量则不会自动赋值。
20. 什么是构造方法 ?
- 构造方法名称与类名一致;
- 构造方法没有返回值类型这一结构,不能用void声明构造函数;
- 创建对象时,使用new关键字调用执行构造方法;
- 一个类即使没有声明构造方法,Java会提供默认的无参构造方法。
21. 构造方法的作用是什么 ?
1.构造方法的主要作用是用于完成创建对象的初始化工作。
2.Java为每个类提供了默认的无参数构造方法,如果我们为一个类定义有参构造方法时,Java就不会在提供无参数构造方法。
3.当我们为一个类重载构造方法时,应当把无参数的构造方法也定义出来(无论是否会用到,都建议),因为这样可以确保在任何场合下,该类都有无参数的构造方法可以使用。(Spring框架中创建bean,默认采用无参数构造方法)。
22.面向对象的三大特征是什么 ?
- 1.封装:
封装的目的是隐藏事务内部的实现细节,以便提高安全性和简化编程。是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息,只能通过允许被外界访问的方法来操作属性。
- 2.继承:
继承是代码复用的基础机制,使用已存在的类定义作为基础来拓展创建新类,新类的定义可以增加新的数据或新的功能。通过使用继承,可以快速地拓展出新类的定义,可以提高代码的重用,程序的可维护性,提高我们的开发效率。
- 3.多态:
多态顾名思义,表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例,使应用程序扩展更灵活。
23. 什么是多态 ?
多态表示一个对象具有多种状态。具体表现为父类的引用指向子类的实例。在Java中多态主要体现在重载,重写,向上(向下)转型等。
多态的特点:
1.多态中对象类型和引用类型之间必须具有继承类或者实现接口的关系;
2.多态中引用类型变量调用的方法,究竟是调用哪个类中的方法,在程序运行期间才能确定(具体是那个方法只能根据引用指向的对象的真正类型去决定)。
3.多态中不能通过父类的引用去调用只在子类中存在但父类中不存在的方法;
4.多态中,如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。