数据类型 & 运算符
float型字符必须在变量最后面加上F或f
高精度可以用java.math.BigDecimal
(没讲)
数组
定义 - double[] marks
,double [5]marks
, marks = new double[5]
, marks = new double[]{1, 2, 3, 4, 5}
public static void arraycopy(Object src, int srcPos, Object dest, int destPos,int length)
冒泡排序
java.util.Arrays
- static int binarySearch (Object[] a, Object key)
, static void sort(Object[] a, int fromIndex, int toIndex)
, static boolean equals(Object[] a, Object[] b)
, static void fill (int[] a, int fromIndex, int toIndex, int val)
二维数组 - int[][]matrix = new int[2][];
字符串类
==
比较的是对象是否相同,equals
比较的是内容是否相同,equalsIgnoreCase
不区分大小写比较内容是否相同
String str = "string"
与String str = new String("string")
- 前者的意思是str指向值为string
的String对象,如果变量池中有就直接指向,没有就创建。后者就是直接创建一个新的String对象并指向它
相关使用,还有compareTo
和compareToIgnoreCase
1 2 3 4 5 6 7 8 char []chars1 = {'A' ,'B' ,'C' };char []chars2 = {'中' ,'国' ,'π' ,'α' ,'M' ,'N' };var s1 = new String (chars1);var s2 = new String (chars2, 0 , 4 ); System.out.println("s1 = " + s1); System.out.println("s2 = " + s2);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var s = "Java is cool" ; System.out.println(s.length()); System.out.println(s.substring(5 ,7 )); System.out.println(s.substring(8 )); System.out.println(s.toUpperCase()); System.out.println(s.toLowerCase()); var s1 = "编写一次," ;var s2 = "到处运行。" ; s1 = s1.concat(s2); System.out.println(s1); System.out.println(s.replace('a' ,'A' )); System.out.println(s.isEmpty());
1 2 3 4 5 6 7 8 var s = new String ("This is a Java string." ); System.out.println(s.length()); System.out.println(s.indexOf('a' )); System.out.println(s.lastIndexOf('a' , 12 )); System.out.println(s.indexOf("is" )); System.out.println(s.lastIndexOf("is" )); System.out.println(s.indexOf("my" ));
格式符
含义
%d
结果被格式化成十进制整数
%f
结果被格式化成十进制浮点数
%e
结果以科学计数法格式输出
%s
结果以字符串输出
%b
结果以布尔值(true或false)形式输出
%c
结果以Unicode字符输出
%n
换行格式符,它不与参数数对应。与\n含义相同,但%n是跨平台的
StringBuilder
& StringBuffer
,后者是线程安全的。不需要线程同步建议使用前者
1 2 3 4 5 6 7 8 9 10 var ss = new StringBuilder ("Hello" ); System.out.println(ss.length()); System.out.println(ss.capacity()); ss.append("Java" ); System.out.println(ss); System.out.println(ss.insert(5 , ", " )); System.out.println(ss.replace(6 , 10 , "World!" )); System.out.println(ss.reverse());
面向对象特征
1 2 3 4 5 6 7 8 9 10 11 12 import static java.lang.Math.*;import static java.lang.System.*;public class ImportStaticDemo { public static void main (String[] args) { var d = random(); var pi = PI; out.println("d = " + d); out.println("pi = " + pi); } }
super
为子类调用父类的接口,在子类构造方法中若没有使用super调用父类的构造方法,则编译器在子类的构造方法的第一句自动加上super(),即调用父类无参数的构造方法。
不能既调用this,又调用super。
final
关键字说明不能被@Override
之类的了
abstract
抽象类,只能当父类,可以定义抽象方法
子类对象可以自动转换为父类对象。可以将子类型的引用赋值给父类型的引用。
将父类对象强制转换为子类对象。用“()”运算符。将父类型的引用赋值给子类型的引用。建议先判断是不是
1 2 3 if (a instanceof Dog) { Dog d = (Dog) a; }
注意,父类子类转换的时候,对象的数据并不会随着转换而丢失,依然指向那一块内存,只是类似于被“屏蔽”,无法访问
Java中除static方法和final方法外都是动态绑定。
Jvav核心类库
方法
说明
public boolean equals(Object obj)
比较调用对象的内容是否与参数对象obj相等在类的子类中,使用签名equals(ClassName obj)覆盖equals()方法是一个常见的错误,应该使用equals(Object obj)覆盖equals()方法。
public String toString()
返回对象的字符串表示
public int hashCode()
返回对象的哈希码值
protected Object clone()
创建并返回对象的一个副本
public Class<?> getClass()
返回对象所属的完整类名
protected void finalize()
当对象没有引用时由垃圾回收器调用。该方法已废弃
public void wait() public void wait(long timeout) public void wait(long timeout, int nanos)
使当前线程进入等待状态,直到另一个线程调用notify()或notifyAll()方法
public void notify() public void notifyAll()
通知等待该对象锁的单个线程或所有线程继续执行
方法
说明
static double sin(double x) static double cos(double x) static double tan(double x)
返回角度x的正弦、余弦和正切的值,其中x的单位为弧度
static double asin(double x) static double acos(double x)
返回角度x的反正弦、反余弦的值,其中x的单位为弧度
static double abs(double x)
返回x的绝对值,该方法另有3个重载的版本
static double exp(double x) static double log(double x) static double sqrt(double x) static double pow(double x, double y)
返回e的x次方的值 返回以e为底的自然对数的值 返回x的平方根 返回x的y次方的值
static double max(double x, double y) static double min(double x, double y)
返回x、y的最大值和最小值,另有参数为float、long和int的重载版本
static double random()
返回0.0到1.0之间的随机数(包含0.0但不包含1.0)
static double ceil(double x) static double floor(double x)
返回大于或等于x的最小整数 返回小于或等于x的最大整数
static double rint(double x)
返回与x最接近的整数,如果x到两个整数的距离相等,返回其中的偶数
static int round(float x)
返回(int)Math.floor(x+0.5)
static long round(double x)
返回(long)Math.floor(x+0.5)
static double toDegrees(double angrad) static double toRadians(double angrad)
将弧度转换为角度 将角度转换为弧度
(int)(Math.random() * 10)
返回0到9之间的随机整数
50 + (int)(Math.random() * 51)
返回50到100之间的随机整数
系统类java.lang.System
,是一个final
类
System.out/err.printf/println
, System.in
,后者要结合Scanner
等使用,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.Scanner;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.print("请输入你的名字:" ); String name = scanner.nextLine(); System.out.print("请输入你的年龄:" ); int age = scanner.nextInt(); System.out.println("你好, " + name + ",你今年" + age + "岁。" ); scanner.close(); } }
public static void arraycopy(Object source, int sourcePos,Object destination, int destPos, int length)
public static void exit(int status)
public static long currentTimeMillis()
该方法返回以毫秒为单位的计算机时间。这个值表示自UTC从1970年1月1日以来经过的毫秒数。
public static long nanoTime()
包装类
基本数据类型
对应的包装类
基本数据类型
对应的包装类
boolean
Boolean
int
Integer
char
Character
long
Long
byte
Byte
float
Float
short
Short
double
Double
1 2 3 4 5 6 7 8 public static byte parseByte (String str ):将字符串参数str 转换为byte 类型值。public static short parseShort (String str ) :将字符串参数str 转换为short 型值。public static int parseInt (String str ) :将字符串参数str 转换为int 类型值。public static long parseLong (String str ) :将字符串参数str 转换为long 类型值。public static float parseFloat (String str ) :将字符串参数str 转换为float 类型值。public static double parseDouble (String str ) :将字符串参数str 转换为double 类型值。public static boolean parseBoolean (String str ):将字符串参数str 转换为boolean 类型值。public static String valueOf (double d):下面方法将参数的基本类型double 值转换为字符串。
接口 & 内部类
class A implements AA, BB
接口可以多实现,一个类多个接口
接口内可以放的东西:常量public static final
,抽象方法public abstract
,默认方法 (java 8+) default {kind} func()
,私有方法 (java 9+) private {kind} func()
接口可以多继承接口
内部类编译后将单独生成一个类文件,如上述代码编译后将生成两个类文件:Outer.class和Outer$InnerClass.class。
内部类可以设置访问为private
,那么就只有外部类可以访问了。外部类不能设置为private
匿名内部类常用语回听和GUI监听,方便及时销毁
重写Comparable<T>
接口,需要重写public int compareTo(T other)
,升序(从小到大)是当前对象小于参数对象时,返回负数。可以用Integer.compare(a, b)
来避免溢出等等
异常处理
检查异常,如IOException,SQLException,ClassNotFoundException,必须用try-catch
或throw
处理,否则编译不通过
非检查异常,如NullPointerException,ArrayIndexOutOfBoundsException,IllegalArgumentException,ClassCastException,NumberFormatException,ArithmeticException,不用手动处理也可以通过编译,属于逻辑错误。默认会一直往调用栈上面传,直到有catch,否则就crash
1 2 3 4 5 Throwable ├── Error (一般不处理) └── Exception ├── RuntimeException (非检查异常) └── 其他 Exception (检查异常)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class TryCatchFinallyDemo { public static void main (String[] args) { try { int a = 10 ; int b = 0 ; int c = a / b; System.out.println("结果:" + c); } catch (ArithmeticException e) { System.out.println("发生算术异常:" + e.getMessage()); } finally { System.out.println("无论如何我都会被执行!" ); } System.out.println("程序继续执行" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public void method (Connection conn, ResultSet rs) { try { while (rs.next()) { } } catch (SQLException ex) { } finally { try { if (rs != null ) rs.close(); } catch (SQLException e) {} try { if (conn != null ) conn.close(); } catch (SQLException e) {} } }
断言
当然可以!**断言(assertion)**是 Java 语言中的一种调试工具,用于在程序运行时进行条件判断。如果条件不成立(即为 false
),程序会抛出 AssertionError
,帮助开发者发现逻辑错误。
1. 基本用法
或者带错误信息:
示例
1 2 3 4 5 int x = 5 ;assert x > 0 ; int y = -1 ;assert y >= 0 : "y必须为非负数,但当前值为" + y;
2. 断言的常见场景
检查不应该发生的情况
检查方法的前置条件或后置条件
调试代码时快速定位问题
3. 注意事项
默认情况下,断言是关闭的。
需要通过 JVM 参数 -ea
或 -enableassertions
启用断言。
断言通常不用于处理业务逻辑 ,而是用于开发和测试阶段。
不建议在生产环境下依赖断言做关键逻辑判断。
4. 例子
1 2 3 4 5 6 7 public class AssertDemo { public static void main (String[] args) { int age = -3 ; assert age > 0 : "年龄必须大于0,但当前值为" + age; System.out.println("年龄:" + age); } }
运行时加上 -ea
参数:
如果 age
小于等于 0,会抛出如下错误:
1 Exception in thread "main" java.lang.AssertionError: 年龄必须大于0 ,但当前值为-3
记录,枚举和注解类型
你的问题非常好,下面我来分别介绍一下记录(record) 、**枚举(enum)和 注解类型(annotation)**在 Java 中的含义和用法。
1. 记录(record)
record 是 Java 14 引入的一种新类型(正式版自 Java 16),用于简化只用于保存数据的类(也叫数据类、值类)的编写。
作用
自动为你生成构造器、getter、equals()
、hashCode()
和 toString()
方法。
适合用来封装只包含数据的对象(不可变对象)。
示例
1 2 3 4 5 6 public record Person (String name, int age) { }Person p = new Person ("Tom" , 18 ); System.out.println(p.name()); System.out.println(p.age()); System.out.println(p);
2. 枚举(enum)
enum (枚举)用于定义一组有限的常量。比如一周的七天、性别、状态等。
作用
表示固定数量的常量。
可以为每个枚举常量定义属性和方法。
示例
1 2 3 4 5 6 7 8 9 public enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }Day today = Day.MONDAY;switch (today) { case MONDAY -> System.out.println("今天是星期一" ); default -> System.out.println("不是星期一" ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public enum Color { RED("红色" ), GREEN("绿色" ), BLUE("蓝色" ); private final String chinese; Color(String chinese) { this .chinese = chinese; } public String getChinese () { return chinese; } }Color color = Color.BLUE; System.out.println(color.getChinese());
3. 注解类型(annotation)
**注解(annotation)**是 Java 5 引入的特殊类型,用于为代码添加元数据。常见的注解有 @Override
、@Deprecated
、@SuppressWarnings
等。
作用
给编译器、工具或框架提供信息。
可以自定义注解类型,用于标记类、方法、字段等。
示例
常用注解
1 2 3 4 @Override public String toString () { return "Hello" ; }
自定义注解
1 2 3 4 5 6 7 8 public @interface MyAnnotation { String value () ; int count () default 1 ; }@MyAnnotation(value = "test", count = 3) public void testMethod () {}
还有的常见注解
@Deprecated
@SuppressWarnings
@interface
泛型
也是public class Hi<T>
这样的
通配符,比如List<?>
表示可以接受任何类型的列表
可以使用有限的通配符,比如List<? extends Number>
, List <? extends Integer>
,前者指定上界,后者指定下界
遍历器的使用方法:
1 2 3 4 5 6 7 8 List<String> myList = List.of("北京" ,"上海" ,"广州" ,"深圳" ) ; ListIterator<String> iterator = myList.listIterator(); while (iterator.hasNext()){ iterator.next(); }while (iterator.hasPrevious()){ System.out.print(iterator.previous() + " " ); }
泛型由于涉及到类型擦除,不能做以下操作:使用instanceof
,创建泛型示例,创建泛型数组,捕获泛型类型的异常,做静态变量的类型;此外,在类型转换的时候会出现“非检查警告”。上面的操作都是需要具体的类型
List
在 Java 中,List
是一个非常常用的集合接口,属于 java.util
包。它有多个常用实现类,比如 ArrayList
、LinkedList
等。下面给你介绍一下 List
的基本用法,包括常见的操作和示例代码。
1. 导包
1 2 import java.util.List;import java.util.ArrayList;
2. 创建 List 对象
1 List<String> list = new ArrayList <>();
3. 添加元素
1 2 3 list.add("Apple" ); list.add("Banana" ); list.add("Orange" );
4. 获取元素
1 String fruit = list.get(1 );
5. 遍历 List
方式一:for-each 循环
1 2 3 for (String item : list) { System.out.println(item); }
方式二:普通 for 循环
1 2 3 for (int i = 0 ; i < list.size(); i++) { System.out.println(list.get(i)); }
方式三:Java 8 Lambda 表达式
1 list.forEach(item -> System.out.println(item));
6. 修改元素
1 list.set(1 , "Blueberry" );
7. 删除元素
1 2 list.remove(0 ); list.remove("Orange" );
8. 判断是否包含某个元素
1 boolean hasApple = list.contains("Apple" );
9. 获取 List 的长度
10. 清空 List
11. 判断是否为空
1 boolean isEmpty = list.isEmpty();
12. 示例代码
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 import java.util.ArrayList;import java.util.List;public class ListDemo { public static void main (String[] args) { List<String> list = new ArrayList <>(); list.add("Apple" ); list.add("Banana" ); list.add("Orange" ); System.out.println("List内容:" + list); for (String item : list) { System.out.println(item); } list.set(1 , "Blueberry" ); System.out.println("修改后:" + list); list.remove("Apple" ); System.out.println("删除后:" + list); System.out.println("是否包含Orange? " + list.contains("Orange" )); } }
13. 使用迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class IteratorDemo { public static void main (String[] args) { List<String> list = new ArrayList <>(); list.add("Apple" ); list.add("Banana" ); list.add("Orange" ); Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); System.out.println(item); if (item.equals("Banana" )) { it.remove(); } } System.out.println("删除后的List: " + list); } }
14. 数组转List
1 2 3 String[] str = {"one" ,"two" ,"three" ,"four" }; List<String> list = Arrays.asList(str); System.out.println(list);
Set & TreeSet
一、Set(以 HashSet 为例)
Set
是接口,通常使用它的实现类,如 HashSet
。
特点:
元素无序(存储顺序和取出顺序不一定相同)。
元素不可重复。
查找、添加、删除速度快。
常用操作示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.Set;import java.util.HashSet;public class HashSetDemo { public static void main (String[] args) { Set<String> set = new HashSet <>(); set.add("Apple" ); set.add("Banana" ); set.add("Orange" ); set.add("Apple" ); System.out.println(set); for (String item : set) { System.out.println(item); } } }
二、TreeSet
TreeSet
是 Set
的一个实现类,底层用红黑树 实现。
特点:
元素自动排序(默认升序,也可以自定义排序规则)。
元素不可重复。
查找、添加、删除速度比 HashSet
慢一些。
常用操作示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.Set;import java.util.TreeSet;public class TreeSetDemo { public static void main (String[] args) { Set<String> set = new TreeSet <>(); set.add("Banana" ); set.add("Apple" ); set.add("Orange" ); set.add("Apple" ); System.out.println(set); for (String item : set) { System.out.println(item); } } }
三、两者主要区别
特点
HashSet(Set)
TreeSet
底层结构
哈希表(Hash表)
红黑树(自平衡二叉树)
元素顺序
无序
自动排序(默认升序)
是否允许重复
否
否
是否允许null
允许一个null
不允许null
速度
快
较慢
自定义排序
不支持
支持
四、TreeSet自定义排序(进阶)
如果要按照自定义规则排序,可以传入 Comparator
:
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.util.TreeSet;import java.util.Comparator;public class CustomSortDemo { public static void main (String[] args) { TreeSet<String> set = new TreeSet <>(Comparator.reverseOrder()); set.add("Banana" ); set.add("Apple" ); set.add("Orange" ); System.out.println(set); } }
五、自己实现一个Comparator
1 2 3 4 5 6 Comparator<Integer> cmp = new Comparator <Integer>() { @Override public int compare (Integer o1, Integer o2) { return o1 - o2; } };
队列
1. Queue(接口)
位置 :顶层接口
作用 :定义了队列的基本操作(如添加、移除、查看元素),是所有队列的父接口。
常用方法 :
offer(E e)
:入队,成功返回 true
poll()
:出队,返回队头元素并移除
peek()
:查看队头元素但不移除
2. Deque(接口)
全称 :Double Ended Queue(双端队列)
作用 :允许在队列的两端插入和删除元素(既可以当队列用,也可以当栈用)。
常用方法 :
offerFirst(E e)
/ offerLast(E e)
:分别从队头/队尾插入
pollFirst()
/ pollLast()
:分别从队头/队尾移除元素
peekFirst()
/ peekLast()
:分别查看队头/队尾元素
3. PriorityQueue(类)
作用 :优先队列,元素按照优先级自动排序(不是先进先出,而是最小/最大优先)。
特点 :
默认是小顶堆 (最小的元素优先出队)
可以自定义排序规则(通过 Comparator)
常用场景 :任务调度、Top K问题、堆排序等
示例:
1 2 3 4 5 PriorityQueue<Integer> pq = new PriorityQueue <>(); pq.offer(5 ); pq.offer(1 ); pq.offer(3 ); System.out.println(pq.poll());
4. ArrayDeque(类)
作用 :基于数组实现的高效双端队列(Deque接口的实现类)
特点 :
不允许null元素
既可以当队列用,也可以当栈用
性能优于LinkedList
常用场景 :队列、栈、双端队列
示例:
1 2 3 4 5 ArrayDeque<String> deque = new ArrayDeque <>(); deque.offerLast("A" ); deque.offerFirst("B" ); System.out.println(deque.pollLast()); System.out.println(deque.pollFirst());
5. LinkedList(类)
作用 :既实现了队列(Queue、Deque接口),又实现了链表(List接口)
特点 :
允许null元素
支持双向链表操作(增删查改都可以)
既可以当队列用,也可以当栈、链表用
常用场景 :队列、双端队列、链表操作
示例:
1 2 3 4 5 6 LinkedList<Integer> list = new LinkedList <>(); list.offer(1 ); list.offer(2 ); System.out.println(list.poll()); list.addFirst(0 ); System.out.println(list);
总结表
名称
类型
主要作用
特点
Queue
接口
队列的标准操作
先进先出
Deque
接口
双端队列
两端都能操作
PriorityQueue
类
优先队列
按优先级排序
ArrayDeque
类
高效双端队列
不允许 null,性能好
LinkedList
类
链表/队列/双端队列
允许 null,多功能
键值对
好的,这张图展示了 Java 中常用的几种 Map 相关的类和接口的继承关系。下面我来一一讲解:
1. Map(接口)
位置 :最顶层的接口
作用 :定义了键值对(key-value)映射的基本操作,是所有 Map 实现类的父接口。
常用方法 :
put(K key, V value)
:添加键值对
get(Object key)
:根据 key 获取 value
remove(Object key)
:移除指定 key 的映射
containsKey(Object key)
:是否包含某个 key
containsValue(Object value)
:是否包含某个 value
keySet()
、values()
、entrySet()
clear()
:删除所有的键值对
2. HashMap(类)
作用 :最常用的 Map 实现类,基于哈希表实现。
特点 :
允许 null 作为 key 和 value
线程不安全 (多线程环境下需手动加锁)
无序 :存储顺序与插入顺序无关
查询和插入的时间复杂度一般为 O(1)
常用场景 :大多数情况下的键值对存储
示例代码:
1 2 3 4 Map<String, Integer> map = new HashMap <>(); map.put("apple" , 1 ); map.put("banana" , 2 ); System.out.println(map.get("apple" ));
3. Hashtable(类)
作用 :早期的 Map 实现类,也基于哈希表。
特点 :
不允许 null 作为 key 或 value
线程安全 :内部方法都加了 synchronized,效率较低
无序
现在一般不推荐使用,建议用 ConcurrentHashMap
替代
常用场景 :老项目或对线程安全有要求但不关心性能的场景
示例代码:
1 2 3 Map<String, Integer> table = new Hashtable <>(); table.put("apple" , 1 );
4. TreeMap(类)
作用 :基于红黑树实现的有序 Map。
特点 :
有序 :按照 key 的自然顺序(或构造时传入的 Comparator)排序
不允许 null 作为 key(但 value 可以为 null)
查询和插入的时间复杂度为 O(logN)
常用场景 :需要对 key 排序的场景,比如区间查找、范围查询等
示例代码:
1 2 3 4 Map<String, Integer> treeMap = new TreeMap <>(); treeMap.put("banana" , 2 ); treeMap.put("apple" , 1 ); System.out.println(treeMap);
5. 自定义TreeMap的Comparator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Comparator<String> cmp = new Comparator <String>() { @Override public int compare (String o1, String o2) { return Integer.compare(o1.length(), o2.length()); } }; TreeMap<String, Integer> treeMap = new TreeMap <>(cmp); treeMap.put("apple" , 1 ); treeMap.put("banana" , 2 ); treeMap.put("kiwi" , 3 ); treeMap.put("pear" , 4 ); System.out.println(treeMap);
总结对比表
名称
是否有序
是否线程安全
是否允许null
底层结构
适用场景
HashMap
否
否
允许
哈希表
普通键值对存储
Hashtable
否
是
不允许
哈希表
老项目、简单线程安全
TreeMap
是
否
key不允许
红黑树
需要排序的键值对存储
Collection
1. Collection 是什么?
Collection 是接口,不是类!
它位于 java.util
包中,是所有单值集合(如 List、Set、Queue 等)的顶层父接口。
它定义了集合的基本操作 ,比如增、删、查、遍历等。
2. Collection 与 Map 的区别
Collection
代表“一组元素”,但不包括 Map (Map 是 key-value 对,不是单纯的元素集合)。
Map
不是 Collection
的子接口,两者是并列的。
3. Collection 的常用子接口
List :有序集合,允许重复元素。例如:ArrayList
、LinkedList
Set :无序集合,不允许重复。例如:HashSet
、TreeSet
Queue :队列,按特定顺序处理元素。例如:LinkedList
(也实现了 Queue)、PriorityQueue
4. 常用方法
Collection 接口定义了常用的集合操作方法,例如:
add(E e)
:添加元素
remove(Object o)
:移除元素
size()
:元素个数
isEmpty()
:是否为空
contains(Object o)
:是否包含某元素
iterator()
:返回迭代器
clear()
:清空集合
5. 示例代码
1 2 3 4 5 6 7 Collection<String> coll = new ArrayList <>(); coll.add("apple" ); coll.add("banana" ); System.out.println(coll.size()); for (String s : coll) { System.out.println(s); }
6. 结构图(简化版)
1 2 3 Collection / | \ List Set Queue
具体实现类如 ArrayList
, HashSet
, LinkedList
等都在这些分支下。
总结
Collection
是接口,不是类。
它是 Java 集合框架的基础,定义了操作集合的通用方法。
常见的集合类(如 List、Set、Queue)都继承自 Collection。
二进制IO流
先来看一眼类图
再来看一些样例
1 2 3 4 5 6 7 8 9 10 11 12 13 public static void main (String[] args) { var outputFile = new File ("output.dat" ); try (var out = new FileOutputStream (outputFile);) { for (var i = 0 ; i < 10 ; i++) { int x = (int ) (Math.random() * 90 ) + 10 ; out.write(x); } out.flush(); System.out.println("已向文件写入10个两位数!" ); } catch (IOException e) { System.out.println(e.toString()); } }
1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) { var inputFile = new File ("output.dat" ); try (var in = new FileInputStream (inputFile);) { int c = in.read(); while (c != -1 ){ System.out.print(c + " " ); c = in.read(); } }catch (IOException e){ System.out.println(e.toString()); } }
1 2 3 4 5 6 7 8 9 10 11 try ( FileOutputStream output = new FileOutputStream ("data.dat" ); DataOutputStream dataOutStream = new DataOutputStream ( new BufferedOutputStream (output)); ){ dataOutStream.writeDouble(123.456 ); dataOutStream.writeInt(100 ); dataOutStream.writeUTF("Java语言" ); }catch (IOException e){ e.printStackTrace(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 try ( FileInputStream input = new FileInputStream ("data.dat" ); DataInputStream dataInStream = new DataInputStream ( new BufferedInputStream (input)); ){ while (dataInStream.available()>0 ){ double d = dataInStream.readDouble(); int i = dataInStream.readInt(); String s = dataInStream.readUTF(); System.out.println("d = " +d); System.out.println("i = " +i); System.out.println("s = " +s); } }catch (IOException e){ e.printStackTrace(); }
文本IO流
还是先看俩类图
再看俩示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 File inputFile = new File ("input.txt" );File outputFile = new File ("output.txt" );try ( FileReader in = new FileReader (inputFile); FileWriter out = new FileWriter (outputFile); ){ int c = in.read(); while (c !=-1 ) { out.write(c); c = in.read(); } }catch (IOException e) { System.out.println(e.toString()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 String fileName = "article.txt" ;int sum = 0 ;try ( FileReader inFile = new FileReader (fileName); BufferedReader reader = new BufferedReader (inFile); ){ String aLine = reader.readLine(); while (aLine != null ){ String [] words = aLine.split("[ ,.]" ); sum = sum + words.length; aLine = reader.readLine(); } }catch (IOException e) { System.out.println(e.toString()); } System.out.println("单词数量为:" + sum);
还可以用PrintWriter
,做到和System.out
类似的体验
1 2 3 4 5 6 7 8 9 var fileName = "number.txt" ;var out = new FileWriter (new File (fileName));var pw = new PrintWriter (out,true );for (var i = 0 ; i < 10 ; i++){ var num = (int )(Math.random()*101 )+100 ; pw.println(num); } pw.close();
1 2 3 4 5 6 7 8 9 var in = new FileReader (new File (fileName));var reader = new BufferedReader (in);var aLine = reader.readLine();while (aLine != null ){ System.out.print(aLine + " " ); aLine = reader.readLine(); } reader.close();
函数式编程 & 流
Lambda表达式 - (String a, String b) -> {return a.length() - b.length();}
或(a, b) -> {return a.length() - b.length();}
Java Stream API 的操作大致可以分为中间操作 和终结操作 两大类,每一类下又有多种常见的方法。下面为你详细分类和说明:
特点:
返回新的 Stream
可以链式调用
只有遇到终结操作时才会真正执行(惰性求值)
常见中间操作
方法
作用说明
示例代码
filter
过滤元素
stream.filter(x -> x>0)
map
元素转换(映射)
stream.map(x -> x*2)
flatMap
扁平化映射(如把List<List>变成List)
stream.flatMap(List::stream)
distinct
去重
stream.distinct()
sorted
排序(可自定义 Comparator)
stream.sorted()
peek
对每个元素执行操作(主要用于调试)
stream.peek(System.out::println)
limit
截取前N个
stream.limit(5)
skip
跳过前N个
stream.skip(2)
2. 终结操作(Terminal Operations)
特点:
触发整个 Stream 的计算
结果不是 Stream,而是具体的值、集合或副作用
常见终结操作
方法
作用说明
示例代码
forEach
遍历每个元素(有副作用)
stream.forEach(System.out::println)
collect
收集结果到集合、字符串等
stream.collect(Collectors.toList())
reduce
归约操作(如求和、最大值等)
stream.reduce(0, Integer::sum)
count
统计元素个数
stream.count()
anyMatch
是否存在某个元素满足条件
stream.anyMatch(x -> x>0)
allMatch
是否所有元素都满足条件
stream.allMatch(x -> x>0)
noneMatch
是否所有元素都不满足条件
stream.noneMatch(x -> x>0)
findFirst
返回第一个元素(Optional)
stream.findFirst()
findAny
返回任意一个元素(Optional,常用于并行流)
stream.findAny()
min
/max
求最小/最大值
stream.min(...)
stream.max(...)
3. 分类总结
分类
常用方法
中间操作
filter、map、flatMap、distinct、sorted、peek、limit、skip
终结操作
forEach、collect、reduce、count、anyMatch、allMatch、noneMatch、findFirst、findAny、min、max
4. 补充说明
中间操作 可以有多个,链式连接。
终结操作 只能有一个,执行后流关闭,不能再操作。
流操作是惰性执行 ,只有遇到终结操作才会真正开始处理数据。
5. 示例代码
1 2 3 4 5 6 7 8 9 List<String> names = Arrays.asList("Tom" , "Jerry" , "Spike" , "Tom" ); List<String> result = names.stream() .filter(name -> name.length() > 3 ) .distinct() .sorted() .collect(Collectors.toList()); System.out.println(result);
并发
好嘛,准gopher来试试jvav的并发好不好用了(
Runnable
接口 - 可以载入这个接口来实现多进程,这个接口里面只有一个public void run()
方法需要重写
Thread
类 - 也可以集成这个类来实现多进程,然后直接用类里面的start()
方法就可以启动了。也是需要重写里面的public void run()
方法。由于jvav的单继承特性,这种方法会占用唯一的一个父类
Thread
类中不推荐使用的方法 - stop()
, suspend()
, resume()
原子操作
- JVM一步就能完成的操作,但很多操作不是原子操作,比如自加和自减。非原子操作就要加锁啦
利用同步synchonized
来完成加锁操作。在需要加锁的方法加上synchronized
关键字,然后在调用的时候使用synchronized (object){}
来访问。其中,object
是钥匙,可以是任何一个对象,但是同一个钥匙只能在同一时间被一个对象使用。
可以使用static synchronized
关键词来锁定方法所在的整个对象。