map遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Map<String, Integer> map = new HashMap<>(); map.put("a" , 1 ); map.put("b" , 2 ); map.put("c" , 3 ); for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println("key: " + entry.getKey()); Syetem.out.println("value: " + entry.getValue()); } for (String key : map.keySet()) { System.out.println("key: " + key); } for (Integer value : map.values()) { System.out.println("value: " + value); } Iterator<Map.Entry<String, Integer>> itor = map.entrySet().iterator(); while (itor.hasNext()) { Map.Entry<String, Integer> entry = itor.next(); System.out.println("key: " + entry.getKey()); System.out.println("value: " + entry.getValue()); } map.foreach((key, value) -> { System.out.println("key: " + key); System.out.println("value: " + value); });
Set遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Set<String> set = new HashSet<>(); set.add("a" ); set.add("b" ); set.add("c" ); for (String str : set) { System.out.println(str); } Iterator<String> itor = set.iterator(); while (itor.hasNext()) { String str = itor.next(); System.out.println(str); }
时间工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public class Test { public static void main (String[] args) { Date date = new Date(); System.out.println(date); Instant instant = Instant.now(); System.out.println(instant); long currentSecond = instant.getEpochSecond(); long currentMilli = instant.toEpochMilli(); long systemCurrent = System.currentTimeMillis(); System.out.println(currentSecond); System.out.println(currentMilli); System.out.println(systemCurrent); LocalDateTime localDateTime = LocalDateTime.now(); LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); System.out.println(localDateTime); System.out.println(localDate); System.out.println(localTime); LocalDateTime localDateTime1 = LocalDateTime.of(2019 , Month.SEPTEMBER, 10 , 14 , 46 , 56 ); System.out.println(localDateTime1); localDateTime1 = localDateTime1.plus(1 , ChronoUnit.YEARS); System.out.println(localDateTime1); localDateTime1 = localDateTime1.minus(1 , ChronoUnit.MONTHS); System.out.println(localDateTime1); localDateTime1 = localDateTime1.with(ChronoField.YEAR, 2023 ); System.out.println(localDateTime1); LocalDate localDate1 = LocalDate.of(2019 ,9 ,10 ); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy" ); String str = localDate1.format(dateTimeFormatter); System.out.println(str); LocalDateTime localDateTime2 = LocalDateTime.parse("2017-12-13 10:10:10" , DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" )); System.out.println(localDateTime2); } }
参考链接1 、参考链接2
使用Predicate操作集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class Test { public static void main (String[] args) { var books = new HashSet<>(); books.add("轻量级JAVA EE企业应用实战" ); books.add("疯狂JAVA讲义" ); books.add("疯狂IOS讲义" ); books.add("疯狂Ajax讲义" ); books.add("疯狂Android讲义" ); books.removeIf(ele -> ((String) ele).length() < 10 ); books.foreach(System.out::println); var books = new HashSet<>(); books2.add("轻量级JAVA EE企业应用实战" ); books2.add("疯狂JAVA讲义" ); books2.add("疯狂IOS讲义" ); books2.add("疯狂Ajax讲义" ); books2.add("疯狂Android讲义" ); System.out.println(calAll(books2, ele -> ((String) ele).contains("疯狂" ))); System.out.println(calAll(books2, ele -> ((String) ele).contains("Java" ))); System.out.println(calAll(books2, ele -> ((String) ele).length() > 10 )); System.out.println(books.stream().filter(ele -> ((String) ele).contains("疯狂" )).count()); System.out.println(books.stream().filter(ele -> ((String) ele).contains("Java" )).count()); System.out.println(books.stream().filter(ele -> ((String) ele).length() > 10 ).count()); books.stream().mapToInt(ele -> ((String) ele).length()).foreach(System.out::println); } private static int calAll (Collection books, Predicate predicate) { int total = 0 ; for (var obj : books) { if (predicate.test(obj)) { total++; } } return total; } }
内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Cow { private double weight; public Cow () {} public Cow (double weight) { this .weight = weight; } private class CowLeg { private double length; private String color; public CowLeg () {} public CowLeg (double length, String color) { this .length = length; this .color = color; } public void info () { System.out.println(this .color + this .length); System.out.println(Cow.this .weight); } } public static void main (String[] args) { } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class LocalInnerClass { public static void main (String[] args) { class InnerBase { int a; } class InnerSub extends InnerBase { int b; } var is = new InnerSub(); is.a = 5 ; is.b = 8 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 interface Product { double getPrice () ; String getName () ; } public class AnonymousTest { public void test (Product p) { System.out.println(p.getName() + p.getPrice()); } public static void main (String[] args) { var ta = new AnonymousTest(); ta.test(new Product() { @Override public double getPrice () { return 567.8 ; } @Override public String getName () { return "ddsd" ; } }); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 abstract class Device { private String name; public abstract double getPrice () ; public Device () {} public Device (String name) { this .name = name; } } public class AnonymousInner { public void test (Device d) { System.out.println(d.getPrice()); } public static void main (String[] args) { var ai = new AnonymousInner(); ai.test(new Device("theName" ) { @Override public double getPrice () { return 67.8 ; } }); var d = new Device() { { System.out.println("我是初始化代码块" ); } @Override public double getPrice () { return 56.2 ; } } ai.test(d); } }
lambda表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public interface Command { void process (int element) ; } public class ProcessArray { public void process (int [] target, Command cmd) { for (var t : target) { cmd.process(t); } } } public class CommandTest { public static void main (String[] args) { var pa = new ProcessArray(); int [] target = {3 , -4 , 6 , 4 }; pa.process(target, element -> System.out.println("数组的平方:" + element * element)); } }
final修饰符
可修饰类、变量(类变量、实例变量、局部变量、形参)、方法。
final修饰基本类型变量和引用类型变量的区别:
修饰基本类型变量,不可重新赋值;但对于引用类型变量,final仅保证这个引用类型变量所引用的地址不变,但对象是完全可以改变的。
final类型变量功能类似“宏替换”
关于不可变类:
java提供的8个包装类和java.lang.String类都是不可变类。当创建它们的实例后,其实例的实例变量不可变,java没有提供它们可供修改的方法。
自己创建不可变类,可参考“疯狂java讲义” P188 重点是类中自己使用新的引用对象。
比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CommandTest { public static int findMax (Comparable[] arr) { int maxIndex = 0 ; for (int i = 0 ; i < arr.length; ++i) { if (arr[i].compareTo(arr[maxIndex]) > 0 ) { maxIndex = i; } } return maxIndex; } public static void main (String[] args) { String[] str1 = {"Joe" , "Bob" , "Bill" , "Zeke" }; System.out.println(findMax(str1)); } }
泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Apple <T > { private T info; public Apple () {} public Apple (T info) { this .info = info; } } public class CommandTest { public static void main (String[] args) { Apple<String> a1 = new Apple<>("苹果" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class A extends Apple <T > { } public class SubA extends Apple <String > { @Override public String getInfo () { return "子类" + super .getInfo(); } }
1 2 3 4 public class SubA extends Apple { }
List<String>与List<Integer>虽不同泛型,但仍是同一个class类。因此,在静态方法、静态初始化块、静态变量(都是类相关)它们的声明和初始化中,不允许使用泛型形参。
1 2 3 4 5 6 7 8 9 public class R <T > { static T info; T age; public void foo (T msg) {} public static void bar (T msg) {} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class CommandTest { public static void test (List<Object> c) { for (Object o : c) { System.out.println(o); } } public static void main (String[] args) { List<String> strList = new ArrayList<>(); Integer[] ia = new Integer[5 ]; Number[] na = ia; na[0 ] = 0.5 ; List<String> iList = new ArrayList<>(); } }
泛型方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class CommandTest { static <T> void fromArrayToCollection (T[] a, Collection<T> c) { for (T o : c) { c.add(o); } } static <T> void test1 (Collection<T> from, Collection<T> to) { for (T ele : from) { to.add(ele); } } static <T> void test2 (Collection<? extends T> from, Collection<T> to) { for (T ele : from) { to.add(ele); } } public static void main (String[] args) { var oa = new Object[100 ]; Collection<Object> co = new ArrayList<>(); fromArrayToCollection(oa, co); List<Object> as = new ArrayList<>(); List<String> ao = new ArrayList<>(); test2(ao, as); } }
使用泛型方法还是使用通配符,随个人喜好 。
泛型构造器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Foo <E > { public E param1; public <T> Foo(E param1, T param2) { this .param1 = param1; System.out.println(param2); } } public class GenericConstructor { public static void main (String[] args) { Foo<String> mc1 = new Foo<>("abccc" , 5 ); Foo<String> mc2 = new <Integer> Foo<String>("sadsad" , 10 ); } }
extends(继承) implements(实现)
一个类只能extends继承一个父类,但可以implements实现多个接口,以此来代替C++中多继承的概念。
一个接口可同时extends多个接口,但不能implements实现任何接口。参考链接
普通for循环与增强型for循环(即foreach,即 for (Integer i : arrayList))
普通for循环获取元素下标,通过下标遍历元素;增强型for循环是java的语法糖,遍历数组时编译后就是普通的fori循环,遍历List集合时编译后是通过迭代器实现遍历。迭代器遍历链表快,遍历数组慢。
所以遍历LinkedList时需选用增强型for循环。
遍历时修改集合对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public static void main (String[] args) { ArrayList<Integer> arrayList = new ArrayList<>(); arrayList.add(1 ); arrayList.add(2 ); arrayList.add(2 ); arrayList.add(4 ); arrayList.add(5 ); for (int i = 0 ; i < arrayList.size(); ++i) { if (ArrayList.get(i) == 2 ) { arrayList.remove(i); i--; } } System.out.println(arrayList); for (Integer i : arrayList) { if (i == 2 ) { arrayList.remove(i); arrayList.add(9 ); arrayList.set(1 , 8 ); } } System.out.println(arrayList); ListIterator<Integer> listIterator = arrayList.listIterator(); while (listIterator.hasNext()) { Integer i = (Integer) listIterator.next(); if (i == 2 ) { arrayList.add(6 ); listIterator.remove(); listIterator.add(6 ); listIterator.set(8 ); } } System.out.println(arrayList); }
参考链接
List两种实现
ArrayList:
可增长的数组实现。有点在于get、set的调用花费常数时间。缺点是插入和删除代价高,尤其在首端。
LinkedList:
推荐使用LinkedList<Integer> list2 = new LinkedList<>(); 用List<Integer> list2 = new LinkedList<>();好多方法都调不到。
双向链表,优点是在已知位置时插入删除快。缺点是不易索引,get调用花费大。
LinkedList常用内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public static void main (String[] args) { LinkedList<String> linkedList = new LinkedList<>(); linkedList.add("1" ); linkedList.add("2" ); linkedList.add("3" ); linkedList.add("4" ); linkedList.getFirst(); linkedList.getLast(); linkedList.addFirst("0" ); linkedList.addLast("5" ); linkedList.removeFirst(); linkedList.removeLast(); linkedList.clear(); linkedList.subList(2 , 5 ).clear(); linkedList.remove("2" ); linkedList.remove(2 ); ArrayList<String> arrayList = new ArrayList<>(linkedList); String[] my = linkedList.toArray(new String[0 ]); String[] my2 = linkedList.toArray(new String[linkedList.size()]); linkedList.indexOf("2" ); linkedList.lastIndexOf("2" ); linkedList.set(3 , "Replace" ); linkedList.contains("2" ); System.out.println(linkedList); }
参考链接
树
没有儿子的节点称为树叶; 具有相同父亲的节点称为兄弟。
满二叉树、完全二叉树
(TreeNode)要自己实现
前序遍历、中序遍历、后序遍历(取决于何时访问根节点)参考链接
二叉搜索树: (没要求完全二叉树)
所有关键字唯一
左子树所有值 < 根节点值 < 右子树值
左右子树分别都是二叉搜索树
平衡搜索树: 树高O(log n)
AVL树(平衡二叉搜索树)、红黑树、B+树 AVL树和红黑树适合内存存储应用,B+树适合磁盘存储应用。
AVL树和红黑树使用“旋转”保持平衡。AVL树每次插入操作最多需要一次旋转,每次删除操作最多需要O(log n)次旋转。红黑树插入和删除操作都只需一次旋转。一次旋转耗时O(1)。
AVL树:左子树和右子树都是AVL树;左右子树高度差小于等于1;旋转见代码
B+树:一次硬盘访问的时间,足够处理器执行40万条指令。因此我们往往愿意通过大量的指令计算来节省一次硬盘的访问。
M阶B+树具有如下性质:
数据项存储在树叶上。
非叶节点存储关键字,以指示搜索的方向;关键字i代表子树i+1的最小关键字。
除树根外,所有非树叶节点的儿子数在[M/2, M]之间。
所有树叶都在相同的深度上,并有[L/2, L]个数据项,L看情况来定。
新插入数据时,可能出现的情况是:
想要插入数据项的那片树叶已经插满了,那就分裂一次上面的父节点;
如果分裂上面的父节点时,父节点也超数了,那就继续向上分裂。
B+树与B树的区别:
B树每个节点都存储数据,B+树只有叶子节点存储数据,非叶节点起索引作用。因此B+树更扁,I/O次数更少。
B+树所有叶子节点使用链表相连,便于区间查找和遍历。
Set、Map:
ArrayList和LinkedList查找效率都很低(非ArrayList指定索引查找元素的情况,而是直接给定某个元素的值,查看该元素详情的情况)。Collections API提供了Set和Map。
Set接口为不允许重复的Collection。保持有序状态的Set实现是TreeSet,底层红黑树。
Map同理于Set,TreeMap底层同样红黑树。
堆:
堆是完全二叉树
大根树:每个节点的值都大于等于其子节点
大根堆:大根树 + 完全二叉树
大根堆插入一个新元素,即在尾部插入一个新元素,执行一趟起泡操作即可维护。
大根堆删除一个元素,即删除根节点元素,将尾部元素删除并放置在根节点位置,重新组织维护成大根堆。
PriorityQueue:
Java的优先级队列默认是小顶堆
不允许放入null元素
底层实现为数组,因为通过公式可计算出父子节点的对应位置,所以底层可用数组实现(迭代器遍历出来的结果顺序,就是下面数组的顺序)
常用方法:
add()、offer() 插入元素 前者失败抛异常,后者返false
element()、peek() 获取但并不删除首元素 前者失败抛异常,后者返null
remove()、poll() 获取并删除首元素 前者失败抛异常,后者返null
remove(Object o) 删除o元素
iterator() 迭代器
具体的方法实现:参考链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class CommandTest { public static final Comparator<Integer> cmp = new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } } public static void main (String[] args) { PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(cmp); priorityQueue.add(3 ); priorityQueue.add(5 ); priorityQueue.add(10 ); priorityQueue.add(7 ); priorityQueue.add(9 ); priorityQueue.add(15 ); priorityQueue.add(11 ); priorityQueue.add(13 ); priorityQueue.add(20 ); priorityQueue.add(12 ); while (!priorityQueue.isEmpty()) { System.out.println(priorityQueue.poll()); } } }
Java常见容器
参考链接
iterator、ListIterator
最短路径算法、广度优先遍历、深度优先遍历
…