有一段话,我很喜欢:人会长大三次。第一次是在发现自己不是世界中心的时候。第二次是在发现即使再怎么努力,终究还是有些事令人无能为力的时候。第三次是在,明知道有些事可能会无能为力,但还是会尽力争取的时候。
作为乌龟,我们可以去自己想去的地方。但是不要停止奔跑。
1.冒泡排序
针对 数组的 排序 ,其思想就是 逐个对比数大小 ,把大的数字放后面。
public static void bubbleSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
2.二分查找
针对数组 对半查找key 所在的位置
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
3.集合数组
public class MyStack {
private LinkedList link;
public MyStack() {
link = new LinkedList();
}
public void add(Object obj) {
link.addFirst(obj);
}
public Object get() {
return link.removeFirst();
}
public boolean isEmpty() {
return link.isEmpty();
}
}
/*
* MyStack的测试
*/
public class MyStackDemo {
public static void main(String[] args) {
// 创建集合对象
MyStack ms = new MyStack();
// 添加元素
ms.add("hello");
ms.add("world");
ms.add("java");
while(!ms.isEmpty()){
System.out.println(ms.get());
}
}
}
使用LinkedList模拟一个堆栈或者队列数据模式 堆栈:先进后出 队列:先进先出
4.Vector使用
Vector vector = new Vector<>();
vector.addElement("ss");
vector.addElement("8888");
vector.addElement("1231312432");
for (int i = 0; i < vector.size(); i++) {
String string = (String) vector.elementAt(i);
System.out.println("vector:" + string);
}
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
String object = (String) enumeration.nextElement();
System.out.println("vector:" + object);
}
5.TreeSet类
- 使用元素的自然顺序对元素进行排序
或者根据创建 set 时提供的 Comparator 进行排序
所以排序有两种方式
自然排序
比较器排序
具体取决于使用的构造方法。
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
// 自然顺序进行排序
TreeSet<Integer> ts = new TreeSet<Integer>();
// 创建元素并添加
// 20,18,23,22,17,24,19,18,24
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);
// 遍历
for (Integer i : ts) {
System.out.println(i);
}
}
}
6. 二叉树
那么二叉树是怎么把元素存进去,又是怎么取出来的呢?
如果你弄懂了这个问题,那么你就明白了二叉树了
我们先来了解元素是如何存储进去的?
第一个元素存储的时候,直接作为根节点存储。
从第二个元素开始,每个元素从根节点开始比较
比根节点元素大,就放在右边
比根节点元素小,就放在左边
相等的话就忽略。
我们以上面的存储的元素20,18,23,22,17,24,19,18,24来画一个图帮助大家理解
7.HashMap和Hashtable的区别?
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("android", "hello");
hm.put(null, "world");
hm.put("java", null);
System.out.println(hm);
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("android", "hello");
ht.put(null, "world"); //NullPointerException
ht.put("java", null); // NullPointerException
System.out.println(ht);
在输出结果中:HashMap会打印出{null=world, Java=null, Android=hello} 而在Hashtable中会报错
所以我们就能得出他们的区别
HashMap:线程不安全,效率高。允许null键和null值
Hashtable:线程安全,效率低。不允许null键和null值
8.Collections类
- Collections类概述
针对集合进行操作的工具类,都是静态方法。 - Collection和Collections的区别
Collection:是单列集合的顶层接口,有子接口List和Set。
Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法 - Collections成员方法
public static < T> void sort(List list):排序 默认情况下是自然顺序。
public static < T> int binarySearch(List< ?> list,T key):二分查找
public static < T> T max(Collection< ?> coll):最大值
public static void reverse(List< ?> list):反转
public static void shuffle(List< ?> list):随机置换
9.final,finally和finalize的区别?
final
最终的意思,可以修饰类,成员变量,成员方法
修饰类,类不能被继承
修饰变量,变量是常量
修饰方法,方法不能被重写
finally
是异常处理的一部分,用于释放资源。
一般来说,代码肯定会执行,特殊情况:在执行到finally之前jvm退出了
finalize
是Object类的一个方法,用于垃圾回收
这个题的难点就在于finalize,我们很少了解
子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。
如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
10.装饰设计模式
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,Java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式),所以提供了字节缓冲区流
11.IO流
注意:我们除了用windows记事本能读懂的数据用字符流以外,其余的全部使用字节流。
// 第五种字符缓冲流一次读写一个字符串
private static void method5(String srcString, String destString)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(srcString));
BufferedWriter bw = new BufferedWriter(new FileWriter(destString));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
// 第四种字节缓冲流一次读写一个字节数组
private static void method4(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcFile));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
close()和flush()的区别?
close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
12.线程
由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,然后提供一些类供我们使用。我们就可以实现多线程程序了。
同步的特点:
多个线程
多个线程使用的是同一个锁对象
好处:同步的出现解决了多线程的安全问题
弊端: 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
同步代码块的锁对象可以时任意对象。
但是,当把同步关键字加在方法上,它的对象是this
当此方法为精态方法时,它的对象是类的字节码文件对象,也就是 类名.class
13.多线程生产者和消费者问题
什么是生产者和消费者
简单来说就是生产一个,消费一个,具体点就是
生产者 :先看是否有数据,有就等待;没有就生产,生产完成之后通知消费者来消费数据
消费者:先看是否有数据,有就消费;没有就等待,通知生产者生产数据
为了处理这样的问题,Java提供了一种机制,等待唤醒机制
抽象到现实:
比如 你到沙县 吃个鸭腿饭! 如果老板 刚好有一份弄好的鸭腿饭,那直接拿给你消费。没有的话, 老板自己立马打个饭加点青菜萝卜 烤个鸭腿放上去,自己生产一份 拿去给你消费。
而你呢?如果有一份做好的,那么就直接开搞吃,没有的话就通知老板 下单搞一份,在那默默等待咯。如果吃不够,再叫老板生产一份!
14.设计模式
面向对象思想设计原则
单一职责原则
其实就是开发人员经常说的”高内聚,低耦合”
开闭原则
核心思想是:一个对象对扩展开放,对修改关闭。其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
里氏替换原则
核心思想:在任何父类出现的地方都可以用它的子类来替代。其实就是说:同一个继承体系中的对象应该有共同的行为特征。
依赖注入原则
核心思想:要依赖于抽象,不要依赖于具体实现。
接口分离原则
核心思想:不应该强迫程序依赖它们不需要使用的方法。
迪米特原则
核心思想:一个对象应当对其他对象尽可能少的了解
设计模式概述
设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式不是一种方法和技术,而是一种思想
设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用
学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成
设计模式的分类
创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)
结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)
行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)
1.工厂方法模式
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
2.单例设计模式
单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。
饿汉式:类一加载就创建对象
懒汉式:用对象的时候,才去创建对象
面试主要面两个思想,分别是:
懒加载思想(延迟加载)
线程安全问题(就要考虑下面3个方面)
是否多线程环境
b:是否有共享数据
c:是否有多条语句操作共享数据
如果都是,就会存在线程的安全问题,我们上面的懒汉式代码是不完整的,应该给对象中的方法加上synchronized关键字,这样才算完整
public synchronized static Teacher getTeacher() {
if (t == null) {
t = new Teacher();
}
return t;
}
模版设计模式
模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
装饰设计模式
装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案
在IO流中的装饰模式应用
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));