1、面向对象特征
封装,继承,多态和抽象
封装
封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法 来改变它内部的数据。在Java当中,有3种修饰符:public, private和protected。每一 种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。 下面列岀了使用封装的一些好处:
- 通过隐藏对象的属性来保护对象内部的状态。
- 提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。
- 禁止对象之间的不良交互提高模块化。
继承
承给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在 不&改类的情况下给现存的类添加新特性。
多态
多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上 的操作可以应用到其他类型的值上面。
抽象
抽象是把想法从具体的实例中分离岀来的步骤,因此,要根据他们的功能而不是实现细 节来创建类。Java支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术 的主要目的是把类的行为和实现细节分离开。
2、final, finally, finalize 的区别
final
修饰符(关键字)如果一个类被声明为final,意味着它不能再派生岀新的子类,不能作 为父类被继承。因此一个类不能既被声明为abstract的,又被声明为final的。将变量或 方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时 给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使 用,不能重载。
finally
在异常处理时提供finally块来执行任何清除操作。如果抛岀一个异常,那么相匹配的 catch子句就会执行,然后控制就会进入finally块(如果有的话)。
finalize
方法名。Java 技术允许使用finalizef()方法在垃圾收集器将对象从内存中清除岀去之前 做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象 调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalizef()方 法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前 对这个对象调用的。
3、int和Integer有什么区别
int 是基本数据类型;Integer是其包装类,注意是一个类。 为什么要提供包装类呢?
一是为了在各种类型间转化,通过各种方法的调用。否则你无法直接通过变量转化。比 如,现在int要转为String:
int a=0;
String result=lnteger.toString(a);
在java中包装类,比较多的用途是用在于各种数据类型的转化中。
//通过包装类来实现转化的
int num=lnteger.valueOf("12");
int num2=lnteger.parselnt("12");
double num3=Double.valueOf("12.2");
double num4=Double.parseDouble("12.2");
//其他的类似。通过基本数据类型的包装来的valueOf和parseXX来实现String转为XX
String a=String.valueOf("1234");//这里括号中几乎可以是任何类型
String b二String.valueOf(true);
String c=new lnteger(12).toString();//通过包装类的 toString()也可以
String d二new Double(2.3).toString();
再举例下。比如现在要用泛型
List<lnteger> nums;
这里<>需要类。如果你用int。它会报错的。
4、重载和重写的区别
override (重写)
- 1.方法名、参数、返回值相同。
- 2.子类方法不能缩小父类方法的访问权限。
- 3.子类方法不能抛岀比父类方法更多的异常(但子类方法可以不抛岀异常)。
- 4.存在于父类和子类之间。
- 5.方法被定义为final不能被重写。
overload (重载)
- 1.参数类型、个数、顺序至少有一个不相同。
- 2.不能重载只有返回值不同的方法名。
- 3.存在于父类和子类、同类中。
5、抽象类和接口有什么区别
- 接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以 有私有方法或私有变量的;
- 另外,实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写 需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到 具体类实现;
- 还有,接口可以实现多重继承,而一个类只能继承一个超类,但可以通过继承多个接口 实现多重继承;
- 接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常 量)的作用。
6、说说反射的用途及实现
Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有的成 员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架。 Java反射的主要功能:
- 确定一个对象的类
- 取岀类的modifiers,数据成员,方法,构造器,和超类
- 找岀某个接口里定义的常量和方法说明
- 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象)
- 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到
- 在运行时刻调用动态对象的方法
- 创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值 反射的应用很多,很多框架都有用到:
spring 的 ioc/di 也是反射... javaBean和jsp之间调用也是反射... struts的FormBean和页面之间...也是通过反射调用... JDBC 的 classForName()也是反射... hibernate 的 find(Class clazz)也是反射...
反射还有一个不得不说的问题,就是性能问题,大量使用反射系统性能大打折扣。怎么使用 使你的系统达到最优就看你系统架构和综合使用问题啦,这里就不多说了。
7、说说自定义注解的场景及实现
(此题自由发挥,就看你对注解的理解了) 登陆、权限拦截、日志处理,以及各种Java框架,如Spring, Hibernate, JUnito 靠到注解就不能不说反射,Java自定义注解是通过运行时靠反射获取注解。实际开发中,例 如我们要获取某个方法的调用日志,可以通过AOP (动态代理机制)给方法添加切面,通过 貝京来获取方法包含的注解,如果包含日志注解,就进行日志记录。
8、HTTP请求的GET与POST方式的区别
GET方法会把名值对追加在请求的URL后面。因为URL对字符数目有限制,进而限制了用 在客户端请求的参数值的数目。并且请求中的参数值是可见的,因此,敏感信息不能用这种 方式传递。
POST方法通过把请求参数值放在请求体中来克服GET方法的限制,因此,可以发送的参数 的数目是没有限制的。最后,通过POST请求传递的敏感信息对外部客户端是不可见的。
9、session 与 cookie 区别
cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个Web服 务器存储cookie,以后浏览器在给特定的Web服务器发请求的时候,同时会发送所有为该 服务器存储的cookie。下面列出了 session和cookie的区别: 无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用 cookie,但是,session仍然是能够工作的,因为客户端无法禁用服务端的session。
10、JDBC 流程
加载JDBC驱动程序:
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM (Java虚拟机),这通过 java.lang.Class 类的静态方法 forName(String className)实现。 例如:
try{
//加载MySql的驱动类
Class.forNamef'com.mysql.jdbc.Driver");
}catch(ClassNotFoundException e){
System.out.println("找不到驱动程序类,加载驱动失败!"); e.printStackTrace();
}
成功加载后,会将Driver类的实例注册到DriverManager类中。
提供JDBC连接的URL
- 连接URL定义了连接数据库时的协议、子协议、数据源标识。
- 书写形式:协议:子协议:数据源标识
协议:在JDBC中总是以jdbc开始子协议:是桥连接的驱动程序或是数据库管理系统名称。 数据源标识:标记找到数据库来源的地址与连接端口。、 例如:
jdbc:mysql://localhost:3306/test?
useUnicode=true&characterEncoding=gbk;
useUnicode=true; (MySql 的连接 URL)
表示使用Unicode字符集。如果characterEncoding设置为gb2312或GBK,本参数必须设置 为 true 。characterEncoding二gbk: 字符编码方式。
创建数据库的连接
- 要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代 表一个数据库的连接。
- 使用 DriverManager 的 getConnectin(String url, String username , String password )方法传 入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。 例如:〃连接MySql数据库,用户名和密码都是root
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "root";
try{
Connection con = DriverManager.getConnection(url, username , password); }catch(SQLException se){
System.out.println(“数据库连接失败! “); se.printStackTrace();
创建一个 Statement
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3种类型: 1)执行静态SQL语句。通常通过Statement实例实现。 2)执行动态SQL语句。通常通过PreparedStatement实例实现。 3)执行数据库存储过程。通常通过CallableStatement实例实现。 具体的实现方式:
Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(sql);
CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}");
执行SQL语句
Statement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute□ 1)ResultSet executeQuery(String sqIString):执行查询数据库的SQL语句,返回一个结果集 (ResultSet)对象。 2)Lnt executeUpdate(String sqIString):用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL 语句,如:CREATE TABLE 和 DROP TABLE 等。 3)execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的语句。 具体实现的代码:
ResultSet rs = stmt.executeQuery("SELECT * FROM ...”);
int rows = stmt.executeUpdate("INSERT INTO ...〃);
boolean flag = stmt.execute(String sql);
处理结果
两种情况: 1)执行更新返回的是本次操作影响到的记录数。 2)执行查询返回的结果是一个ResultSet对象。
- ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行 中数据的访问。
- 使用结果集(ResultSet)对象的访问方法获取数据:
while(rs.next()){
String name = rs.getString(rtnamew);
String pass = rs.getString(l); // 此方法比较高效 }
(列是从左到右编号的,并且从列1开始)
7.关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序 相反: 1) 关闭记录集 2) 关闭声明 3) 关闭连接对象
if(rs != null){//关闭记录集
try{
rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(stmt != null){ // 关闭声明
try{
stmt.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn != null){
//关闭连接对象 try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
11、MVC设计思想
MVC就是
M:Model 模型
V:View视图
C:Controller 控制器
模型就是封装业务逻辑和数据的一个一个的模块;控制器就是调用这些模块的(java中通常 是用Servlet来实现,框架的话很多是用Struts2来实现这一层);视图就主要是你看到的,比 如JSP等。 当用户发岀请求的时候,控制器根据请求来选择要处理的业务逻辑和要选择的数据,再返回 去把结果输岀到视图层,这里可能是进行重定向或转发等。
12、equals 与==的区别
值类型(int,char,long,boolean等)都是用==判断相等性。对象引用的话,判断引用所指的 对象是否是同一个。equals是Object的成员函数,有些类会覆盖(override)这个方法,用 于判断对象的等价性。例如String类,两个引用所指向的String都是"abc”,但可能岀现他们 实际对应的对象并不是同一个(和jvm实现方式有关),因此用判断他们可能不相等,但用 equals判断一定是相等的。
13、1List 和 Set 区别
List,Set 都是继承自 Collection 接口
List特点:元素有放入顺序,元素可重复
Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉
注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的, 其位置其实是固定的,加入Set的Object必须定义equalsf)方法,另外list支持for循环, .就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标 来取得想要的值。
Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起 其他元素位置改变。
14、List 和 Map 区别
List是对象集合,允许对象重复。
Map是键值对的集合,不允许key重复。
15、Arraylist 与 LinkedList 区别
Arraylist:
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查 询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续,ArrayList要移动数据,所以插入和删除操作效率比较低。
LinkedList:
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等 一个连续的地址,对于新增和删除操作add和remove, LinedList比较占优势。LinkedList适 用于要头尾操作或插入指定位置的场景。
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时 采用 LinkedList。
16、ArrayList 与 Vector 区别
public ArrayList(int initialcapacity) //构造一个具有指定初始容量的空列表。
public ArrayList() //构造一个初始容量为10的空列表。
public ArrayList(Collection<? extends E> c) // 构造一个包含指定 collection 的元素的列表
Vector有四个构造方法:
public Vector()//使用指定的初始容量和等于零的容量增量构造一个空向量。
public Vector(int initialcapacity) //构造一个空向量,使其内部数据数组的大小,其标准容量增 星为零。
public Vector(Collection<? extends E> c) //构造一个包含指定 collection 中 的元素的向量 public Vector(int initialcapacity,int capacityincrement) //使用指定的初始容量和容量增量构造 一个空的向量
ArrayList和Vector都是用数组实现的,主要有这么四个区别:
(1)Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。 而ArrayList不是,这个可以从源码中看岀,Vector类中的方法很多有synchronized进行 修饰,这样就导致了 Vector在效率上无法与ArrayList相比;
(2)两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式不 同。
(3)Vector可以设置增长因子,而ArrayList不可以。
(4) Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
适用场景分析:
1)Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。 如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
2)如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数 据,用Vector有一定的优势。
17、HashMap 和 Hashtable 的区别
1.hashMap 去掉了 HashTable 的 contains 方法,但是加上了 containsValue()和 containsKey() 方法。
2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
3.hashMap允许空键值,而hashTable不允许。
注意:
TreeMap:非线程安全基于红黑树实现。
TreeMap没有调优选项,因为该树总处于平衡状态。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
18、HashSet 和 HashMap 区别
1)set是线性结构,set中的值不能重复,hashset是set的hash实现,hashset中值不能重 复是用hashmap的key来实现的。
2)map是键值对映射,可以空键空值。HashMap是Map接口的hash实现,key的唯一性 是通过key值hash值的唯一来确定,value值是则是链表结构。
3)他们的共同点都是hash算法实现的唯一性,他们都不能持有基本类型,只能持有对象。
19、HashMap 和 ConcurrentHashMap 的区别
Concurrent Hash Map是线程安全的HashMap的实现。
⑴ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用 lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更 好,而HashMap没有锁机制,不是线程安全的。 (2) HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。 ConcurrentHashMap的工作原理及代码实现 HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体, 当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时 间。 ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16, 0.75, 16。、
public Concurrent Hash Map(int paramlntl, float paramFloat, int paramlnt2) {
//•••
int i = 0;
int j = 1;
while (j < paramlnt2) {
++i;
j «= 1;
}
this.segmentShift = (32 - i);
this.segmentMask = (j - 1);
this.segments = Segment.newArray(j);
//•••
int k = paramlntl / j;
if (k * j < paramlntl)
++k;
int I = 1;
while (I < k)
I «= 1;
for (int il = 0; il < this.segments.length; ++il)
this.segments[il] = new Segment。,paramFloat);
}
public V put(K paramK, V paramV) {
if (paramV == null)
throw new NullPointerException();
int i = hash(paramK.hashCode()); //这里的 hash 函数和 HashMap 中的不一样
return this.segments[(i »> this.segmentShift & this.segmentMask)].put(paramK, \, paramV, false);
}
ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为把一个 大的Map拆分成N个小的HashTable,在put方法中,会根据hash(paramK.hashCode())来决 定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机 制是基于lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只 是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map (HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable 已经被淘汰了。
获取更多面试题,点我或者 今天分享到这里结束,希望我的分享能够帮助到你。