Java 阶段面试 知识点合集 - 我们到底能走多远系列(15)
我们到底能走多远系列(15)
扯淡:这些知识点来源是通过面试涉及到的,面的公司不多,知识点涉及也不多,我每次面试后都在备忘录里写下有用的东西,集合起来分享一下,因为是知识点,所以就不出什么面试题目啦。不涉及任何公司,也不谈论面经,纯粹是学习而已。
《我们到底能走多远系列》的阶段性目标已经达到啦,15个,先给自己鼓励一下吧。
有目的性学习的确会让人不偷懒,能让人在短时间里努力,自我激励的方式很多,每天花点时间做一件事对你肯定有帮助,好吧先讲一个故事,口痒了,哈哈。
可能很多朋友都听过了,没关系,再听一遍,你就可以熟练的讲给你的朋友们听了。
从前有两个和尚他们分别住在河对岸的两个庙里,每天他们都会来河边打水,每天都会见面,时间一长他们就相当于那啥,心灵相通,成了好朋友,但他们谁也没跨过河去看望过对方。这样年复一年,一日,住在东岸的和尚没来打水,西岸的和尚就疑惑了,一天不打水,他喝什么呢?第二天,西岸的和尚还是没来,连续半个月东岸的和尚都没见到西岸的和尚,于是他就想他朋友是不是病了。于是就挑着水去到西岸的庙里,他看到他的朋友一点没事,就问他:你怎么不来河里打水了呢,没有水,你喝什么呢?西岸的和尚把他朋友领到园子里,指着角落里的一口井说,这是我挖的一口井,有了井,就不用再去河边打水了。东岸的和尚又问了:我们平时在庙里怎么忙,几乎没有空闲的时间,你怎么可能有时间挖一口井呢?回答:我每天就在那个地方掘一下,年复一年,它就成了井。
你在掘你的井吗?
主题:
关于数据结构:有不正确的地方或改进的地方希望你能指出来,我会感谢你给我进步的机会。
1,stack
来自《Introduction to Algorithms》的图:
遵循先进后出(FILO)的原则,下面是模拟的代码:
package code.structures; public class Stack { private String[] s;// 用数组来模拟 private int top; private int length; // 初始化 public Stack(int index){ this.s = new String[index]; this.top = 0; this.length = index; } // 放数据 public void push(String str){ if(str == null){ return; } if(top == length){ System.out.println("stack is full"); return; } this.s[top] = str; this.top++; } // 拿数据 public String pop(){ if(this.isEmpty()){ System.out.println("There is no data"); return null; } String s1 = s[--top];//因为数组从0开始,顺便每pop一次要把top减一 s[top] = null; return s1; } // 取得最高位置 public int getTop(){ return this.top; } public boolean isEmpty(){ if(this.top == 0){ return true; } return false; } }
2,queue
来自《Introduction to Algorithms》的图:
遵循先进先出(FIFO)的原则,下面是模拟的代码:
代码使用标志符的方式来控制内部的数组不溢出和为空是不能取出数据。
package code.structures; public class Queue { private String[] s;// 用数组来模拟 private int head; // 队列头 private int tail; // 队列尾 private int length; // 队列长度 private boolean isFull; // 满信号 private boolean isEmpty; // 空信号 public Queue(int index) { this.s = new String[index]; this.head = 0; this.tail = 0; length = index; isFull = false; isEmpty = true; } // 放数据 public boolean enQueue(String str) { if (isFull) { // 已满的队列就不能再放数据啦 System.out.println("queue is full"); return false; } // 放在队列的尾部 s[tail] = str; tail++; // 移动尾部 // 头尾相连 if (tail == length) { tail = 0; } // 在放数据的时候出现头尾相同时,就认为是满了 if (head == tail) { isFull = true; } // 因为是放数据,所以不可能出现空队列 if (isEmpty) { isEmpty = false; } return true; } // 拿数据 public String deQueue() { if (isEmpty) {// 空队列就不处理了 System.out.println("queue is empty"); return null; } // 从头部取得数据 String str = s[head]; head++; if (head == length) { head = 0; } // 取数据的时候出现头尾相同,就认为出现空队列 if (head == tail) { isEmpty = true; } // 因为是取数据,所以不可能出现一个满队列 if (isFull) { isFull = false; } return str; } public boolean isEmpty(){ return isEmpty; } public boolean isFull(){ return isFull; } }
3,ArrayList和LinkedList
我们不看他们的源码,但也有必要知道他们大概的实现方式:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。这就是他们区别的关键之处,我想着相当于是一个数组和一个链表在比较。
ArrayList基于数组的,看他的构造方法:
public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity // 传入ArrayList大小,就帮你创建一个这样大小的Object数组 this.elementData = (E[])new Object[initialCapacity]; } public ArrayList() { this(10);//默认的话,就是10大小的数组 }
关于ArrayList的动态数组的实现,是依靠啦一个方法: System.arraycopy方法。
看下面两个源码方法就会明白:
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; // 新数组长度是老数组的1.5倍 int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // 创建出新的数组 elementData = (E[])new Object[newCapacity]; // 把老数据拷贝到新数组里去 System.arraycopy(oldData, 0, elementData, 0, size); } } public boolean add(E o) { ensureCapacity(size + 1); // 确定是否需要增长数组 elementData[size++] = o; return true; }
ArrayList的remove方法,决定了它暴露了频繁删除数据性能不高的原因:
public E remove(int index) { RangeCheck(index); modCount++; E oldValue = elementData[index];//删除的数据作为返回值 int numMoved = size - index - 1; if (numMoved > 0) // 用一个自我拷贝,移动了删除点后的全部数据,所以会影响效率 System.arraycopy(elementData, index+1, elementData, index, numMoved); // copy数据后,最后一位的数据还在,需要把它删除 elementData[--size] = null; // Let gc do its work return oldValue; }
而LinkedList是基于列表的,它的remove只需要断开一个连接,连上一个连接,无论我们删除那一个数据需要的时间是相同的。但是考虑到LinkedList的检索需要更多的时间因为,最差的结果里,需啊哟遍历整个Link。
所以:
1.对于随机访问get和set,ArrayList觉得优于LinkedList。
2.对于新增和删除操作add和remove,LinedList比较占优势。
3.若只对单条数据插入或删除,ArrayList的速度反而优于 LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList.
3.HashMap和HashTable
1.HashMap 线程非安全 null可为key
2.HashTable 线程安全 null不可为key
3.HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。
4.SQL基础几点
1,case语句的使用
select classId, count(case when sex = "男" then 1 end) from Test group by classTd;
2,group by :
select后面的所有列中,没有使用聚合函数的列,必须使用group by!
3,having:
筛选满足条件的组,条件经常包含聚合组函数.
4,left join 相当于 left out join ,right join 相当于 right out join 也就是说什么外连接就是左连接和右连接嘛(不知道准不准确),join 相当于 inner join。
还有个full join,链表全部需要查出来嘛。
left join和right join相当于是求有交集的两个集合的一个集合的值。
inner join相当于是纯粹的交集。
full join 你懂的还剩下并集。
5,代码规范
可读性:代码是否可读易读,对于一个团队来说,编码标准是否一致,编码风格是否一致;
功能性:代码正确得实现了业务逻辑;
可维护性:代码逻辑是有层次的,是容易修改的;
高效性:代码实现在时间和空间的使用上是高效的;
就这么多吧,sql方面还有很多需要学习的地方,发现以前写的出的sql现在觉得很困难了,各位,有没有学习提高sql的方法,或推荐的书。以前系统学过sql后几个月没用,就一下生疏了,然后重复捡起来,再生疏,难点复杂点的sql头绪会很乱,有好的训练方法吗?
让我们继续前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不会成功。
共勉