Java面试题
看到这篇文章的应该都是要找工作或是想对自己最近所学的做个验证
既然大家都这么厉害了,我就先出道简单的题考考大家
下面代码的运行结果是什么?
public static void main(String[] args) {
int i = 1;
i = i++;
int j = i++;
int k = i + ++i * i++;
System.out.println("i =" + i);
System.out.println("j =" + j);
System.out.println("k =" + k);
}
当大家第一眼看这道题的时候是不是觉得超简单呢, 嘿嘿,看仔细,想清楚哦! ! !
答案呢我会在本文的最后公布,急不可耐的小伙伴可以直接翻到最下面
局部变量和成员变量
代码执行后的运行结果
public class Mst5 {
static int s;
int i;
int j;
{
int i = 1;
i++;
j++;
s++;
}
public void test(int j){
j++;
i++;
s++;
}
public static void main(String[] args) {
Mst5 obj1 = new Mst5();
Mst5 obj2 = new Mst5();
obj1.test(10);
obj1.test(20);
obj2.test(30);
System.out.println(obj1.i + "," + obj1.j + "," + obj1.s);
System.out.println(obj2.i + "," + obj2.j + "," + obj2.s);
}
}
运行结果
2 1 5
1 1 5
考点:
就近原则
变量的分类
成员变量:
类变量:随着类的初始化而初始化,随着类的卸载而消亡,该类的所有对象的类变量是共享的
实例变量:随着对象的创建而初始化,随着对象被回收而消亡,每一个对象的实例变量是独立的
局部变量:每一个线程,每一次调用执行都是新的生命周期
非静态代码块每次创建实例对象都会执行
面向对象
封装
- 减少代码冗余
- 封装的目标就是要实现软件部件的"高内聚、低耦合",防止程序相互依赖而带来的变动影响,封装隐藏了对象的属性和实施细节
- 将对象封装成一个高度自治和相对封闭的个体,对象状态由这个对象的行为来读取和改变表现了封装的隐藏性,增加数据的安全性。
继承
-
单根性,传递性
-
减少了类的冗余代码
-
让类与类之间产生关系,为多态打下基础
-在定义和实现一个类的时候,可以在一个已经存在的类的基础上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容,或修改原来的方法使之更适合特殊的需要 -
基础是子类自动共享父类数据和方法,是类之间的一种关系,提高了软件的可重用性和可扩展性
多态
- 多态就是指多种状态,就是说当一个操作在不同的对象时,会产生不同的结果
- 在Java中,实现多态的方式有两种,一种是编译时的多态,另一种是运行时多态,编译时的多态是通过方法的重载实现的,而运行时多态是通过方法的重写实现的
- 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,这样不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上
多态的实现机制
靠的是父类或接口定义的变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的房啊
使用final关键字修饰一个变量时,是引用不能改变,还是引用的对象不能变
使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
final StringBuffer a=new StringBuffer(“immutable”);
执行如下语句将报告编译期错误:a=new StringBuffer("");
但是,执行如下语句则可以通过编译:a.append(" broken!");
有人在定义方法的参数时,可能想采用如下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){
}
实际上,这是办不到的,在该方法内部仍然可以增加如下代码来修改参数对象:
param.append(“a”)
对于jvm内存的理解
Java堆
堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例
Java堆是垃圾收集器管理的主要区域。Java堆细分为新生代和老年代。不管怎样,划分的目的都是为了更好的回收内存,或者更快地分配内存
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。如果在堆中没有完成实例分配,并且堆也无法在扩展时将会抛出OutOfMemoryError异常
栈
优点:存取速度比堆要快,仅次于直接位于CPU中的寄存器
缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于储存局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
栈内存就是虚拟机栈,或者说是虚拟机栈中局部变量表的部分
局部变量表存放了编辑期可知的各种基本数据类型对象引用(reference类型,它不代表对象本身,可能是一个指向对象起始地址的引用指针,也可能指向一个对象代表的句柄或其他与此对象相关的位置)和returnAddress类型
其中64位长度的long和double类型的数据会占用两个局部变量空间,其余的数据类型只占用1个。
对象创建
检查: 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析、和初始化过。如果没有,那么必须先执行相应的类加载过程
内存分配: 接下来将为新生对象分配内存,对象所需内存在类加载完毕之后就可以完全确定,为对象分配内存空间的任务等同于把一块确定的大小的内存从Java堆中划分出来
假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针指向空闲空间那边挪动一段与对象大小相等的距离,这个分配方式叫做“指针碰撞”
如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”
选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
内存空间初始化: 虚拟机将分配到的内存空间都初始化为零值,内存空间初始化保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
对象设置: 虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。
init: 执行new指令之后会接着执行Init方法,进行初始化,这样一个对象才算产生出来
IO流
为了永久性的保存数据
根据数据流向的不同分为输入流和输出流
根据处理数据类型的不同分为字节流和字符流
当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流
Java序列化
可以将一个对象保存到一个文件,所以可以通过流的方式在网络上传输,可以将文件的内容读取,转化为一个对象。
处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的
序列化: 将对象存储到特定存储介质中的过程,也就是将对象状态转换为可保存传输格式的过程,其过程中会将对象的共有成员私有成员,包括类名,转换为字节流,然后将字节流写入数据流,存在存储介质(文件)
意义: 将java对象序列化后,可以将其转换为字节序列,可借助网络传输,保存状态为二进制,实现平台无关性,可传至其他操作系统再通过反序列化得到相同对象,而无需担心数据因平台而显示异常。
反序列化: 从特定存储介质中读取数据并重新构建成对象的过程
注意:
若向文件中序列化多个对象,那么反序列化恢复对象时,必须按照写入的顺序读取。
若一个可序列化的对类,由多个父类,则这些父类要么时可序列化的,要么有无参数的构造器否则会抛出异常
对于一些敏感信息(如:密码),可以通过transient修饰,限制序列化
当程序试图序列化一个对象,将会检查是否已被序列化,只有序列化后的对象才能被转换成字节序列输出,若对象已被序列化,则程序直接输出一个序列化编号,不再重新序列化
&和&&的区别
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为 true 时,整个运算结果才为 true,否则,只要有一方为 false,则结果为 false。
&&还具有短路的功能,即如果第一个表达式为 false,则不再计算第二个表达式,例如,对于 if(str != null && !str.equals(“”))表达式,当 str 为 null 时,后面的表达式不会执行,所以不会出现 NullPointerException如果将&&改为&,则会抛出 NullPointerException 异常。If(x33 & ++y>0) y 会增长,If(x33 && ++y>0)不会增长
&还可以用作位运算符,当&操作符两边的表达式不是 boolean 类型时,&表示按位与操作,我们通常使用 0x0f 来与一个整数进行&运算,来获取该整数的最低 4 个 bit 位,例如,0x31 & 0x0f 的结果为 0x01。
char型变量中能不能存储一个中文汉字?为啥?
char 型变量是用来存储 Unicode 编码的字符的,unicode 编码字符集中包含了汉字,所以,char 型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在 unicode 编码字符集中,那么,这个 char型变量中就不能存储这个特殊汉字。补充说明:unicode 编码占用两个字节,所以,char 类型的变量也是占用两个字节
是否可以从一个static方法内部发出对非static方法的调用?
不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而 static 方法调用时不需要创建对象,可以直接调用。也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法的调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个 static 方法内部发出对非 static 方法的调用
Integer与int的区别
int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 java 为 int 提供的封装类。int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为 0 的区别,int 则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为 0 的区别,则只能使用 Integer。在 JSP 开发中,Integer 的默认为 null,所以用 el 表达式在文本框中显示时,值为空白字符串,而 int 默认的默认值为 0,所以用 el 表达式在文本框中显示时,结果为 0,所以,int 不适合作为 web 层的表单数据的类型
JDK 和 JRE 的区别是什么?
JRE是Java Runtime Environment的缩写,顾名思义是java运行时环境包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需的软件环境,是提供给想运行java程序的用户使用的,还有所有的Java类的class文件,都在lib目录下,并且都打包成了jar。
JDK是Java Development Kit的缩写,顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。
什么是值传递和引用传递?
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响 源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对 象所做的改变会反映到所有的对象上。
String、StringBuffer、StringBuilder的区别
String是一组不可变的unicode编码的字符序列;
StringBuffer的长度是可变的,如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法;线程安全;
StringBuilder是从 JDK 5开始,为StringBuffer该类补充了一个单个线程使用的等价类;通常应该优先使用 StringBuilder类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快
sleep() 和 wait() 有什么区别?
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,将执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
socket通信(tcp/udp区别及JAVA的实现方式)
TCP传输控制协议,具有极高的可靠性,保证数据包按照顺序准确到达,但其也有着很高的额外负担。
UDP使用者数据元协议,并不能保证数据包会被成功的送达,也不保证数据包到达的顺序,但其传输速度很快。大多数我们会使用TCP,偶尔才会动用UDP,如声音讯号,即使少量遗失,也无 关紧
MVC
Model(模型) 表示应用程序核心(比如数据库记录列表)。
是应用程序中用于处理应用程序数据逻辑的部分。
通常模型对象负责在数据库中存取数据。
View(视图) 显示数据(数据库记录)。
是应用程序中处理数据显示的部分。
通常视图是依据模型数据创建的。
Controller(控制器) 处理输入(写入数据库记录)。
是应用程序中处理用户交互的部分。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
JDBC
JDBC 是允许用户在不同数据库之间做选择的一个抽象层。JDBC 允许开发者用 JAVA 写数据库应用程序,而不需要关心底层特定数据库的细节。
驱动(Driver)在 JDBC 中的角色。
JDBC驱动提供了特定厂商对JDBC API接口类的实现,驱动必须要提供java.sql包下面这些类的实现:Connection, Statement, PreparedStatement,CallableStatement, ResultSet和Driver。
PreparedStatement 比 Statement 有什么优势?
PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);
PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;
当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)
数据库连接池是什么意思?
像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户端数量增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候建立很多个数据库连接并维护在一个池中。连接请求由池中的连接提供。在连接使用完毕以后,把连接归还到 池中,以用于满足将来更多的请求
BS与CS的联系与区别。
C/S 是Client/Server的缩写。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、Sybase、Informix或 SQLServer。客户端需要安装专用的客户端软件。
B/S 是Brower/Server的缩写,客户机上只要安装一个浏览器(Browser),如Netscape Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或 SQLServer等数据库。在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,
但是主要事务逻辑在服务器端实现。浏览器通过Web Server 同数据库进行数据交互
C/S 与 B/S区别:
- 硬件环境不同:
① C/S 一般建立在专用的网络上, 小范围里的网络环境,局域网之间再通过专门服务器提供连接和数据交换服务;
② B/S 建立在广域网之上的,不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围,一般只要有操作系统和浏览器就行 - 对安全要求不同 :
① C/S 一般面向相对固定的用户群,对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜.可以通过B/S发布部分可公开信息.
② B/S 建立在广域网之上, 对安全的控制能力相对弱,可能面向不可知的用户。 - 对程序架构不同 :
① C/S 程序可以更加注重流程, 可以对权限多层次校验,对系统运行速度可以较少考虑.
② B/S 对安全以及访问速度的多重的考虑,建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势,从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN和IBM推的JavaBean 构件技术等,使 B/S更加成熟. - 软件重用不同:
① C/S程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.
② B/S对的多重结构,要求构件相对独立的功能.能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子 。 - 系统维护不同
① C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难.可能是再做一个全新的系统,
② B/S 构件组成,方面构件个别的更换,实现系统的无缝升级.系统维护开销减到最小.用户从网上自己下载安装就可以实现升级. - 处理问题不同 :
① C/S程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关.应该都是相同的系统,
② B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的.与操作系统平台关系最小. - 用户接口不同:
① C/S多是建立的Window平台上,表现方法有限,对程序员普遍要求较高
② B/S 建立在浏览器上,有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本
公布本文开头题目的答案
i = 4
j = 1
k = 11
当看到答案的时候 是不是很惊讶 是不是在怀疑人生了 心理想大喊 沃特 什么鬼
在这我给大家总结了几点 看完你就懂了
- = 赋值操作最后计算
- = 右边从左到右加载值依次压入操作数栈
- 在表达式中 : ++在前 先改变局部变量表,再压入操作数栈,
++在后,先压入操作数栈再改变局部变量表 - 实际先算哪个看运算符优先级
- 最后的赋值之前,临时结果也是存储在操作数栈中
不管是不是做对了 都点个赞吧