1.JVM、JRE和JDK的关系
·JVM
JVM可以理解成一个可运行Java字节码的虚拟计算机系统1. 他有一个解释器组件,可以实现字节码与操作系统之间的通信2. 对于不同的操作系统,有不同的JVM3. JVM屏蔽了底层运行平台的差别,实现了“一次编译,随处运行”
·JRE: Java Runtime Environment
·JDK:Java Development Kit
JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
如果你需要运行java程序,只需安装JRE就可以了。
如果你需要编写java程序,需要安装JDK。
也就是说,JDK范围最广JDK-->JRE-->JVM
2.什么是跨平台性?原理是什么?
所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。
实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。(注意不是能在所有的平台上运行,关键是该平台是否能安装相应的虚拟机)。
总结:Java程序之所以能够实现跨平台运行,是因为它根本就不直接运行在任何底层平台上,而是需要在哪里运行,就在哪里(如Windows平台)事先准备好自己的Java平台,而这只是仅仅是安装和配置一个软件而已!
3.&&和&的区别
& 既是位运算符又是逻辑运算符,&的两侧可以是int,也可以是boolean表达式,当&两侧是int时,要先把运算符两侧的数转化为二进制数再进行运算,而短路与(&&)的两侧要求必须是布尔表达式。
&为真的条件是两侧表达式都为真,但是即使我们判断出左侧表达式的值为false,程序也还是要继续执行去判断右侧的表达式值的真假
&&若左侧表达式的值为false时,程序则不会继续判断右侧表达式的真假了
总结:当判断多个bool表达式的并集结果时,&&比&处理速度更快
4.用最有效率的方法计算2*8
2 << 3,
因为将一个数左移n 位,就相当于乘以了2 的n 次方,那么,一个数乘以8 只要将其左移3 位
即可,而位运算cpu 直接支持的,效率最高,所以,2 乘以8 等於几的最效率的方法是2 << 3。
5.不使用临时变量时交换两个整数变量的值
int a1,b1;//方法一a1 = a1 + b1;b1 = a1 - b1;a1 = a1 -b1;//方法二a1 = a1 ^ b1;b1 = a1 ^ b1;//a1^b1^b1a1 = a1 ^ b1;//a1^b1^a1
6.运算符转换判断
short s1 =1;s1 =s1 + 1;有错吗?
short s1 = 1;s1 += 1;有错吗?
因为byte、 short、 int 不会互相转换d,它们三者在计算时会转换成 int 类型。
而“+”是算术运算符,有算术运算符,就是已经在运算了,所以结果会转成int 类型。
如果把 int 类型的结果赋给 byte、short类型的结果,必须加上强制声明。 所以, 上面的第一个语句块,错在用“+”这个算术运算符运算后,结果变成了 int 型, 然后重新把计算结果赋给 short 型的变量时,没有强制声明值为 short的型的,所以会出错。 应该更改为: short s1 = 1; s1 = (short)(s1 + 1);
而第二个语句块,s1 += 1; 不会出错,因为“+=”是赋值运算符,不牵涉与其它类型的数字计算,也不会转成 int 类型的,所以没错。
注:
如果你认为表达式(x += i)只是表达式(x = x + i)的简写方式,这并不准确。这两个表达式都被称为赋值表达式。
第二个表达式使用的是简单赋值操作符(=),而第一个表达式使用的是复合赋值操作符。
换句话说,复合赋值表达式自动地将所执行计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,那么这个转型不会造成任何影响。然而,如果结果的类型比该变量的类型要宽,那么复合赋值操作符将悄悄地执行一个窄化原生类型转换。
因此,复合赋值表达式可能是危险的。为了避免这种令人不快的突袭,请不要将复合赋值操作符作用于byte、short或char类型的变量。
因为S1是short型的,占2个字节,而1是int型的,占4个字节。在两个类型的值相加的时候,会发生自动类型的提升。也就是说s1+1后,其结果是int型的,而不是short型的,所以可以想想看,把4个字节的东西放在两个字节的空间里,肯定编译不通过。 后面的那个不会发生类型的提升,JAVA规范上说 e1+=e2 实际上是 e1=(T1)(e1+e2),其中T1是e1的数据类型。 s1+=1等效于 s1=(short)(s1+1),所以是正确的。
7.数据类型转换判断
float f = 3.4;是否正确
不正确;
3.4的默认数据类型为double,比左边float类型的范围更广
应该为 float f = 3.4f;
8.手动实现冒泡排序
升序
int temp;int[] arr = {9,2,4,6,7,}for(int i = 0;i < arr.length -1;i++){for(int j = 0;j < arr.length - i - 1;j++){if(arr[j]>arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
9.finally在什么时候不会被执行?
只有程序关闭时不会被执行。如:电脑关机、电脑停电、软件在内存中消失
如果不是上述情况,finally必然执行
即使finally之前有return语句执行,finally也会执行
解释:先执行return语句,return语句执行需要一定的时间,返回值为void也需要准备时间。在这段准备结果的时间中,finally执行。
eg1.
package com.java.demo1;public class Demo6 {public static void main(String[] args) {Person p =haha();System.out.println(p.age);}public static Person haha(){Person p = new Person();try{p.age = 18;return p;}finally{p.age = 28;}}static class Person{int age;}}//始终是一个对象,最后执行finally,p.age年龄被更改
内存画图分析:
eg2.
package com.java.demo1;public class Demo7 {public static void main(String[] args) {int a =haha();System.out.println(a);}public static int haha(){int a = 10;try{return a;}finally{a = 20;}}}//return a;中的a是被备份的那个//实际上又开辟了一块内存空间,这是返回的a和finally中的赋值的a无关
内存画图分析:
eg3.
package com.java.demo1;public class Demo8 {public static void main(String[] args) {haha();}public static void haha(){try{int a = 10;int b = 0;System.out.println(a/b);}catch(Exception e){//退出JVMSystem.exit(0);}finally {System.out.println("锄禾日当午,汗滴禾下土");}}}
唯一一种在代码中使finally不执行的代码就是上述eg3.
System.exit(0);
总结:finally问题总绕不开两点:
1.finally必然执行
2.return的时机以及备份的具体内容
结论:
1.finally语句不执行的情况
①程序关闭时不会被执行。如:电脑关机、电脑停电、软件在内存中消失
②try语句没有被执行到,如在try语句之前return就返回了,这样finally语句就不会执行
③在try块catch块中有System.exit(0);这样的语句。System.exit(0)是终止Java虚拟机JVM的,连JVM都停止了
所有都会结束,finally语句也不会被执行到
2.在try-catch-finally中,当return遇到finally,return对finally无效,即:
①在try catch块里return的时候,finally也会被执行
②finally里的return语句会把try catch 块里的return语句效果覆盖掉
3.return语句 并不一定都是函数的出口,执行return时,只是把return后面的值复制了一份到返回值变量里去了。
10.说说你对面向对象思想的理解
面向对象编程,即OOP,面向对象的概念和应用已经超越了程序设计、软件开发领域,目前已经发展到了各个领域。
面向对象可以说是对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段的产物。
特点:抽象 封装 继承 多态
通俗地讲,其实可以这么理解,假如我是上帝,我要造 人 (这是对象)。
首先,我要知道人类要有哪些最基本的东西 ?
人要有思想,人还要有肉体
这个过程呢就是(抽象)
因为人的数量很庞大,所以我需要找别人帮我一起造人,但是我不想让他知道我造人的技术(人的脸需要用多少克泥巴,需要怎么用手去捏鼻子等等),我可以把我的造人的技术封装起来,别人只需要知道他要做什么样的人类就好了。【封装】
当我自己造人的时候,我可能造着造着就累了,我可能就要用我之前造出来的某个泥人作为模板“复制”,“粘贴”了
用模板创出来的泥人具有模板的特征,就像孩子一样具有父母的性状。我们称这个过程为【继承】
但是呢 好多泥人都是我后来偷懒用模板复制出来的,为了让人类更丰富多彩一些,我对他们又进行了改变。这个过程可以叫【多态】
接下来我举个栗子来区分面向过程和面向对象
例子:是如何将大象装进冰箱
为了解决这个问题,我们采用两种方案,一种是面向过程方案,另一种是面向对象方案
面向过程:
总共分三个过程,第一个过程:冰箱门打开(关着门的冰箱) 返回值是打开门的冰箱
第二个过程:大象装进去(打开门的冰箱) 返回值是打开着门,装着大象的冰箱
第三个过程:冰箱门关上(打开着门,装着大象的冰箱) 返回值关着门的装着大象的冰箱
面向对象:
总共分三个动作,(每个动作都有一个对象去执行)
第一个动作:冰箱.开门()
第二个动作:冰箱.装进(大象)
第三个动作:冰箱.关门()
或者是链式调用冰箱.开门().装进(大象).关门()
面试答法:
面向对象是基于万物皆对象这个哲学观点。把一个对象抽象成类,具体就是把一个对象的静态特征和动态特征抽象成属性和方法,也就是把一类事物的算法和数据结构封装在一个类之中,程序就是多个对象和相互之间的通信组成的。
面向对象具有封装性、继承性、多态性。封装隐蔽了对象内部不需要不暴露的细节,使得内部的细节跟外界脱离,只依靠接口进行通信,封装性降低了编程的复杂性。通过继承,使得新建一个类变得容易,一个类从派生类那里获得其非私有的方法和公用属性的繁琐工作交给了编译器。而继承和实现接口和运行时的类型绑定机制所产生的多态,使得不同的类所产生的对象能够对相同的消息做出不同的反应,极大地提高了代码的通用性
总之,面向对象的特性提高了大型程序的重用性和可维护性
11.Java对象初始化顺序
原则:父类优于子类,静态优于非静态
先初始化父类的静态代码—>初始化子类的静态代码–>初始化父类的非静态代码—>初始化父类构造函数—>初始化子类非静态代码—>初始化子类构造函数
12.Overload重载和Override重写的区别?Overload的方法是否可以改变返回值的类型?
重载:同一个类中,方法名相同,参数列表不同。与返回值类型无关。(可以改变返回值类型)
重写:存在于子父类中,或者子父接口中,方法声明相同
13.int和Integer的区别
1、Integer是int的包装类,int则是Java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
延伸:
关于Integer和int的比较
1、由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
Integer i = new Integer(100);Integer j = new Integer(100);System.out.print(i == j); //falseSystem.out.println(i.equals(j)); //trueSystem.out.println(i.intValue()==j.intValue()); //true//上面的两个代码是一样的比较过程,详细可以看下面equals的源码
实例化对象的时候,构造函数会将传入的参数存入一个int类型的变量value,可以通过intValue得到这个value。
2、Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
Integer i = new Integer(100);int j = 100;System.out.print(i == j); //true
3、非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
Integer i = new Integer(100);Integer j = 100;System.out.print(i == j); //false
4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
Integer i = 100;Integer j = 100;System.out.print(i == j); //true
Integer i = 128;Integer j = 128;System.out.print(i == j); //false
对于第4条的原因:
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:
public static Integer valueOf(int i){assert IntegerCache.high >= 127;if (i >= IntegerCache.low && i <= IntegerCache.high){return IntegerCache.cache[i + (-IntegerCache.low)];}return new Integer(i);}
java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了
