一、简单讲一下java的跨平台原理
由于各个操作系统支持的指令集,不是完全一致的,就会让我们的程序在不同的操作系统上要执行不同的代码。Java开发适用于不同的操作系统及位数的java虚拟机来屏蔽各系统之间的差异,提供一个接口。对于我们java开发者而言,你只需要在不同的操作系统上安装不同的java虚拟机,这时你的java程序只要遵守java规范,就可以在所有的操作系统上面运行java程序了
二、讲一下java中int数据占几个字节
Java中有几种基本的数据类型? 8种
Int占4个字节,32位
Boolean 1位
三、面向对象的特征有哪些
有四大基本特征:封装、抽象、继承、多态
面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。
抽象就是找出一些事的相似和共同之处,然后将这些事务归为一个类,这个类只考虑这些事务的相似和共同支持,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。
在定义和实现一个类的时候,可以在一个已经存在的类的基础上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法是指更适合特殊的需要,这就是继承。
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向那个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法必须在由程序运行期间才能决定
四、有的基本的数据类型,为什么还需要包装类型
基本的数据类型,java中提供了8种基本的数据类型。boolean int float等
包装类型:每一个包装类型都会一一对应一个包装类型。
boolean ---->Boolean
int ----->Integer
装箱和拆箱
把基本的数据类型装换成对应的包装类型
Integer i = 1自动装箱,实际上在编译是会调用Integer.valueof()方法来装箱
拆箱:就是把包装类型转换为基本的数据类型 基本数据类型 名称 = 对应的包装类型
Integer i = 1;
int j = i;//自动拆箱 //int j = i.intValue();手动拆箱
java是一个面向对象的语言,而基本的数据类型,不具备面向对象的特点。
缓存值:对象缓存,Integer i = 1;integer j = 1; i == j ,true
对于127 -- -128之间的值会进行缓存,如果不存在的话将会创建对象
五、说下"=="和equals方法究竟有什么区别?
==是用来判断两个变量之间的值是否相等。变量可以分为基本数据类型变量还有引用数据类型变量。如果是基本数据类型直接比较值,而引用数据类型要比较引用的内存地址的首地址。
equals用来比较两个对象长得是否一样。判断两个对象的某些特征是否一样。实际上就是调用equals方法进行比较
六、讲一下String 和 StringBuilder的区别(final)?StringBuffer 和 StringBuilder的区别?
在java中提供了三个类String StringBuilder StringBuffer来表示和操作字符串。字符串就是多个字符的集合。
String是内容不可变的字符串。String底层使用了一个不可变的字符数组(final char[])
String str = new String("bbbb");
而StringBuilder StringBuffer,是内容可以改变的字符串StringBuilder StringBuffer底层使用的可变的字符数组(没有final来修饰)
最经典的就是字符串的拼接。
StringBuilder
1.StringBuilder首先继承AbstractStringBuilder抽象类
2.然后在AbstractStringBuilder类中定义一个char类型的value数组
3.StringBuilder的charAt(),方法,首先会进行判断是否正确是否越界,然后根据数组索引返回
4.StringBuilder的setCharAt()方法,底层对数组的修改
StringBuffer
1.StringBuffer首先继承AbstractStringBuilder抽象类(与StringBuilder的父类相同)
1、String进行拼接String c = "a" + ''b'';
2、StringBuilder 和 StringBuffer
StringBuilder sb = new StringBuilder(); sb.apend("a").apend("b")
1.AbstractStringBuilder类中的append方法
2.首先会调用ensureCapacityInternal()方法
3.在ensureCapacityInternal()方法中判断是否长度超过数组的长度,如果超过的话就,再开辟一段空间,并且将之前数组赋值过来
拼接字符串不能使用String进行拼接,要使用StringBuilder 或者 StringBuffer,因为String进行拼接会创建多个对象而StringBuilder 或 StringBuffer不会,所以拼接字符串StringBuilder StringBuffer会更快
StringBuilder 不是线程安全的但是效率较高。而StringBuffer是线程安全的,效率较低
StringBuilder
StringBuffer
七、讲一下java中的集合?
Java中的集合分为value,key-value(Collection 和 Map)两种。
存储值得有List 和 Set。
List是有序的,可以重复的。
Set是无序的,不可以重复的。根据equals和hashcode判断,也就是说如果一个对象要存储在Set中必须重写equals和hashCode方法。
存储key-value的为map
八、ArrayList 和 LinkedList的区别
List常用ArrayList 和 LinkedList。区别和使用的场景?
ArrayList底层使用的是数组。LinkedList底层使用的是链表。
数组的查询具有查询特定元素比较快。而插入删除和修改比较慢(数组在内存中是一块连续的内存,如果插入或删除是需要移动内存)。
链表不要求内存是连续的,在当前元素中存放下一个或者上一个元素的地址。查询的时候需要从头部,一个一个的找。所以查询效率低。插入时不需要移动内存,只需要改变引用指向即可。所以插入或者删除的效率较高。
ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList使用在查询比较少,而插入和删除比较多的情况
ArrayList的底层源码
1. indexOf()方法
首先判断插入的元素是否为null,如果是空的话,进行查找,如果不是在利用equals方法进行查找,如果查找到返回元素的索引,如果没有返回-1
2.lastIndexOf()
与indexof()方法相似,但是查找的时候从后往前查找
3. toArray
调用Arrays.copyOf(elementData, size),传入,数组还有数组的长度,并返回
4. get(int index)
首先会调用rangeCheck()方法进行检查下标是否越界,然后调用elementData(index)方法根据数组下标进行返回
5. set(int index, E element)
首先会检查是否会出现数组越界,然后查找原始的元素,接着进行修改,最后返回原始的元素
6.add(E e)
判断数组最小的长度,调用ensureCapacityInternal()方法
调用calculateCapacity()方法
与原始数组进行比较返回最小应该创建的数组大小
当ArrayList添加的长度超过10的时候就会增加长度
调用grow方法增加长度,并且将原始数组进行复制
7.remove
首先判断移除的下标是否越界,然后通过调用数组复制的本地方法进行复制,返回删除的元素
8.clear
LinkedList底层源码
九、讲一下HashMap 和HashTable的区别?HashTable和ConcurrentHashMap的区别?
相同点:HashMap和HashTable都可以用来存储key-value的数据
区别:
1、HashMap可以把null作为key或者value的,而HashTable是不可以的。
2、HashMap是线程不安全的,效率较高。而HashTable是线程安全的,效率较低。
ConcurrentHashMap即实现线程安全又效率较高
通过把整个Map分为N个Segment(类似HashTable),可以提供线程安全,但是效率提升N倍,默认提升1倍。
十、实现拷贝文件的工具类使用字节流还是字符流?
我们拷贝文件不确定只包含字符流,有可能有字节流(图片、声音、图像等),为考虑到通用性,要使用字节流。
十一、讲一下线程的几种实现方式?
①实现方式
1、通过集成Thread类实现一个线程
2、通过实现Runnable接口实现一个线程
集成扩展性不强,java总支持单继承,如果一个类继承了Thread就不能继承其他的类了。
②怎样启动?
Thread thread = newThread(继承了Thread 的对象、实现了Runnable的对象)
thread.setName("设置一个线程的名称");
thread.start();
启动线程使用start()方法,而启动了以后执行的是run方法。
③怎么区分线程?在一个系统中有很多的线程,每个线程都会打印日志,我想区分是哪个线程打印的怎么办?
thread.setName("设置一个线程的名称");这是一种规范,在创建完线程之后,都需要设置线程的名称。
十二、有没有使用过线程并发库
简单了解过,java通过Executors提供四个静态方法创建四种线程池,其中有个newFixedThreadPool 创建一个定长的线程池,可控线程的最大并发数,超过的线程会在队列中等待。
十三、线程池的作用
1、限定线程的个数,不会导致由于线程过多导致系统运行缓慢或者崩溃
2、线程池不需要每次去创建或销毁,节约资源
3、线程池不需要每次都去创建,响应时间更快
十四、讲一下http get 和 post请求的区别?
get和post请求都是http的请求,用户通过不同的http的请求方式完成对url资源的不同操作。get,post,put,delete就对应着对这个资源的查、改、增、删四个操作,具体点来讲get一般用来获取、查询资源的信息,而post一般用来更新资源的信息
区别:
1、get请求提交的数据会在地址栏显示出来,而post请求不会再地址栏中显示出来
2、传输数据的大小
3、安全性,post的安全性要比get的安全性高
十五、说一下你对servlet的理解?或者servlet是什么?
Servlet是用Java编写的服务器端的程序。而这些程序都要实现Servlet这个接口。其主要的功能在于交互式地浏览和修改Web内容。Serlvet运行支持Java的应用服务器中。HTTPServlet重写doget和dopost方法或者你也可以重写service方法完成对get和post的请求和相应
十六、Servlet的生命周期
servlet有良好的生命周期,包括加载和实例化、初始化、处理请求以及服务结束。这个生存周期由Servlet
接口的init,service和destroy方法表达。
servlet启动的时候,生命周期开始。Servlet被服务器实例化之后,容器开始运行init()方法,请求到达运行其service方法,service方法自动派遣运行doget或者dopost方法,当服务其决定销毁的时候调用destroy方法。
加载Servlet的class---》实例化Servlet----》调用Servlet的init方法完成初始化----》请求响应(Servlet的service方法)----》Servlet容器关闭的时候(destory)
十七、ServletAPI中的forward()与redirect()的区别
1、forward是服务器端的转向而redirect是客户端的跳转
2、使用forward浏览器的地址不会发生改变。而redirect会发生改变
3、forward是一次请求中完成。而redirect是重新发起请求。
4、forward实在服务器端完成,而不是客户端重新发起请求,效率较高
十八、什么是协议
协议:计算机与网络设备之间要相互通信,双方要基于相同的方法和规则在不同的硬件和操作系统之间的通讯
十九、Spring是什么?
Spring是J2EE应用框架,是轻量级IOC和AOP的容器框架,主要针对javaBean的生命周期进行管理的轻量级容器。
1、IOC或DI
IOC控制反转:将创建对象的控制权转移到Spring容器来进行管理,这种控制权发生转移叫做控制反转
核心原理:就是配置文件+反射(工厂也可以) +容器(map)
2、AOP:面向切面编程
核心原理:使用动态代理设计模式在执行前后或出现异常后加入相关逻辑
我们主要通过AOP来做:
1、事务判断
2、权限管理
3、日志。。。
二十、SpringMVC和Strus2的优略分析
共同点:
他们都是表现层框架,都是基于MVC模型编写的
他们底层都离不开原始的ServletAPI
他们处理请求的机制都是一个核心容器
区别:
SpringMVC的入口是Servlet,而Strus2是Filter
SpringMVC是基于方法设计的,而Struts2是基于类,Struts2每次执行都会创建一个动作类。所以SpringMVC会稍微比Struts2快些。
SpringMVC使用更加假按揭,同时还支持JSR303,处理ajax请求更方便
Struts2的ONGL表达式使页面开发效率相比于SpringMVC更高些,但是Struts2的表单标签,远没有html执行效率高。