场景:程序要连接数据库
面向对象:市面上大家都使用的是什么组件,或那个框架完成的,我直接拿来使用。如何使用对象,组织者
面向过程:我该怎么连接数据库,怎么具体实现。如何创建对象,执行者
1.1 java的三大特性:封装、继承、多态封装:隐藏内部实现,对外提供接口,提高安全性,复用性
继承:公用的内容,抽取作为父类,提高复用性
多态:包含重写,重载。
多态是同一个行为具有多个不同的表现形式或形态的能力;多态就是同一个接口使用不同的实例而执行不同 *** 作; 2. JDK、JRE、JVMjdk:开发工具包,提供运行环境(jre)和开发环境,包含编译java源文件的编译器javac,还有调试和分析工具。
jre:java运行环境仅包含java虚拟机(jvm)和一些基础类库
jvm:java虚拟机,运行字节码文件
2.2. java的跨平台主要是通过jvm实现的,在不同平台(win,mac,linux…)都有自己的jvm,而只要是编译后的字节码文件都可以通过任何平台的jvm运行,从而实现跨平台
3. ==和equals的区别== : 比较的的是具体的值 (基本数据类型) ,如果比较引用数据类型 也是比较引用地址
equals :默认比较的是引用指向的地址(object类的方法),可以进行重写
修饰类:类不可被继承,最终类
修饰方法:该方法不可被重写
修饰变量:那么这个变量就成为一个常量
修饰基本数据类型,那么这个值不可改变
修饰引用数据类型,指向的堆内存不可改变
5. String,StringBuffer,StringBuilderString跟后两者的区别:String 是final类每次声明都是不可变对象,每次 *** 作都会new新的对象
StringBuffer StringBuilder都是在原有对象进行 *** 作 如果要经常改变字符串的内容 使用这两者
StringBuffer是线程安全的,StringBuilder是不安全的
效率:StringBuilder > StringBuffer > String
5.1 线程安全与不安全线程安全:在多环境下,这个对象的访问不需要加入额外的同步控制, *** 作的数据依然是正确的
线程不安全:反之,数据不正确
StringBuffer安全是因为源码每个方法中都加入了synchronized关键字
在开发中,优先选用StringBuilder(性能高),要解决线程安全(高并发、多线程情况下)——>多线程要考虑,栈内存中数据是共享,还是每个线程独享,如果是线程独享,不必考虑安全问题
6. 抽象类和接口的区别1,语法层面
1.1,JDK1.8之前
抽象类:方法可以有抽象的,也可以有非抽象(正常的方法,具体的实现), 有构造器
接口:方法都是抽象,属性都是常量,默认有public static final修饰
1.2,JDK1.8之后
接口里面可以有实现的方法,注意要在方法的声明上加上default或者static
interface IEatable{
public default void eat(){}
}
2,开发设计层面
抽象类:同一类事物的抽取,比如针对Dao层 *** 作的封装,如,BaseDaoImpl,BaseServiceImpl
接口:通常更像是一种标准的制定,定制系统之间对接的标准规范 (解耦)
例子:- 1,单体项目,分层开发,接口作为各层之间交互的纽带,在controller中注入IUserService,在Service注入IUserDao
- 2,分布式项目,面向服务的开发,抽取服务service,这个时候,就会产生服务的提供者和服务的消费者两个角色
- 这两个角色之间的纽带,依然是接口
最后区分几个概念:
多继承,多重继承,多实现
多继承:接口可以多继承,类只支持单继承- 多重继承:A->B->C(爷孙三代的关系)
- 多实现:Person implements IRunable,IEatable(记忆联想-符合多项国际化标准) 7. 递归
递归:方法内部调用方法自身
找到规律找到递归出口 7.1 递归为什么会栈内存溢出在调用方法时候会在栈中开辟空间 栈帧,调用一次,会创建一个,所以,如果递归次数太多,会导致栈内存溢出。
7.2 N的阶乘N! = (N-1)! * n;
5! = 1*2*3*4*5;
4! = 1*2*3*4;
public static int getResult(int n){
if(n < 0){
throw new RuntimeException("非法参数");
}
if(n == 1 || n == 1){
return 1; //递归出口
}
return getResult(n-1) * n;
}
7.3 斐波那契
数字:1,1,2,3,5,8,13,21 … 求,第n个数是多少
规律:每个数字都是前两个数字之和
递归出口:第一项和第二项都是1
public int getFeiBo(int n){
if(n < 0){
throw new RuntimeException("非法参数");
}
if(n == 1 || n == 2){
return 1;
}else{
return getFeiBo(n-2) + getFeiBo(n-1);
}
}
8. 什么是向上转型?什么是向下转型?
向上转型:父类引用指向子类对象。(安全)
向下转型:父类对象强转为子类对象。(不安全)
9.Integer intInteger 引用数据类型(包装类);
int 基本数据类型
Integer i1 = new Integer(66);
Integer i2 = new Integer(66);
System.out.println(i1 == i2); //false 两个都是new出来的 所以指向的堆内存不同 false
// 自动装箱范围:-128 -- +127 之间 也就不是新new出来的对象 查看Integer.valueof源码
Integer i3 = 66;
Integer i4 = 66;
int i5 = 66;
System.out.println(i3 == i4); //true i3,i4都是使用基本数据类型进行赋值 进行自动装箱 (jdk1.5之后)Integer.valueof();
System.out.println(i3 == i5); //true 引用数据类型跟基本数据类型进行比较时候 会进行 自动拆箱 就是将引用类型转成基本类型
Integer i6 = 128;
Integer i7 = 128;
int i8 = 128;
System.out.println(i6 == i7); //false
System.out.println(i6 == i8); //true
10. 重写和重载的区别
重载:发生在一个类中,多个方法 方法名相同,参数列表不同(顺序,类型,都可)就叫做重载。与返回值无关
重写:发生在两个父类跟子类之间,子类对父类方法的重新编写,满足:方法名相同,参数列表相同,子类方法访问权限只能大于父类
11. List和Set的区别list:有序,不可重复
set:无序,不可重复 (无序:加入集合的顺序 != 遍历的顺序)
12.ArrayList 和LinkedList的区别底层数据结构
ArrayList 底层是数组结构,是一块连续的内存空间LinkedList底层是双向链表,是不连续的内存常规答案
ArrayList查询快,因为内存是连续的,方便寻址,但是增删慢,因为需要发生数据迁移
LinkedList查询慢,通过指针查找,但增删快,只需要改变前后结点的指针指向
通过下标查询,ArrayList快,如果指定元素,查询所在位置,两者相同 ArrayList有下标
增删:
如果是中间或者非结尾
ArrayList因为底层为数组保证内存连续,所以,插入位置后的所有元素都要移动,导致速度变慢LinkedList因为底层是链表,只需要改变所在位置前后元素的结点指向即可如果是结尾
ArrayList因为底层为数组,可计算位置,快速定位直接 *** 作
LinkedList有两个指针,头指针,尾指针,要在末尾找会从尾指针开始找
末尾插入,两者类似
在向List中存入固定个数的元素 ArrayList更节省内存(初始化容量)
ArrayList 扩容
创建一个新的数组,长度是原数组的1.5倍(位运算)将原数组迁移到当前数组双向链表中在元素A和B中间插入元素C
13. HashSet 存储原理伪代码:
C.pre = A
C.next = A.next
A…next.pre = C
A.next = C
HashSet 不可重复的原因:hashSet.add方法使用的是map集合,将add的东西作为key,所以不可重复
HashSet底层使用HashMap实现存储
13.1 为什么使用hash算法,有什么优势,解决了什么问题?主要是解决数据的唯一性判断的效率问题,保证为O(1)的复杂度
存储数据,底层用的是数组,数组实现唯一性就是遍历,这种效率比较低,所以采用hashcode采用hash算法,通过存储对象的hashcode,然后在跟数组长度-1做运算,得到我们要的存储在数组中的下表,如果此时这个下表没有其他元素,那么就不用比较,直接存储。hash冲突:不同的元素,或对象,hash值相同这时候就需要比较,使用equals,如果equals相等 则是重复的 不插入,如果不相等,就将当前位置的next指针指向要插入的元素,从而形成链表 13.2 什么是hash表本质是一个数组,数组元素构成链表
13.3 链表的优化jdk1.8之后,防止链表过长,会将链表优化为红黑树,使用二分查找比较,这样效率就更快了
14. ArrayList 和 Vector区别:前者线程安全,后者不安全
类似于StringBuffer 和 StringBuilder的区别
15. HashTable & HashMap & ConcurrentHashMap HashTable 线程安全,内部有锁的控制HashMap 线程不安全,内部没有锁 优点:效率高缺点:如果有多个线程同时 *** 作,并且线程共享栈帧,那么就会产生线程安全的问题,甚至会出现死锁 ConcurrentHashMap 使用的是分段锁,降低锁粒 jdk8 以前 将数据分段,执行分段锁(分离锁),核心把锁的范围变小,这样出现并发冲突的概率就变小在put时候,key会首先进过hash运算,拿到所在的hash段,然后只锁当前段 相当于是折中jdk7 和 jdk8中的区别 jdk1.7采用的是链表 jdk1.8采用的链表+红黑树发生hash冲突时候 jdk1.7 采用链表 jdk1.8默认使用链表 链表长度超过8且数组容量超过64时时候使用红黑树 并发安全的实现 JDK1.7采用分段锁的方式,而JDK1.8采用CAS和synchronized的组合模式 查询时间复杂度 JDK1.7采用链表的方式,时间复杂度为O(n),而JDK1.8在采用红黑树的方式时,时间复杂度为O(log(n)) 开发中选择 HashMap 不是多线程的情况如果HashMap是个全局对象,并且线程共享map对象 选择ConcurrentHapMapHashTable 不选择 效率低 16. 栈 stack 是如何实现的特点:FILO(First In Last Out)先进后出
底层是使用数组
入栈:数组尾部直接插入public E push(E item) {
addElement(item);
return item;
}
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1); // 判断数组容量是否充足
elementData[elementCount++] = obj;
}
出栈:尾部出
第一种:获取并从栈中删除
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
第二种:获取栈顶元素
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)