编程语言分类:
Java是一种面向对象、静态类型、编译执行有VM/GC和运行时、跨平台的高级语言(机器语言→汇编语言→高级语言)。
JRE = JVM + 核心类库。JRE(Java运行环境),JVM(Java虚拟机,真正运行Java程序的地方),核心类库(Java已经写好的程序,供程序员调用)。
JDK = JRE + 开发工具。JDK(Java开发工具包),开发工具(java、javac等)。
官网下载:https://www.oracle.com/cn/java/technologies/downloads/,为了便于管理,建议采用Compressed Archive版本。
长期支持版 (Long-Term Support, LTS):
配置Path环境变量:右键「此电脑」→「属性」→「高级系统设置」→「环境变量」→「系统变量」→「新建」,变量名:JAVA_HOME,变量值:填写JDK安装路径,如:C:\dev\java\jdk-21.0.4。
双击系统变量下的Path环境变量,新建%JAVA_HOME%\bin并上移到第一位,最后点击确定即可。
打开CMD窗口,输入:java -version,测试JDK是否安装成功。
业内大多数程序员都在遵守阿里巴巴的命名规则:《阿里巴巴Java开发手册(终极版)》。
IDEA全称IntelliJ IDEA,是用于Java语言开发的集成环境,是业界公认的目前用于Java程序开发最好的工具。
IntelliJ IDEA官网:https://www.jetbrains.com/idea/download/
IntelliJ IDEA正版专属激活码领取(永久更新): JETBRA.IN CHECKER | IPFS:https://3.jetbra.in/
project中可以创建多个module,module中可以创建多个package,package中可以创建多个class。
字面量:数据在程序中的书写格式。
就是给类,方法,变量等起的名字。
标识符命名规则,硬性要求:
软性建议:
基本数据类型,4大类8种:
// 默认是int类型,字面量后面加 L/l 变成long类型 long lg = 100L; // 默认是double类型,字面量后面加 F/f 变成float类型 float f = 3.14F;引用数据类型,String、数组。
public class HelloWorld { public static void main(String[] args) { // 得到一个键盘扫描器对象 Scanner sc = new Scanner(System.in); // 调用sc,接收键盘输入数据 System.out.println("姓名:"); String name = sc.next(); System.out.println("年龄:"); int age = sc.nextInt(); System.out.println(name + age + "岁"); } }Scanner键盘录入字符串:
switch 注意事项:
for循环中控制循环的变量只能在循环中使用,while循环中控制循环的变量在循环后还可以继续使用。
public class HelloWorld { public static void main(String[] args) { System.out.println(createCode(4)); }
public static String createCode(int n) { // 创建Random对象,用于生成随机数 Random r = new Random(); // 每位随机字符 String code = ""; for (int i = 1; i <= n; i++) { int type = r.nextInt(3); switch (type) { case 0: // 随机一个数字字符 0-9 code += r.nextInt(10); break; case 1: // 随机一个大写字符 A 65 Z 65+25 (0-25)+65 char ch1 = (char) (r.nextInt(26) + 65); code += ch1; break; case 2: // 随机一个小写字符 a 97 z 97+25 (0-25)+97 char ch2 = (char) (r.nextInt(26) + 97); code += ch2; break; } } return code; }
}
Java为了便于虚拟机执行Java程序,将虚拟机内存划分为:
this关键字,就是一个变量,用在方法中,可以拿到当前类的对象,即方法调用者的地址值。
构造器其实是一种特殊的方法,但这个方法没有返回值类型,方法名必须和类名相同。在创建对象时,会调用构造器。也就是说new Student()就是在执行构造器,当构造器执行完了,也就意味着对象创建成功。
在设计一个类时,如果不写构造器,Java会自动生成一个无参数构造器。一旦定义了有参数构造器,Java就不再提供空参数构造器,此时建议加一个无参数构造器。
封装设计规范用8个字总结,就是:合理隐藏、合理暴露,这就需要用到修饰符。 修饰符本类同一包下其他类任意包下子类任意包下任意类private√缺省√√protected√√√public√√√√ private < 缺省 < protected < public
一般称之为实体类(封装数据的类),可以使用ptg插件1秒生成标准JavaBean。
应用场景:实体类的对象只负责数据存取(除了给对象存、取值的方法就没有提供其他方法了),而对数据的业务处理交给其他类的对象来完成,以实现数据和数据业务处理相分离。
package com.abc.domain; public class Student { // 1.成员变量私有化 private String name; private int age; // 2.空参、带参构造方法 public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } // 3.对私有成员变量提供get和set方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,就像一个工具一样,所以把这样的类就叫做工具类。
工具类没有创建对象的需求,建议将工具类的构造器进行私有,这样别人就不能使用构造方法new对象了。
重写的方法上面,可以加一个注解@Override,用于标注这个方法是重写的父类方法。使用这个方法重写小技巧,可以指定java编译器,检查方法重写的格式是否正确,代码可读性也会更好。
super关键字:代表继承的父类。子类构造器,都会先调用父类构造器,再执行自己。如果不想使用默认的super()方式调用父类构造器,可以手动使用super(参数)调用父类有参数构造器。
this和super的用法:
访问本类成员: this.成员变量 //访问本类成员变量 this.成员方法 //调用本类成员方法 this() //调用本类空参数构造器 this(参数) //调用本类有参数构造器 访问父类成员: super.成员变量 //访问父类成员变量 super.成员方法 //调用父类成员方法 super() //调用父类空参数构造器 super(参数) //调用父类有参数构造器 注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。注意多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
多态的表现形式:父类类型 对象名称 = 子类对象;,其实是自动类型转换。
多态的前提:
多态的好处:
多态的弊端:
final关键字:
常量:被static final修饰的成员变量,通常用于记录系统配置信息。
关键字abstract,是抽象的意思,可以修饰类也可以修饰方法:
抽象类特点:
关键字interface,用来定义接口这种特殊结构。接口不能创建对象,是用来被类实现(implements)的,实现接口的类称为实现类。 public interface 接口名{ // 成员变量(常量) // 成员方法(抽象方法) }一个类可以实现多个接口(接口可理解成干爹),类实现接口必须重写所有接口的全部抽象方法,否则这个类也必须是抽象类。
接口和类的关系:
内部类是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类内部,这个类就是内部类。
内部类有四种形式,分别是:
Outer.Inner in = new Outer().new Inner();,外部类.内部类 变量名 = new 外部类().new 内部类()Outer.Inner in = new Outer.Inner();枚举是一种特殊类,格式如下: public enum 枚举类名{ 枚举项1,枚举项2,枚举项3; }特点:
泛型限定:
泛型擦除,即泛型只能编译阶段有效,一旦编译成字节码,是不包含泛型的。而且泛型只支持引用数据类型,不支持基本数据类型。
包装类就是把基本类型数据包装成对象。 基本数据类型对应包装类(引用数据类型)byteByteshortShortintIntegerlongLongcharCharacterfloatFloatdoubleDoublebooleanBoolean 当对一个原始值调用方法或属性时,解释器会临时将原始值包装为对应的对象,然后调用这个对象的属性或方法。
String创建对象的区别:
"..."方式写出的字符串对象,会存储到字符串常量池,且相同内容的字符串只存储一份字符串对象的内容比较,千万不要用==(默认比较地址),字符串对象的内容一样时地址不一定一样。判断字符串内容,建议用String提供的equals方法,只关心内容一样,就返回true,不关心地址。
public class HelloWorld { public static void main(String[] args) { String s = "好abc"; // 字符串遍历 for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); System.out.println(ch); }
System.out.println("-------------------"); // 字符串转字符数组,再遍历 char[] chars = s.toCharArray(); for (char aChar : chars) { System.out.println(aChar); } System.out.println("-------------------"); System.out.println(createCode(4)); } public static String createCode(int n) { String code = ""; String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random r = new Random(); for (int i = 0; i < n; i++) { int index = r.nextInt(data.length()); code += data.charAt(index); } return code; }
}
StringBuilder可以看成是一个容器,创建之后里面的内容是可变的,作用是提高字符串的操作效率。
使用StringBuilder拼接字符串时,代码写起来还是有一点麻烦,而StringJoiner号称是拼接神器,不仅效率高,而且代码简洁,JDK 8才出现这个类。 public class HelloWorld { public static void main(String[] args) { //参数1:间隔符,参数2:开头,参数3:结尾 StringJoiner s1 = new StringJoiner(",","[","]"); s1.add("java1"); s1.add("java2"); s1.add("java3"); System.out.println(s1); // [java1,java2,java3] } }
表示日期、时间、日期时间的类:LocalDate、LocalTime、LocalDateTime类,这三个类的用法套路都是一样的。 public class HelloWorld { public static void main(String[] args) { // 获取本地日期对象(不可变对象) LocalDate ld = LocalDate.now(); System.out.println(ld); // 2024-09-10
// 获取日期对象中的信息 int year = ld.getYear(); // 年 int month = ld.getMonthValue(); // 月(1-12) int day = ld.getDayOfMonth(); // 日 int dayOfYear = ld.getDayOfYear(); // 一年中第几天 int dayOfWeek = ld.getDayOfWeek().getValue(); // 星期几(1-7) System.out.println(year); System.out.println(month); System.out.println(day); System.out.println(dayOfYear); System.out.println(dayOfWeek); // 直接修改某个信息: withYear、withMonth、withDayOfYear、withDayOfMonth LocalDate ld2 = ld.withYear(2099); LocalDate ld3 = ld.withMonth(12); System.out.println(ld2); // 2099-09-10 System.out.println(ld3); // 2024-12-10 System.out.println(ld); // 2024-09-10 // 把某个信息加多少: plusYears、plusMonths、plusDays、plusWeeks LocalDate ld4 = ld.plusYears(2); LocalDate ld5 = ld.plusMonths(2); // 把某个信息减多少:minusYears、minusMonths、minusDays、minusWeeks LocalDate ld6 = ld.minusYears(2); LocalDate ld7 = ld.minusMonths(2); // 获取指定日期的LocalDate对象 LocalDate ld8 = LocalDate.of(2099, 12, 12); LocalDate ld9 = LocalDate.of(2099, 12, 12); // 判断2个日期对象是否相等,在前还是在后:equals isBefore isAfter System.out.println(ld8.equals(ld9)); // true System.out.println(ld8.isAfter(ld)); // true System.out.println(ld8.isBefore(ld));// false // 获取本地日期和时间对象 LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); // 2024-09-10T22:32:28.566246800 // 可以把LocalDateTime转换成LocalDate和LocalTime LocalDate d = ldt.toLocalDate(); LocalTime t = ldt.toLocalTime(); System.out.println(d); // 2024-09-10 System.out.println(t); // 22:33:39.302744400 LocalDateTime dt = LocalDateTime.of(d, t); System.out.println(dt); // 2024-09-10T22:33:39.302744400 }
}
public class HelloWorld { public static void main(String[] args) { // ZoneId:时区id ZoneId zoneId = ZoneId.systemDefault(); System.out.println(zoneId.getId()); // Asia/Shanghai System.out.println(zoneId); // Asia/Shanghai
// 获取Java支持的全部时区id System.out.println(ZoneId.getAvailableZoneIds()); // 把某个时区id封装成ZoneId对象 ZoneId zoneId1 = ZoneId.of("America/New_York"); // ZonedDateTime:带时区的时间 // 获取某个时区的ZonedDateTime对象 ZonedDateTime now = ZonedDateTime.now(zoneId1); System.out.println(now); // 2024-09-10T11:00:28.352739400-04:00[America/New_York] // 世界标准时间 ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC()); System.out.println(now1); // 2024-09-10T15:00:28.352739400Z // 获取系统默认时区的ZonedDateTime对象 ZonedDateTime now2 = ZonedDateTime.now(); System.out.println(now2); // 2024-09-10T23:00:28.352739400+08:00[Asia/Shanghai] }
}
通过获取Instant的对象可以拿到此刻的时间,由两部分组成:从1970-01-01 00:00:00开始到此刻的总秒数 + 纳秒数(1秒=1000毫秒 1毫秒=1000微秒 1微秒=1000纳秒)。 public class HelloWorld { public static void main(String[] args) { // 创建Instant对象,获取此刻时间信息,不可变对象 Instant now = Instant.now(); System.out.println(now); // 2024-09-10T15:42:27.397201Z
// 获取总秒数 long second = now.getEpochSecond(); System.out.println(second); // 1725982947 // 不够1秒的纳秒数 int nano = now.getNano(); System.out.println(nano); // 397201000 // Instant对象的作用:做代码的性能分析,或者记录用户的操作时间点 Instant now1 = Instant.now(); // 代码执行。。。。 Instant now2 = Instant.now(); }
}
DateTimeFormater,对日期进行格式化和解析。 public class HelloWorld { public static void main(String[] args) { // 创建日期时间格式化器对象 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm
");// 对时间进行格式化 LocalDateTime now = LocalDateTime.now(); System.out.println(now); String rs = formatter.format(now); // 正向格式化 System.out.println(rs); // 2024年09月10日 23:53:14 // 格式化时间另一种方案 String rs2 = now.format(formatter); // 反向格式化 System.out.println(rs2); // 2024年09月10日 23:53:14 // 解析时间一般使用LocalDateTime提供的解析方法来解析 String dateStr = "2029年12月12日 12:12:12"; LocalDateTime ldt = LocalDateTime.parse(dateStr, formatter); System.out.println(ldt); // 2029-12-12T12:12:12 }
}
Period、Duration这两个类用来对计算两个时间点的时间间隔。其中Period用来计算日期间隔(年、月、日),Duration用来计算时间间隔(时、分、秒、纳秒)。 public class HelloWorld { public static void main(String[] args) { LocalDate start = LocalDate.of(2029, 8, 10); LocalDate end = LocalDate.of(2029, 12, 15);
// 创建Period对象,封装两个日期对象 Period period = Period.between(start, end); // 通过Period对象获取两个日期对象相差的信息 System.out.println(period.getYears()); // 0 System.out.println(period.getMonths());// 4 System.out.println(period.getDays()); // 5 LocalDateTime start2 = LocalDateTime.of(2025, 11, 11, 11, 10, 10); LocalDateTime end2 = LocalDateTime.of(2025, 11, 11, 11, 11, 11); // 得到Duration对象 Duration duration = Duration.between(start2, end2); // 获取两个时间对象间隔的信息 System.out.println(duration.toDays()); // 0 间隔多少天 System.out.println(duration.toHours());// 0 间隔多少小时 System.out.println(duration.toMinutes()); // 1 间隔多少分 System.out.println(duration.toSeconds()); // 61 间隔多少秒 System.out.println(duration.toMillis());// 61000 间隔多少毫秒 System.out.println(duration.toNanos()); // 61000000000 间隔多少纳秒 }
}
public class HelloWorld { public static void main(String[] args) { int[] arr = {10, 20, 30, 40}; System.out.println(Arrays.toString(arr)); // [10, 20, 30, 40]
// 拷贝数组,包前不包后 int[] arr2 = Arrays.copyOfRange(arr, 1, 3); System.out.println(Arrays.toString(arr2)); // [20, 30] // 拷贝数组,指定新数组长度 int[] arr3 = Arrays.copyOf(arr, 5); System.out.println(Arrays.toString(arr3)); // [10, 20, 30, 40, 0] // 把数组中原数据改为新数据又存进去 double[] prices = {99.8, 128, 100}; // 把所有的价格都打八折,然后又存进去 Arrays.setAll(prices, new IntToDoubleFunction() { @Override public double applyAsDouble(int value) { // value = 0 1 2 return prices[value] * 0.8; } }); System.out.println(Arrays.toString(prices)); // [79.84, 102.4, 80.0] // 使用Lambda表达式简化格式 // Arrays.setAll(prices, value -> prices[value] * 0.8 ); // 对数组进行排序(默认升序) Arrays.sort(prices); System.out.println(Arrays.toString(prices)); // [79.84, 80.0, 102.4] }
}
集合包括:Collection单列集合和Map双列集合。
Collection接口:
List接口:添加元素有序、可重复、有索引
ArrayList实现类
LinkedList实现类
Set接口:添加元素无序、不重复、无索引
HashSet实现类,子类LinkedHashSet实现类是有序的
TreeSet实现类(默认按大小升序)
Map接口:
迭代器就是一种集合的通用遍历方式。 public class HelloWorld { public static void main(String[] args) { Collection c = new ArrayList<>(); c.add("赵敏"); c.add("小昭"); c.add("灭绝"); System.out.println(c); // [赵敏, 小昭, 灭绝]
// 增强for循环(元素数据类型 变量名 : 数组或集合) for (String s : c) { System.out.println(s); } // 调用forEach方法 c.forEach(System.out::println); //[赵敏, 小昭, 灭绝] }
}
ArrayList适合:根据索引查询数据;不适合:数据量大的同时,又要频繁的进行增删操作。 public class HelloWorld { public static void main(String[] args) { // 创建ArrayList集合对象 ArrayList list = new ArrayList<>();
list.add("Python"); list.add("Java"); list.add("Python"); System.out.println(list); // [Python, Java, Python] // 往集合某个索引位置处添加数据 list.add(1, "MySQL"); System.out.println(list); // [Python, MySQL, Java, Python] // 根据索引获取集合中某个索引位置处值 String rs = list.get(1); System.out.println(rs); // MySQL // 获取集合大小,即存储的元素个数 System.out.println(list.size()); // 4 // 根据索引删除集合中的某个元素,返回被删除的元素 System.out.println(list.remove(1)); // MySQL // 直接删除某个元素,默认删除第一次出现的数据,删除成功返回true System.out.println(list.remove("Python")); // true System.out.println(list); // [Java, Python] // 修改某个索引位置处的数据,修改后会返回原来的值 System.out.println(list.set(1, "JS")); // Python System.out.println(list); // [Java, JS] list.removeIf(name -> name.contains("J")); System.out.println(list); // [] }
}
HashSet集合底层是基于哈希表实现的,哈希表根据JDK版本的不同有区别:
HashSet集合存储元素时,底层调用了元素的两个方法:一个是hashCode方法获取元素的hashCode值(哈希值);另一个是调用了元素的equals方法,用来比较新添加的元素和集合中已有的元素是否相同。
JDK 8开始后,当链表长度超过8,且数组长度>=64时,会把链表转成红黑树。
Map集合遍历: public class HelloWorld { public static void main(String[] args) { Map<String, Double> map = new HashMap<>(); map.put("蜘蛛精", 169.8); map.put("孙悟空", 165.8); map.put("至尊宝", 169.5); System.out.println(map);
// 遍历map集合,传递Lambda表达式 map.forEach((k, v) -> System.out.println(k + "-->" + v)); }
}
也叫Stream API,是从JDK 8以后的一个新特性,专业用于对集合或数组进行便捷操作。
获取Stream流:
public class HelloWorld { public static void main(String[] args) { // 1、获取List集合Stream流 List names = new ArrayList<>(); Collections.addAll(names, "张三丰", "张无忌", "周芷若"); Stream stream = names.stream(); System.out.println(stream); // 2、获取Set集合Stream流 Set set = new HashSet<>(); Collections.addAll(set, "刘德华", "张德玉", "蜘蛛精"); Stream stream1 = set.stream(); stream1.filter(s -> s.contains("德")).forEach(System.out::println); // 3、获取Map集合的Stream流 Map<String, Double> map = new HashMap<>(); map.put("古力娜扎", 172.3); map.put("迪丽热巴", 168.3); map.put("马尔扎巴", 166.3); Set keys = map.keySet(); Stream ks = keys.stream(); System.out.println(ks); Collection values = map.values(); Stream vs = values.stream(); System.out.println(vs); Set<Map.Entry<String, Double>> entries = map.entrySet(); Stream<Map.Entry<String, Double>> kvs = entries.stream(); kvs.filter(e -> e.getKey().contains("巴")) .forEach(e -> System.out.println(e.getKey() + "-->" + e.getValue())); // 4、获取数组Stream流 String[] names2 = {"张翠山", "东方不败", "唐大山"}; Stream s1 = Arrays.stream(names2); Stream s2 = Stream.of(names2); System.out.println(s1); System.out.println(s2); } }
Stream流中间方法可以继续调用,这样一来就可以支持链式编程(或者叫流式编程)。
Stream流终结方法,调用完之后,其结果就不再是Stream流了,所以不支持链式编程。
缓冲字节流(自带8KB缓冲池): public class HelloWorld { public static void main(String[] args) { try ( InputStream is = new FileInputStream("helloworld-app/src/abc.txt"); // 1、定义一个字节缓冲输入流包装原始字节输入流 InputStream bis = new BufferedInputStream(is);
OutputStream os = new FileOutputStream("helloworld-app/src/abc2.txt"); // 2、定义一个字节缓冲输出流包装原始字节输出流 OutputStream bos = new BufferedOutputStream(os); ){ byte[] buffer = new byte[1024]; int len; while ((len = bis.read(buffer)) != -1){ bos.write(buffer, 0, len); } System.out.println("复制完成!!"); } catch (Exception e) { e.printStackTrace(); } }
}
有两种转换流InputStreamReader,OutputStreamWriter,它们可以将字节流转换为字符流,并且可以指定编码方案。
字节流是以字节为单位来读写数据、字符流是以字符为单位来读写数据、而对象流是以对象为单位来读写数据。也就是把对象当做一个整体,可以写一个对象到文件(序列化),也可以从文件中把对象读取出来(反序列化)。
为了简化对IO操作,Apache开源基金组织提供了一组有关IO流小框架(名字叫Commons-IO),可以提高IO流的开发效率。
引入jar包(提供的工具类叫FileUtils),具体步骤如下:
public class HelloWorld { public static void main(String[] args) throws IOException { // 复制文件 FileUtils.copyFile(new File("helloworld-app/src/abc.txt"), new File("helloworld-app/src/abc2.txt"));
// 复制文件夹 FileUtils.copyDirectory(new File("D:\\私人珍藏"), new File("D:\\私人珍藏2")); // 删除文件夹 FileUtils.deleteDirectory(new File("D:\\私人珍藏2")); // Java原生提供的一行代码搞定很多事情 Files.copy(Path.of("helloworld-app/src/abc.txt"), Path.of("helloworld-app/src/abc2.txt")); System.out.println(Files.readString(Path.of("helloworld-app/src/abc.txt"))); }
}
作用:用于简化匿名内部类的代码书写,JDK 8新语法形式。Lambda表达式只能简化函数式接口的匿名内部类。
函数式接口:
用来进一步简化Lambda表达式,它简化的更加过分。 Student.java: package com.abc.hello;
public class Student implements Comparable { private String name; private double height; private int age;
public Student(String name, double height, int age) { this.name = name; this.height = height; this.age = age; } public int getAge() { return age; } @Override public int compareTo(Student o) { return this.age - o.age; // 按照年龄升序排列 // return o.age - this.age; // 按照年龄降序排列 } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", height=" + height + ", age=" + age + '}'; }
}
CompareByAge.java:package com.abc.hello; public class CompareByAge { public static int compareByAge(Student o1, Student o2) { return o1.getAge() - o2.getAge(); // 升序排序规则 } }
HelloWorld.java:
package com.abc.hello; import java.util.Arrays; public class HelloWorld { public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("蜘蛛精", 169.5, 23); students[1] = new Student("紫霞", 163.8, 26); students[2] = new Student("至尊宝", 167.5, 24); System.out.println(Arrays.toString(students)); // 原始写法:对数组中学生对象,按照年龄升序排序 // Arrays.sort(students, new Comparator() { // @Override // public int compare(Student o1, Student o2) { // return o1.getAge() - o2.getAge(); // 按照年龄升序排序 // } // }); // 使用Lambda简化后形式 // Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge()); // Arrays.sort(students, (o1, o2) -> CompareByData.compareByAge(o1, o2)); //静态方法引用:类名::方法名。实际上是用类名调用方法,但把参数给省略了 Arrays.sort(students, CompareByAge::compareByAge); System.out.println(Arrays.toString(students)); } }
异常体系:
Error:系统级别错误
Exception:异常
运行时异常:RuntimeException
编程时异常:Exception
两种特殊的文本文件,一种是properties文件,一种是xml文件。
如果XML标签文本中有特殊字符,需要用一些占位符代替: < 表示 < > 表示 > & 表示 & ' 表示 ' " 表示 " 3 < 2 && 5 > 4 如果标签文本中,出现大量的特殊字符,不想使用特殊字符,此时可以用CDATA区,格式如下: 4 ]]> 读取XML文件中的数据,称为XML解析。好用的XML解析框架,最知名的是DOM4J(第三方开发)。
DOM4J也提供了往XML文件中写标签的方法,但是用起来比较麻烦,不建议使用。可以使用StringBuilder按照标签的格式拼接,然后再使用BufferedWriter写到XML文件中去就可以了。
XML约束有两种,一种是DTD约束(.dtd结尾文件)、一种是Schame约束(.xsd结尾文件)。Schame可以约束XML文件的编写和数据类型
推荐使用Logback日志框架,是基于SLF4J日志规范实现的框架,分为3个模块:logback-core(必须有)、logback-classes(必须有)、logback-access(可选)。
要使用Logback日志框架,至少需要在项目中整合如下3个模块:
本文作者:a
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!