三毛笔记

Java基础语法学习笔记

准备工作

JRE = JVM + 核心类库。JRE(Java运行环境),JVM(Java虚拟机,真正运行Java程序的地方),核心类库(Java已经写好的程序,供程序员调用)。

JDK = JRE + 开发工具。JDK(Java开发工具包),开发工具(java、javac等)。

安装JDK

官网下载:https://www.oracle.com/cn/java/technologies/downloads/,为了便于管理,建议采用Compressed Archive版本。

配置环境变量

配置Path环境变量:右键「此电脑」→「属性」→「高级系统设置」→「环境变量」→「系统变量」→「新建」,变量名:JAVA_HOME,变量值:填写JDK安装路径,如:C:\dev\java\jdk-21.0.4。

双击系统变量下的Path环境变量,新建%JAVA_HOME%\bin并上移到第一位,最后点击确定即可。

测试JDK

打开CMD窗口,输入:java -version,测试JDK是否安装成功。

业内大多数程序员都在遵守阿里巴巴的命名规则:《阿里巴巴Java开发手册(终极版)》。

IDEA

IDEA全称IntelliJ IDEA,是用于Java语言开发的集成环境,是业界公认的目前用于Java程序开发最好的工具。

IntelliJ IDEA官网:https://www.jetbrains.com/idea/download/

IntelliJ IDEA正版专属激活码领取(永久更新):

项目结构

project中可以创建多个module,module中可以创建多个package,package中可以创建多个class。

IDEA常用快捷键

基础语法

标识符

就是给类,方法,变量等起的名字。

标识符命名规则--硬性要求:

软性建议:

数据类型

基本数据类型,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 + "岁");
    }
}

分支结构

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

实体JavaBean

一般称之为实体类,可以使用PTG插件1秒生成标准JavaBean。

实体类是一种特殊形式的类,只负责数据存取(除了给对象存、取值的方法就没有提供其他方法了),而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离(应用场景)。

工具类

如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,就像一个工具一样,所以把这样的类就叫做工具类。

工具类没有创建对象的需求,建议将工具类的构造器进行私有,这样别人就不能使用构造方法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 接口名{
  // 成员变量(常量)
  // 成员方法(抽象方法)
}

一个类可以实现多个接口(接口可理解成干爹),类实现接口必须重写所有接口的全部抽象方法,否则这个类也必须是抽象类。

接口和类的关系:

内部类

内部类是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类内部,这个类就是内部类。

内部类有四种形式,分别是:

枚举类

枚举是一种特殊类,格式如下:

public enum 枚举类名{
  枚举项1,枚举项2,枚举项3;
}

特点:

泛型

泛型限定:

泛型擦除,即泛型只能编译阶段有效,一旦编译成字节码,是不包含泛型的。而且泛型只支持引用数据类型,不支持基本数据类型。

包装类

包装类就是把基本类型数据包装成对象。

基本数据类型对应包装类(引用数据类型)
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

字符串

String类常用方法

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

使用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]
    }
}

JDK 8日期类

表示日期、时间、日期时间的类: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类

通过获取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:ss");

        // 对时间进行格式化
        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 间隔多少纳秒
    }
}

Arrays类

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接口:

Map接口:

遍历集合

迭代器就是一种集合的通用遍历方式。

public class HelloWorld {
    public static void main(String[] args) {
        Collection<String> 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); //[赵敏, 小昭, 灭绝]
    }
}

List集合

ArrayList适合:根据索引查询数据;不适合:数据量大的同时,又要频繁的进行增删操作。

public class HelloWorld {
    public static void main(String[] args) {
        // 创建ArrayList集合对象
        ArrayList<String> 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); // []
    }
}

Set集合

HashSet集合底层是基于哈希表实现的,哈希表根据JDK版本的不同有区别:

HashSet集合存储元素时,底层调用了元素的两个方法:一个是hashCode方法获取元素的hashCode值(哈希值);另一个是调用了元素的equals方法,用来比较新添加的元素和集合中已有的元素是否相同。

JDK 8开始后,当链表长度超过8,且数组长度>=64时,会把链表转成红黑树。

Map集合

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流

也叫Stream API,是从JDK 8以后的一个新特性,专业用于对集合或数组进行便捷操作。

获取Stream流:

public class HelloWorld {
    public static void main(String[] args) {
        // 1、获取List集合Stream流
        List<String> names = new ArrayList<>();
        Collections.addAll(names, "张三丰", "张无忌", "周芷若");
        Stream<String> stream = names.stream();
        System.out.println(stream);

        // 2、获取Set集合Stream流
        Set<String> set = new HashSet<>();
        Collections.addAll(set, "刘德华", "张德玉", "蜘蛛精");
        Stream<String> 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<String> keys = map.keySet();
        Stream<String> ks = keys.stream();
        System.out.println(ks);

        Collection<Double> values = map.values();
        Stream<Double> 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<String> s1 = Arrays.stream(names2);
        Stream<String> s2 = Stream.of(names2);
        System.out.println(s1);
        System.out.println(s2);
    }
}

Stream流中间方法可以继续调用,这样一来就可以支持链式编程(或者叫流式编程)。

Stream流终结方法,调用完之后,其结果就不再是Stream流了,所以不支持链式编程。

IO流

缓冲流

缓冲字节流(自带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框架

为了简化对IO操作,Apache开源基金组织提供了一组有关IO流小框架(名字叫Commons-IO),可以提高IO流的开发效率。

引入jar包(提供的工具类叫FileUtils),具体步骤如下:

  1. 在模块目录下,新建lib文件夹
  2. 把jar包复制粘贴到lib文件夹下
  3. 选择lib下的jar包,右键点击Add As Library,然后就可以用了
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")));
    }
}

Lambda表达式

作用:用于简化匿名内部类的代码书写,JDK 8新语法形式。Lambda表达式只能简化函数式接口的匿名内部类。

函数式接口:

静态方法引用

用来进一步简化Lambda表达式,它简化的更加过分。
Student.java:

package com.abc.hello;

public class Student implements Comparable<Student> {
    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<Student>() {
//            @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));
    }
}

异常

异常体系:

特殊文本文件

两种特殊的文本文件,一种是properties文件,一种是xml文件。

XML文件

如果XML标签文本中有特殊字符,需要用一些占位符代替:

&lt;  表示 <
&gt;  表示 >
&amp; 表示 &
&apos; 表示 '
&quot; 表示 "
<data> 3 &lt; 2 &amp;&amp; 5 &gt; 4 </data>

如果标签文本中,出现大量的特殊字符,不想使用特殊字符,此时可以用CDATA区,格式如下:

<data>
    <![CDATA[
        3 < 2 && 5 > 4
    ]]>
</data>

读取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个模块:

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »