Java基础面试

1、为什么要重写hashcode()方法

主要原因是默认从Object继承来的hashCode是基于对象的ID实现的。
如果你重写了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。
这样,当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。

2、HashMap

底层是数组+链表+红黑树,哈希表

key : value结构,key不可重复,重复则value值被覆盖

HashMap的key会先后调用hashCode and equals方法,两个方法都需要重写

map.put(k,v)、map.get(k)实现原理:

调用k的hashCode()方法,找到数组下标,再与链表上元素进行equals()。

单向链表中元素超过8个,那么单向链表这种数据结构会变成红黑树数据结构。

当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。

hashmap集合的默认初始化容量为16,默认加载因子为0.75,当hashMap集合底层数组的容量达到75%时,数组就开始扩容。

3、默认的equals方法同==

  • 对于值对象,==比较的是两个对象的值
  • 对于引用对象,比较的是两个对象的地址

4、map遍历

keySet().iterator();

entrySet().iterator();

5、substring截取字符串

substring(2); [2,结束]

substring(2,4); [2,4)

为什么左含右不含

String st1 = "abcdefghi";
String st2 = "ss";
st1.substring(0,st2.length());  //返回"ab"
//length值比索引值多1,右不含正好

concat(“拼接字符串”);
contains(“包含字符串”)

6、JDBC

Class.forName(“com.mysql.jdbc.Driver”):加载注册驱动

DriverManager驱动:获取连接,返回一个连接

Connection对象:连接

Statement对象:执行SQL

ResultSet对象:结果集

7、事务

  • DML(Data Manipulation Language)数据操纵语言:对数据进行操作
    select、insert、delete、update

  • DDL(Data Definition Language)数据库定义语言:

    改变表(table)结构,对对象进行处理,表、视图、索引、存储组(STOGROUP)
    create(创建)、alter(修改)、drop(删除)

  • DCL(Data Control Language) 数据库控制语言:设置或更改数据库用户或角色权限
    grant(授予权限)、deny、revoke

7.1、自动提交

数据一旦提交,不可回滚

  • DML、DDL一旦执行,自动提交
    set autocommit = false; //可取消DML操作自动提交,对DDL无效
    connection.setAutoCommit(false);

  • 默认再关闭连接时,自动提交数据
    connection.close();

7.2、事物的ACID属性
  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)
7.3、隔离级别

并发问题

  • 脏读:T1读取了T2更新但没有提交的数据

  • 不可重复读:T1读取数据,T2更新数据,T1再读,两次数据不一致

  • 幻读:T1读取数据,T2插入数据,T1再读,数据不一致,多出几行

隔离级别

  • read uncommitted(读未提交)
  • read committed(读已提交):oracle默认
    解决脏读
    在一个事务内,其他用户操作数据库且提交了,自己会读到修改后的数据
  • repeatable read(可重复读):mysql默认
    解决不可重复读
    在一个事务内,其他用户操作数据库不影响 自己读取数据,事务未提交期间数据不会改变
  • serializable(串行化):解决幻读

8、SQL

更新:修改现有行

UPDATE 表名称 SET 列名称=新值,列名称=新值 WHERE 列名称=某值

update user set name='jack' where id=1;

插入:创建新行

INSERT INTO 表名称 VALUES (值1, 值2,....)
INSERT INTO 表名称 (列1, 列2,...) VALUES (值1, 值2,....)

INSERT INTO user VALUES("jack",12,"男");
INSERT INTO user(name,a) VALUES("jack",12,"男");

删除

DELETE FROM 表名称 WHERE 列名称 = 值

9、HashMap和Hashtable的区别

HashMap不是线程安全的,HashMap允许null key和null value,而hashtable不允许。效率高一点。

HashTable是线程安全

10、sleep与wait的区别

10.1、来自不同的类

sleep来自Thread类,和wait来自Object类。

10.2、有没有释放锁(释放资源)

sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。

最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源

就是说sleep有时间限制的就像闹钟一样到时候就叫了,而wait是无限期的除非用户主动notify

10.3、使用范围不同

wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用

10.4、是否需要捕获异常

sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

11、sleep()方法和yield()方法有什么区别?

①sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

12、join()

在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join(); //调用join方法,等待线程t执行完毕
t.join(1000); //等待 t 线程,等待时间是1000毫秒。

13、final

  • final修饰属性

    • 基本类型:值不变
    • 对象:引用不变
  • final修饰方法:不可重写

  • final修饰类:不可继承

14、final修饰基本类型变量和引用变量

  • 当使用final修饰基本数据类型时,不能对其重新赋值,不能被改变。
  • 当使用final修饰引用类型变量时,它仅仅保证他的地址不变,即一直引用同一个对象,但这个对象完全可以发生改变。

15、static

static修饰方法:
static静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

static修饰变量:
静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。

static修饰内部类:
1.静态内部类跟静态方法一样,只能访问静态的成员变量和方法,不能访问非静态的方法和属性,但是普通内部类可以访问任意外部类的成员变量和方法
2.静态内部类可以声明普通成员变量和方法,而普通内部类不能声明static成员变量和方法。
3.静态内部类可以单独初始化:
Inner i = new Outer.Inner();
普通内部类初始化:
Outer o = new Outer();
Inner i = o.new Inner();

16、session和cookie的区别包括

存储位置不同、安全性不同、存储方向不同、跨域支持不同、依赖条件不同、大小不同。

1、存储位置不同,session 在服务器端,cookie 在客户端(浏览器)

2、安全性不同,cookie存放在客户端,可通过xss漏洞进行攻击,获取用户敏感信息,session 默认被存在在服务器的一个文件里,不容易被获取。

3、存储方向不同,session 可以放在文件、数据库、或内存中都可以。

4、跨域支持不同,cookie支持跨域使用,session只有在同一个站点才能使用。

5、依赖条件不同、session 的运行依赖 session id,而 session id 是存在 cookie 中的,如果浏览器禁用了 cookie ,同时 session 也会失效

6、大小不同,cookie的大小限制为4kB,且一般一个站点只能用20个cookie。

7、session id是维持一个会话的核心就是客户端的唯一标识。

17、session的创建:

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了sessionId,如果已包含则说明以前已经为此客户端创建过session,服务

器就按照sessionId把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含sessionId,则为此客户端创建一个session并且生成一个与此session相关

联的sessionId,sessionId的值是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionId将被在本次响应中返回给客户端保存。

18、servlet生命周期

1,创建Servlet对象,调用构造函数,通过服务器反射机制创建Servlet对象,第一次请求时才会创建。(默认)

2,调用Servlet对象的init()方法,初始化Servlet的信息,init()方法只会在创建后被调用一次(初始化阶段)

3,响应请求,调用service()或者是doGet(),doPost()方法来处理请求,这些方法是运行的在多线程状态下的。(响应客户请求阶段)

4, 在长时间没有被调用或者是服务器关闭时,会调用destroy()方法来销毁Servlet对象。(终止阶段)

19、反射

获取对象三种方式:

1、Class clazz1 = Class.forName(“全限定类名”);
2、Class clazz2 = Person.class; 
3、Person p = new Preson(); Class clazz3 = p.getClass();

获取构造器
Construnctor con = clazz1.getConstructor(int.class,String.Class);

通过构造器获取对象
User user = (User)con.newInstance(12,“小明”);

获取成员变量并使用—Filed对象

Class.getField(String) 获取类中可见字段

getDeclaedField(“name”) 获取私有变量 setAccessible(true)

获得方法并使用 Method

Class.getMethod(String, Class…)

Class.getDeclaredMethod(String, Class…)

获得该类的所有接口

Class[] getInterfaces();

20、SQL

left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 ,没有显示null
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录,没有显示null
inner join(等值连接) 只返回两个表中联结字段相等的行

21、重写与重载之间的区别

区别点重载方法重写方法
参数列表必须修改一定不能修改
返回类型可以修改一定不能修改
异常可以修改可以减少或删除,一定不能抛出新的或者更广的异常
访问可以修改一定不能做更严格的限制(可以降低限制)

异常小、访问大

22、io流

继承关系

  • InputStream:读取字节流抽象类

    • FileInputStream:字节输入流
    • FilterInputstream:过滤字节输入流
      • BufferedInputStream:字节输入缓冲流
      • DataInputStream:数据类型输入处理流
    • ObjectInputStream:引用类型输入处理流(对象反序列化)
    • ByteArrayInputStream:字节数组输入流
  • Reader:读取字符流抽象类

    • InputStreamReader:字符输入处理流,字节流–>字符流
      • FileReader:字符输入流
    • BufferedReader:字符输入缓冲流
    • CharArrayReader:字符数组输入流

23、Array与Arraylist区别

Array:固定长度数组,存储相同类型的基本数据类型或对象

ArrayList:动态数组,可存储不同类型对象,基本数据类型通过自动装拆箱转换为对象

23.1、储存的数据类型

ArrayList可以存储不同类型的对象,而Array只能存储相同数据类型的数据。

23.2、长度的可变

Array的长度实际上是不可变的,二维变长数组实际上的长度也是固定的,可变的只是其中元素的长度。ArrayList的长度既可以指定(即使指定了长度,也会自动2倍扩容)也可以不指定,是变长的。

23.3、存取和增删元素

对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往ArrayList里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。

23.4、转换

list.toArray()

Arrays.asList()

24、String、StringBuffer、StringBuilder

24.1、创建
String str1 = "hello world";	//字面量创建,添加到常量池
String str1 = new String("hello world"); 
//在类加载的过程中,在运行时常量池中创建了一个"abc"对象,在代码执行过程中创建了一个String对象。
24.2、修改
public final class String{ }  //String类被final修饰,不可继承
private final char value[];  //value属性被final修饰,不可更改

对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象。

String string = "";
string += "hello";		//String类执行+=操作,底层创建StringBuilder进行添加

JVM自动优化为StringBuilder

StringBuilder str = new StringBuilder(string);
str.append("hello");
str.toString();

StringBuffer、StringBuilder会直接在原对象上添加元素

StringBuffer加锁,比StringBuilder慢

25、值传递与引用传递

值传递:(形式参数类型是基本数据类型):

方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

引用传递:(形式参数类型是引用数据类型参数):

也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。

26、数据库范式

1.第一范式(确保每列保持原子性)

2.第二范式(确保表中的每列都和主键相关)

3.第三范式(确保每列都和主键列直接相关,而不是间接相关,消除依赖)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值