黑马java高级笔记(最新)

83 阅读55分钟

高级

静态(static)

添加上静态成员之后,也就是所有的新创建的对象都只会共享其中的一份数据,也就是我想让这一块的数据成为不变的内容,每一个新创建的对象的爱好比如都是打篮球的时候我就可以添加一个static来进行调用,并且使用static可以直接使用对象名.的方式进行调用,不需要重新创建对象就可以使用了.

单例设计模式-------这里的意思是有一个,一个对象只能被创建一次,如果创建的多了就只会共享一条数据

方法重写

1.方法重写就是子类写了一个方法名称,形参列表和父类中的某个方法是一模一样的

2.重写方法的时候记得添加@override注解,这个注解可以校验重写是否正确,同时可读性好

3.私有方法,静态方法不能被重写

继承

1.java是单继承的:一个类只能继承一个直接父类;java中的类不支持多继承,但是支持多层继承

2.Object类是java中所有类的祖宗类

3.在子类方法中访问其他成员(成员变量,成员方法),是依照就近原则的-----------子类里面如果找不到才去父类里面寻找

4.如果字父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办(可以使用super关键字,制定访问父类的成员:super.父类成员变量/父类成员方法)

5.子类构造器的特点(子类的全部构造器,都会先调用父类的构造器,然后在执行自己)----------原因就是在每一个构造器的前面都有一行super关键字,只不过默认的时候是不写的

6.如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(...),指定去调用父类的有参数构造器

package ww.com;
//父类
class People{
    private String name;
    private int age;

    public People() {
    }

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }
}
//子类
class Teacher extends People{
    private String skill;

    public Teacher(String skill) {
        this.skill = skill;
    }

    public Teacher(String name, int age, String skill) {
        //这里的super就会将name和age传送给父类的有参数构造器,然后为其赋值
        super(name, age);
        this.skill = skill;
    }

    @Override
    //这里重新实现toString方法,供其打印 
    public String toString() {
        return "Teacher{" +
                "name"+super.getName()+",age已经"+super.getAge()+
                "岁了,skill='" + skill + '\'' +
                '}';
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
}


public class Test {
    public static void main(String[] args) {
        //static的作用是类变量,也叫做静态变量,就是我只希望出现一份,并且所有的变量之间都可以共享
    Teacher t = new Teacher("刘宇航",22,"java");
        System.out.println(t);
    }
}

7.this(...)调用兄弟构造器

多态

认识多态:1.对象多态2.行为多态------------People p1 = new Student(); People p2 = new Teacher();-------左边可以是父类,右边创建的对象为子类

识别技巧:编译看左边,运行看右边

对于变量而言:编译看右边,运行看左边

2.使用多态可以解耦合,扩展性更强;使用父类类型的变量作为方法的形参时,可以接收一切子类对象.

//由于在这里我并不知道这个People接到的形参是Teacher还是Student,所以我需要在下方进行判断一下是什么类型,然后再继续
//强制类型转换之前,java建议使用instanceof来判断当前对象的真实类型:对象instanceof类型。
public static void go(People p){
    p.run();
    if(p instanceof Student){
        Student s = (Student) p;
        s.test();
    }else if(p instanceof Teacher){
        Teacher t = (Teacher) p;
        t.teach();
    }
}

final

1.final关键字是最终的意思,可以修饰(类,方法,变量)

2.修饰类:该类被称为最终类,特点是不能被继承了

3.修饰方法:该方法被称为最终方法,特点是不能被重写了.

4.修饰变量:该变量只能被赋值一次

final 修饰基本类型的变量,变量存储的数据不能被改变. final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的

使用static final修饰的成员变量就被称为常量;作用:通常用于记录系统的配置信息.------------一般常量的名字使用大写字母

抽象类

使用abstract修饰的类即为抽象类

1.抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类

2.类该有的成员(成员变量,方法,构造器)抽象类都可以有.

3.抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现

4.一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类必须定义成为抽象类

接口

实现接口可以使用implements,实现接口的类称为实现类

1.成员变量(常量)String SCHOOL_NAME = "黑马程序员";--------------------接口定义的量是常量---不需要添加static final

2.接口里面的方法的成员方法(抽象方法)-------------

3.接口中只能定义抽象类和抽象接口

4.一个类可以实现多个接口(接口可以理解为干爹)可以实现类的多个接口

5.1.JDK8中新增的方法,默认方法,必须使用default修饰,默认会被public进行修饰

​ 2.私有方法:必须使用private的方法进行修饰(JDK9开始才支持的)

​ 3.静态方法:必须使用static修饰,默认会被public修饰

6.接口是可以多继承的--------interface D extends C,B,A{}

内部类

1.成员内部类

​ 1.内部类其实就是在一个类的里面再定义一个类,定义好的那个类就属于内部类

​ 2.内部类的调用方式 Outer.Inner in = new Outer().new Inner();--------------new的时候需要先创建出来外部类,然后再去创建内部类

​ 3.成员内部类,如果想要访问最外面的内容可以使用类的名称.this.变量名来进行访问

2.静态内部类

​ 1.有static修饰的内部类,属于外部类自己特有

​ 2.如何调用静态内部类里面的内容呢?----------------------Outer.Inner in = new Outer.Inner();

3.匿名内部类

package ww.com;
public class Test {
    public static void main(String[] args) {
        //下面创建的方法就叫做匿名内部类
        new Animal(){
            @Override
            public void cry() {
                System.out.println("猫,喵喵喵的叫");
            }
        };
    }
}
abstract class Animal{
    public abstract void cry();
}

2.匿名内部类在开发中的使用场景-------------------通常都是作为一个参数传输给方法然后执行

package ww.com;

public class Test {
    public static void main(String[] args) {
        //这里直接将new 出来的Swimming传送给下面的go方法
        go(new Swimming(){
            @Override
            public void swim() {
                System.out.println("狗游泳飞快,跑起来真的不可思议的速度");
            }
        });
    }
    public static void go(Swimming s){
        System.out.println("开始------------------");
        s.swim();
    }
}
//定义一个接口
interface Swimming{
    void swim();
}

3.匿名内部类有啥特点?-------------匿名内部类本质就是一个子类,并会立即创建出一个子类对象

------匿名内部类一般不会自己去写,一般都是别人的项目需要我们提交过去一个类

枚举

1.枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象

2.枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象

3.枚举都是最终类,不可以被继承

4.枚举类中,从第二行开始,可以定义类的其他各种成员

5.编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法

//枚举一般用来判断常量的方式来进行
//比如说我想定义一个方法来判断是男是女,我就可以用如下方法来进行约束,这样在入参的时候就会进行校验,如果不对就会立即报错
首先来定义一个枚举
package ww.com;

public enum Constant {
    BOY,GIRL;
}

//然后来使用
package ww.com;

public class Test {
    public static void main(String[] args) {
        //给下面的函数传送一个枚举类型的常量
        check(Constant.BOY);
    }
    public static void check(Constant sex){
        switch (sex){
            case BOY:
                System.out.println("展示一些美女图片,信息");
                break;
            case GIRL:
                System.out.println("展示一些帅哥图片,一些土豪信息");
                break;
        }
    }
}

泛型

1.定义类,接口,方法时,同时声明了一个或者多个类型变量(如:),称为泛型类,泛型接口,泛型方法,他们统称为泛型

2.作用就是为了避免在编译阶段由于约束所能操作的数据类型,并自动进行检查的能力,这样可以避免强制类型转换,及其可能出现的异常

3.泛型的本职:把具体的数据类型作为参数传给类型变量

泛型类

public class User<类型变量,类型变量,类型变量...>{}

一般使用public class User<E e>{
    
}

泛型接口

public interface Data<T>{
    void add(T t)
} 

//举例
//首先定义一个泛型的接口
package ww.com;
import java.util.ArrayList;
public interface Data<T> {
    void add(T t);
    ArrayList<T> getByName(String name);
}
//定义一个Student的类
package ww.com;
public class Student {
}
//实现上面定义的泛型接口,然后完成这个类
package ww.com;
import java.util.ArrayList;
//这里将Student传送给上面的泛型接口T,然后通过泛型接口T将add方法和ArrayList集合的类型都设置成为了T,这样在实现泛型接口的时候就要去实现这个类了,然后将这个类给实现完成
public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {
	
    }
    @Override
    public ArrayList<Student> getByName(String name) {
        return null;
    }
}

泛型方法

//这里的T就是泛型,然后用于接受类
public static <T> void test(T t){}
//如果这里我只想接收子类,那么我就可以在这里使用两种方法,来对接受的类型做一个限制
1.第一种方法-------------下面的通配符就是可以代表一切类型的意思
public static void go(ArrayList<? extends Car> cars)//这里的?就是通配符的意思也就是所有的类型都是可以接收的,继承了Car类型意思就是接下来的代码只能接收Car的子类,如果是其它类型的话是不支持这样做的
2.第二种方法
public static <T extends Car>  void go(ArrayList<T> cars)//这里就是第二种方式由于T继承了Car,所以就导致了要传入的类型必须是他的子类才可以,如果是其他类型的话是不支持的

泛型是工作在编译阶段的,一旦程序编译成为了class文件,class文件中就不存在泛型了,这就是泛型擦除

泛型是不支持基本数据类型的,只能支持对象类型<引用数据类型>

常用API

1.toString---------------------返回对象的字符串表示形式

2.equals-----------------------判断两个对象是否相等-----------------比较的时候可以使用Objects.equals(a,b)来进行对比,这样就不会出现空指针异常了

3.clone-------------------------克隆一个一模一样的对象出来

package ww.com;
//这里一定要记得实现Cloneable接口
public class User implements Cloneable {
    private int id;
    private String userName;
    private String passWord;
    private double[] scores;

    public User() {
    }

    public User(int id, String userName, String passWord, double[] scores) {
        this.id = id;
        this.userName = userName;
        this.passWord = passWord;
        this.scores = scores;
    }
    ------------------------------------------------------------------------------------------------------------
//这里记得重写clone方法
    //下面的是浅克隆
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    //下面的是深度克隆
    @Override
    protected Object clone() throws CloneNotSupportedException {
       User u2 = (User) super.clone();
      u2.scores = u2.scores.clone();
        return u2;
    }
    ------------------------------------------------------------------------------------------------------------

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double[] getScores() {
        return scores;
    }

    public void setScores(double[] scores) {
        this.scores = scores;
    }
}
//使用克隆好的这个接口
package ww.com;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        User u1 = new User(1,"张三","666",new double[]{99.0,99.5});
        //将u1强制转换成为User类型
       User u2 =(User) u1.clone();

    }
}

Objects

1.equals-------------------------------判断两个对象是否相等----------------------使用Objects.equals(a,b),这样就不怕他抛出异常了,可以很好的进行使用

2.isNull---------------------------------判断对象是否为Null,为null返回true,反之返回false

3.nonNull------------------------------判断对象是否不为null,不为null则返回true,反之

包装类

基本数据类型对应的包装类型(引用数据类型)
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean
package ww.com; 
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        int a = 11;
        Integer b = Integer.valueOf(1);
        System.out.println(b);
    }
}

重点

public static String toString(double d)//可以将基本类型转换为字符串类型
public static int parseInt(String s)//可以将字符串类型转换为整型
public static Integer valueOf(String s)//可以将字符串转换为Integer类型

StringBuilder代表可变字符串对象,相当于一个容器,他里面装的字符串是可以改变的,就是用来操作字符串的

​ 1.append添加数据并返回StringBuilder对象本身

​ 2.reverse将对象的内容反转

​ 3.返回对象内容的长度

​ 4.通过toSting()就可以把实现的StringBuilder转换为String

StringBuffer和StringBuilder是一模一样的,stringBuffer是线程安全的

StringJoiner

//中间使用,来进行拼接
StringJoiner s = new StringJoiner(",");
s.add("java1");
s.add("java2");
s.add("java3");
此时输出就是java1,java2,java3

Math

Math.abs(int a)取得绝对值

Math.ceil(double a)向上取整

Math.floor(double a)向下取整

Math.round(double a)四舍五入

Math.max(int a,int b)取得最大值

Math.min(int a,int b)取得最小值

Math.pow(double a,double b)取次方

Math.random()取随机数

Runtime

//通过程序打开某一个软件
Runtime r = Runtime.getRuntime();
r.exec("软件的路径")
    
//关闭某一个软件
Runtime r = Runtime.getRuntime();
Process p = r.exec("QQ");
Thread.sleep(5000)//让程序在这里暂停5s后在继续往下走
p.destory();//关闭软件

BigDecimal-----重点

double a = 0.1;
double b = 0.2;
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
BigDecimal c1 = a1.add(b1);
System.out.println(c1);
//解决计算结果失真问题
add是加法
    subtract是减法
    multiply是乘法
    divide是除法
    //使用除法的时候会有精度精确的问题
    divide(BigDecimal,精确几位,舍入模式)

Date

JDK8之前传统的日期.时间

package ww.com;

import java.math.BigDecimal;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date d = new Date();
        long time = d.getTime();
        System.out.println(d);
        //计算出来2s之后的时间是多少
        time +=2*1000;
        Date d2 = new Date(time);
        System.out.println(d2);
        //修改当前时间
        Date d3 = new Date();
        d3.setTime(time);
        System.out.println(d3);
    }
}

2.SimpleDateFormat------------------------意思是时间格式化

package ww.com;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date d = new Date();
        System.out.println(d);

        long time = d.getTime();
        System.out.println(time);

        //格式化日期对象,和时间毫秒值
        SimpleDateFormat s = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
        String rs = s.format(d);
        String s1 = s.format(time);
        System.out.println(s1);
        System.out.println(rs);
        
        System.out.println("-------------------------------------------");
        //把字符串转换成时间对象
        String dateStr = "2022-12-12 12:12:11";
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d2 = sdf2.parse(dateStr);
        System.out.println(d2);
        
        
    }
}

3.秒杀案例

package ww.com;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, ParseException {
        String start = "2023年11月11日 0:0:0";
        String end = "2023年11月11日 0:10:0";
        String xj = "2023年11月11日 0:01:18";
        String xp = "2023年11月11日 0:10:57";
        //将所有的日期转换成为对象的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Date startDt = sdf.parse(start);
        Date endDt = sdf.parse(end);
        Date xjDt = sdf.parse(xj);
        Date xpDt = sdf.parse(xp);
        //获取到每一个对象的毫秒值
        long startTime = startDt.getTime();
        long endTime = endDt.getTime();
        long xjTime = xjDt.getTime();
        long xpTime = xpDt.getTime();
        //判断获取到的毫秒值是否在最大值和最小值的区间之间
        if(xjTime>=startTime&&xjTime<=endTime){
            System.out.println("小贾您秒杀成功了");
        }else{
            System.out.println("小贾您秒杀失败了");
        }
        if(xpTime>=startTime&&xpTime<=endTime){
            System.out.println("小皮您秒杀成功了");
        }else{
            System.out.println("小皮您秒杀失败了");
        }
    }
}

4.Calendar日历对象

package ww.com;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, ParseException {
        Calendar now = Calendar.getInstance();
        System.out.println(now);

        //获取日历中的某个信息
        //这里的Calendar.YEAR是一个常量
        int year = now.get(Calendar.YEAR);
        System.out.println(year);

        //拿到日历中记录的日期对象
        Date time = now.getTime();
        System.out.println(time);

        //获取时间毫秒值
        long time2 = now.getTimeInMillis();
        System.out.println(time2);

        //修改日历中的某个信息
        now.set(Calendar.MONTH,9);
        System.out.println(now);

        //为某一个信息增加减少指定的值
        now.add(Calendar.MONTH,1);
        System.out.println(now);
    }
}

JDK8开始新增的日期时间

  1. LocalDate-----------代表的是本地日期(年.月、日、星期)

  2. LocalTime-----------代表本地时间(时分、秒、纳秒)

  3. LocalDateTime----代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)

  4. package ww.com;
    import java.time.LocalDate;
    public class Test {
        public static void main(String[] args)  {
           //获取本地日期对象
            LocalDate ld = LocalDate.now();
            System.out.println(ld);
    
            //1.获取日期对象中的信息
            int year = ld.getYear();//年
            int month = ld.getMonthValue();//月
            int day = ld.getDayOfMonth();//日
            int dayOfYear = ld.getDayOfYear();//一年中的第几天
            int dayOfWeek = ld.getDayOfWeek().getValue();//星期几
            System.out.println("["+year+","+month+","+day+"]");
            System.out.println("----------------------------------------");
            //直接修改某个信息:withYear,withMonth,withDayOfMonth,withDayOfYear
            LocalDate ld2 = ld.withYear(2099);
            System.out.println(ld2);
            System.out.println(ld);
            //把某个信息加多少:plusYears,plusMonths,plusDays,plusWeeks
            LocalDate ld4 = ld.plusYears(2);
            //把某个信息减多少:minusYears,minusMonths,minusDays,minusWeeks
            LocalDate ld6 = ld.minusYears(2);
    
            //5.获取指定日期的localDate对象:public static LocalDate of(int year,int month,int dayMonth)
            LocalDate ld68 = LocalDate.of(2099,12,12);
            System.out.println(ld68);
    
            //判断2个日期对象,是否相等,在前还是在后:
            //equals判断两个日期是否相等
            //isAfter判断这个日期是否在某个日期之后
            //isBefore判断这个日期是否在某个日期之前
    
            System.out.println(ld68.equals(ld2));
            System.out.println(ld68.isBefore(ld2));
            System.out.println(ld68.isAfter(ld2));
    --------------------------------------------------------------------------------------------------------------
     //1.ZoneId的常见方法
            //获取系统默认的时区
            ZoneId zoneId = ZoneId.systemDefault();
            System.out.println(zoneId.getId());
            System.out.println(zoneId);
    
            //获取java支持的全部失去ID
            System.out.println(ZoneId.getAvailableZoneIds());
    
            //把某一个时区的id封装成为ZoneId对象
            ZoneId zoneId1 = ZoneId.of("America/New_York");
            ZonedDateTime now = ZonedDateTime.now(zoneId1);
            System.out.println(now);
    
            //获取世界标准时间
            ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC());
            System.out.println(now1);
            ---------------------------------------------------------------------------------------------------------
            Instant now = Instant.now();
            //获取总的秒数
            long second = now.getEpochSecond();
            System.out.println(second);
            //3.不够一秒的那描述
            int nano = now.getNano();
            System.out.println(nano);
            System.out.println(now);
            ------------------------------------------------------------------------------------------------------------
                 //1.创建一个日期格式化器对象出来
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    
            //2.对时间进行格式化
            LocalDateTime now = LocalDateTime.now();
            System.out.println(now);
    
            String rs = formatter.format(now);
            System.out.println(rs);
    
            //格式化时间的第二种方式
            String rs2 = now.format(formatter);
            System.out.println(rs2);
    
            //4.解析时间:解析时间一般使用LocalDateTime提供的解析方法来解析
            String dateStr = "2029年12月12日 12:12:11";
            LocalDateTime ldt = LocalDateTime.parse(dateStr,formatter);
            System.out.println(ldt);
            --------------------------------------------------------------------------------------------------------------
            //计算两个日期之间的间隔
            LocalDate start = LocalDate.of(2029, 8, 10);
            LocalDate end = LocalDate.of(2029, 8, 15);
            //1.创建Period对象,并封装两个日期对象
            Period period = Period.between(start, end);
    
            //2.通过period对象获取两个日期对象相差的信息
            System.out.println(period.getYears());
            System.out.println(period.getMonths());
            System.out.println(period.getDays());
            --------------------------------------------------------------------------------------------------------------
            //计算两个时间之间的间隔
            LocalDateTime start = LocalDateTime.of(2025, 11, 11, 10, 10, 10);
            LocalDateTime end = LocalDateTime.of(2025, 11, 11, 11, 11, 11);
    
            Duration duration = Duration.between(start, end);
            //获取两个时间对象间隔的信息
            System.out.println(duration.toDays());//间隔多少天
            System.out.println(duration.toHours());//间隔多少小时
            System.out.println(duration.toMinutes());//间隔多少分钟
            System.out.println(duration.toSeconds());//间隔多少秒
            System.out.println(duration.toMillis());//间隔多少毫秒
            System.out.println(duration.toNanos());//介个多少纳秒
        }
    }
    

Arrays

package ww.com;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.function.IntToDoubleFunction;

public class Test {
    public static void main(String[] args) {
        //1.public static String toString(类型[] arr):返回数组的内容
        int[] arr = {10,20,30,40,50};
        System.out.println(Arrays.toString(arr));
        //2.public static 类型[] copyOfRange(类型[] arr,起始索引,结束索引) :拷贝数组(制定范围,包前不包后)
        int[] arr2 = Arrays.copyOfRange(arr, 1, 4);
        System.out.println(Arrays.toString(arr2));
        //3.public static copyOf(类型[] arr,int newLength):拷贝数组,可以指定新数组的长度).
        int[] arr3 = Arrays.copyOf(arr, 10);
        System.out.println(Arrays.toString(arr3));
        //4.public static setAll(double[] array,IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去)
        double[] prices = {99.8,128,100};
        //把所有的价格都打八折,然后又存进去
        Arrays.setAll(prices, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int value) {
                return prices[value] *0.8;
            }
        });
        System.out.println(Arrays.toString(prices));
        //5.public static void sort(类型[] arr):对数组进行排序(默认是升序排序)
        Arrays.sort(prices);
        System.out.println(Arrays.toString(prices));
    }
}

对于对象之间的排序

//创建一个学生对象
package ww.com;

public class Student implements Comparable<Student> {
    private String name;
    private double height;
    private int age;

    //指定比较规则
    //this o
    //这里是指定排序规则,一定要去实现上面的接口,实现接口里面的方法compareTo方法
    @Override
    public int compareTo(Student o) {
        //约定1:认为左边对象大于右边对象 请您返回正整数
        //约定2:认为左边对象小于右边对象请您返回负整数
        //约定3:认为左边对象等于右边对象请您一定返回0
        
        ------------------------------------
        //下面的是第一种写法
        if(this.age>o.age){
            return 1;
        }else if(this.age<o.age){
            return -1;
        }
        --------------------------------------
        下面的是第二种写法
        return this.age-o.age;
        --------------------------------------
        //如果使用第二种写法的话,下面的return 0;就不需要了
        return 0;
    }
    
	//这里记得一定要重写toString方法,如果不重写的话就会导致打印出来的结果就都是地址
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }

    public Student() {
    }

    public Student(String name, double height, int age) {
        this.name = name;
        this.height = height;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}

---------------------------------------------------------------------------------------------------------------------------
//主函数入口区

package ww.com;


import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        //目标:掌握如何对于数组中的对象进行排序.
       Student[] students = new Student[4];
       students[0] = new Student("蜘蛛精",169.5,30);
        students[1] = new Student("紫霞",163.8,26);
        students[2] = new Student("紫霞",163.8,26);
        students[3] = new Student("至尊宝",167.5,24);
        //1.public static void sort(类型[] arr):对数组进行排序.
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

第二种写法

package ww.com;


import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        //目标:掌握如何对于数组中的对象进行排序.
       Student[] students = new Student[4];
       students[0] = new Student("蜘蛛精",169.5,30);
        students[1] = new Student("紫霞",163.8,26);
        students[2] = new Student("紫霞",163.8,26);
        students[3] = new Student("至尊宝",167.5,24);
        //1.public static void sort(类型[] arr):对数组进行排序.
//        Arrays.sort(students);
//        System.out.println(Arrays.toString(students));
        //实现一个匿名内部类
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                -----------------------------------------------------
                    完成写法
                if(o1.getHeight()>o2.getHeight()){
                    return 1;
                }else if(o1.getHeight()<o2.getHeight()){
                    return -1;
                }
                return 0;
                ------------------------------------------------------
                    简写
                return Double.compare(o1.getHeight(),o2.getHeight());
                -------------------------------------------------------
            }
        });
        System.out.println(Arrays.toString(students));
    }
}

Lambda--------重点

Lambda表达式是JDK8开始新增的一种语法格式;作用:用于简化匿名内部类的代码写法

package ww.com;

public class Test {
    public static void main(String[] args) {
      Swimming s = ()->{
          System.out.println("学生快乐的游泳");
      };
      s.swim();
    }
}

interface Swimming{
    void swim();
}

首先需要是一个接口,并且这个接口里面只定义了一个接口,然后就可以通过Lambda找到被重写的匿名内部类然后进行实现

注意:Lambda表达式只能简化函数式接口的匿名内部类

所以究竟什么是函数式接口?-------------接口中只能由一个抽象方法的接口

注意:将来我们见到的大部分函数式接口,上面都可能会有一个@Functionallnterface的注解,有该注解的接口就必定是函数式接口

Lambda表达式的省略写法

1.参数类型可以省略不写

2.如果只有一个参数,参数类型可以省略,同时()也可以省略

3.如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号,如果这行代码是return 语句,也必须去掉return 不写

方法引用--------进一步简化lambda表达式

静态方法的引用

package ww.com;


import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
    Student[] students = new Student[4];
    students[0] = new Student("蜘蛛精",169.5,23);
        students[1] = new Student("紫霞",163.8,26);
        students[2] = new Student("紫霞",163.8,26);
        students[3] = new Student("至尊宝",167.5,24);
        //第一种未简化的时候
//        Arrays.sort(students, new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o2.getAge()-o1.getAge();
//            }
//        });
        //使用lambda的方式来进行简化
        //Arrays.sort(students,(o1,o2)->o1.getAge()-o2.getAge());
        //继续简化
        Arrays.sort(students,(o1,o2)->CompareByData.compareByAge(o1,o2));
        //继续简化
        Arrays.sort(students,CompareByData::compareByAge);
        System.out.println(Arrays.toString(students));
    }
}

//student类
package ww.com;

public class Student {
    private String name;
    private double height;
    private int age;

    public Student() {
    }

    public Student(String name, double height, int age) {
        this.name = name;
        this.height = height;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }
}
//CompareByData定义的一个简化方法,通过简化方法来使用静态方法引用
package ww.com;

public class CompareByData {
    public static int compareByAge(Student o1,Student o2){
        //按照年龄的升序排序
        return o1.getAge()-o2.getAge();
    }
    
}

静态方法的引用

类名::静态方法

使用场景

如果某个Lambda表达式只是调用一个静态方法,别切前后参数的形式一致,就可以使用静态方法引用

实例方法的引用

//定义一个类
package ww.com;

public class CompareByData {
    public  int compareByAgeDesc(Student o1,Student o2){
        //按照年龄的降序排序
        return o2.getAge()-o1.getAge();
    }
}
//Student对象
package ww.com;

public class Student {
    private String name;
    private double height;
    private int age;

    public Student() {
    }

    public Student(String name, double height, int age) {
        this.name = name;
        this.height = height;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }
}

//主函数的调用
package ww.com;


import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
    Student[] students = new Student[4];
    students[0] = new Student("蜘蛛精",169.5,23);
        students[1] = new Student("紫霞",163.8,26);
        students[2] = new Student("紫霞",163.8,26);
        students[3] = new Student("至尊宝",167.5,24);
        //实例方法的调用
        CompareByData compare = new CompareByData();
        Arrays.sort(students,compare::compareByAgeDesc);
        System.out.println(Arrays.toString(students));
    }
}


实例方法的调用

对象名::实例方法

使用场景

如果是某个Lambda表达式只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法进行引用

特定类型方法的引用

package ww.com;


import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
    String[] names = {"body","angela","Andy","dlei","caocao","Babo","jack","Cici"};
        //进行排序
        //Arrays.sort(names);
        //要求忽略首字符大小进行排序
        /*Arrays.sort(names,new Comparator<String>(){
            @Override
            public int compare(String o1,String o2){
                return o1.compareToIgnoreCase(o2);
            }
        });*/
        //简化
        Arrays.sort(names,String::compareToIgnoreCase);

        System.out.println(Arrays.toString(names));
    }
}


特定类型的方法引用

类型::方法

使用场景

如果某一个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用

构造器引用(理解语法就可)

构造器引用

类名::new

使用场景

如果某个Lambda表达式只是在创建对象,并且前后参数情况一致,就可以使用构造器引用

算法

冒泡排序

package ww.com.bean;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        int[] arr = {5,3,2,1};
        for (int i = 0; i < arr.length-1; i++) {
            //第一轮      0           3次
            //第二轮      1           2次
            //第三轮      2           1次
            for (int j = 0; j < arr.length-i-1; j++) {
                if(arr[j]>arr[j+1]){
                    int temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

选择排序

package ww.com.bean;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        int[] arr = {5,3,2,1};
        for (int i = 0; i < arr.length-1; i++) {
           // i=0   第一轮      j = 1,2,3
            //i = 1 第二轮      j = 2,3
            //i = 2 第三轮      j = 3
            for (int j = i+1; j < arr.length; j++) {
                if(arr[i]>arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

选择排序优化

package ww.com.bean;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        int[] arr = {5,3,2,1};
        for (int i = 0; i < arr.length-1; i++) {
           // i=0   第一轮      j = 1,2,3
            //i = 1 第二轮      j = 2,3
            //i = 2 第三轮      j = 3
            int minIndex = i;
            for (int j = i+1; j < arr.length; j++) {
               if(arr[minIndex]>arr[j]){
                   minIndex = j;
               }
            }
            if(i!=minIndex){
                int temp = arr[i];
               arr[i] = arr[minIndex];

               arr[minIndex] = temp;

            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

正则表达式

正则表达式初体验

package ww.com.bean;

public class Test {
    public static void main(String[] args) {
       //正则表达式初体验
        System.out.println(checkQQ("251425876"));
        System.out.println(checkQQ("12e41f123"));
    }
    public static boolean checkQQ(String qq){
        //判断qq号是否合法
        return qq!=null&&qq.matches("[1-9]\\d{5,19}");
    }
}

正则表达式规则

[abc]-----只能是a,b,c
[^abc]----除了abc之外的任何字符
[a-zA-Z]--a到z  A到Z  包括(范围)
[a-d[m-p]]a到d,或者m到p
[a-z&&[def]]d,e,或f(交集)
[a-z&&[^bc]]a到z,除了b和c(等同于[ad-z])
[a-z]&&[^m-p]a到z,除了m到p(等同于[a-lq-z])
    
    
.-----------任何字符
\d----------一个数字;[0-9]
\D----------非数字:[^0-9]
\s----------一个空白字符
\S----------非空白字符:[^\s]
\w----------[a-zA-Z_0-9]
\W----------[^\w]一个非单词字符
    
    
X?----------X,一次或者0次
X*----------X,零次或多次
X+----------X,一次或多次
X{n}--------X,正好n次
X{n,}-------X,正好n次
X{n,m}------X,至少n但不超过m次

//校验用户手机号是否正确
package ww.com.bean;
import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
    //校验用户输入的电话
        checkPhone();
    }
    public static void checkPhone(){
        while (true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入您的电话号码(手机|座机)");
            String phone = sc.nextLine();
            if(phone.matches("(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})")){
                System.out.println("您输入的号码格式正确");
                break;
            }else{
                System.out.println("您输入的号码格式不正确");
            }
        }

    }
}

//校验邮箱号是否正确

 public static void checkEmail(){
        while (true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入您的邮箱号");
            String email = sc.nextLine();
            if(email.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}")){
                System.out.println("您输入的邮箱号格式正确");
                break;
            }else{
                System.out.println("您输入的邮箱号格式不正确");
            }
        }
    }

爬取信息

package ww.com.bean;

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
    String data = "来黑马程序员学习Java,\n" +
            "电话: 1866668888,18699997777\n" +
            "或者联系邮箱: boniu@itcast.cn,\n" +
            "座机电话: 01036517895,010-98951256 \n" +
            "邮箱: bozai@itcast.cn,\n" +
            "邮箱: dlei0日9@163.com,\n" +
            "热线电话: 400-618-9090 ,400-618-4000,4006184000,4006189090";
		//定义规则
        String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})"
                +"|(400-?\\d{3,7}-?\\d{3,7})";
        //使用pattern.comile转化一下
        Pattern p = Pattern.compile(regex);
		//将data输入仍进去匹配
        Matcher matcher = p.matcher(data);
        //设置一个循环,打印输出语句
        while (matcher.find()){
            String rs = matcher.group();
            System.out.println(rs);
        }
    }
}

搜索替换

package ww.com.bean;


import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        //搜索替换功能
    String s1 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
    System.out.println(s1.replaceAll("\\w+", "-"));
    //将我我我喜欢编编编编程程程优化成为我喜欢编程
        /**
         * (一组),匹配任意字符的
         * \\1.伟这个组声明一个组号:1号
         * +:声明必须是重复的字
         */
        String s2 = "我我我喜欢编编编编程程程";
        System.out.println(s2.replaceAll("(.)\\1+", "$1"));
    //将名字提取出来整理成为一个数组
        String s3 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
        String[] names = s3.split("\\w+");
        System.out.println(Arrays.toString(names));
    }
}

异常

解决异常的两种办法,一种是(throws)

第二种是try...catch捕获异常,直接捕获程序出现的异常

自定义异常

自定义运行时异常

//首先需要自定义一个自定义异常类
//继承编译时异常类,然后重写构造器方法
package ww.com.bean;

public class AgelllegalRuntimeException extends RuntimeException{
    public AgelllegalRuntimeException() {
    }

    public AgelllegalRuntimeException(String message) {
        super(message);
    }
}
//主程序执行
package ww.com.bean;

public class Test {
    public static void main(String[] args) {
        try {
            saveAge(160);
            System.out.println("底层是执行成功的");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("底层出现了bug");
        }
    }

    private static void saveAge(int age) {
        if(age>0&&age<150){
            System.out.println("年龄被成功保存"+age);
        }else{
            //用一个异常对象封装这个问题
           throw  new AgelllegalRuntimeException("/age is illegal , your age is"+age);
        }
    }
}

自定义编译时异常

package ww.com.bean;
//继承编译时异常问题
public class AgelllegalException extends Exception{
    public AgelllegalException() {
    }

    public AgelllegalException(String message) {
        super(message);
    }
}


//解决异常问题
package ww.com.bean;

public class Test {
    public static void main(String[] args) {
        try {
//            saveAge(160);
            saveAge2(160);
            System.out.println("底层是执行成功的");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("底层出现了bug");
        }
    }

    private static void saveAge2(int age) throws AgelllegalException {
        if(age>0&&age<150){
            System.out.println("年龄被成功保存"+age);
        }else{
            //用一个异常对象封装这个问题
            //这里抛出之后还会向上进行抛出,如果上面的throws不解决这个问题的话这里是会出错的
            throw new AgelllegalException("/age is illegal , your age is");
        }
    }

}

异常的处理

1 捕获异常,记录异常并响应合适的信息给用户

package ww.com.bean;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args)  {
        try {
            test1();
        } catch (ParseException e) {
            System.out.println("您要解析的时间有问题");
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            System.out.println("您要找的文件不存在");
            e.printStackTrace();
        }
    }
    public static void test1() throws ParseException, FileNotFoundException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse("2028-11-11 10:24");
        System.out.println(d);
        test2();
    }

    public static void test2() throws FileNotFoundException {
        FileInputStream is = new FileInputStream("d:/meinv.png");

    }
}
//这里运行的逻辑其实就是,找到最底层的方法,然后抛出异常,一直找到最顶层的异常的时候就需要区捕获异常了,此时便不再向最外层抛出错误

-------------------------------------------------------------------------------------------------------
尝试优化
package ww.com.bean;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args)  {
        try {
            test1();
        } catch (Exception e) {
            System.out.println("您的当前操作有问题");
            e.printStackTrace();
        } 
    }
    public static void test1() throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse("2028-11-11 10:24");
        System.out.println(d);
        test2();
    }

    public static void test2() throws Exception {
        FileInputStream is = new FileInputStream("d:/meinv.png");

    }
}

2 捕获异常,尝试重新修复

package ww.com.bean;


import java.util.Scanner;
//需求:调用一个方法,让用户输入一个合适的价格返回为止
public class Test {
    public static void main(String[] args)  {

        while (true) {
            try {
                double money = getMoney();
                System.out.println(money);
                break;
            } catch (Exception e) {
                //如果用户输入的不是数字则会让用户一直输入,知道正确为止
                System.out.println("请您输入合法的数字");
            }
        }
    }
    public static double getMoney(){
        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.println("请您输入合适的价格");
            double money = sc.nextDouble();
            if(money>=0){
                return money;
            }else{
                System.out.println("您输入的价格是不合法的");
            }
        }
    }
}

集合进阶

Collection基础

Collection集合特点

List系列集合:添加的元素是有序,可重复,有索引的

​ ArrayList,LinekdList:有序,可重复,有索引

Set系列集合:添加的元素是无序,不重复,无索引

​ HashSet:无序,不重复,无索引

​ LinkedHashSet:有序,不重复,无索引

​ TreeSet:按照大小默认升序排序,不重复,无索引

Collection的常见方法如下

//把给定的对象添加到当前集合中
public boolean add(E e)
//清空当前集合中所有的元素
public void clear()
//把给i定的对象在当前集合中删除
public boolean remove(E e)
//判断当前集合中是否包含给定对象
public boolean contains(Object obj)
//判断当前集合元素是否为空
public boolean isEmpty()
//返回集合元素的个数
public int size()
//把集合中的元素,存储到数组中
public Object[] toArray()

Collection的遍历方式

迭代器

package ww.com.bean;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Scanner;

public class Test {
    public static void main(String[] args)  {
        Collection<String> c = new ArrayList<>();
        c.add("赵敏");
        c.add("小昭");
        c.add("素素");
        c.add("灭绝");
        System.out.println(c);
		//获得迭代器对象
        Iterator<String> it = c.iterator();
        hasNext判断下一个内容是否为空
        while (it.hasNext()){
            next取出下一个内容
            String ele = it.next();
            System.out.println(ele);
        }
    }
}

Collection集合获取迭代器的方法

Iterator iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合中的第一个元素

boolean hasNex() 询问当前位置是否有元素存在,存在返回true,不存在返回false

E next() 获取当前位置的元素,并同时将迭代器对象指向下一个元素处

增强for循环

格式

for(元素的数据类型 变量名:数组或者集合)

增强for可以用来遍历集合或者数组-------本质就是迭代器遍历集合的简化写法

//案例
package ww.com.bean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Scanner;

public class Test {
    public static void main(String[] args)  {
        Collection<String> c = new ArrayList<>();
        c.add("赵敏");
        c.add("小昭");
        c.add("素素");
        c.add("灭绝");
        for (String s:c){
            System.out.println(s);
        }
    }
}


//案例遍历数组
package ww.com.bean;

public class Test {
    public static void main(String[] args)  {
        String[] names = {"迪丽热巴","古力娜扎"};
        for (String name : names) {
            System.out.println(name);
        }
    }
}

Lambda

Lambda表达式遍历集合

得益于JDK8开始的新技术Lambda表达式,提供了一种更简单,更直接的方式来遍历集合

default void forEach(Consumer<? super T> action)结合lambda遍历集合

package ww.com.bean;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Scanner;
import java.util.function.Consumer;

public class Test {
    public static void main(String[] args)  {
        Collection<String> c = new ArrayList<>();
        c.add("赵敏");
        c.add("小昭");
        c.add("素素");
        c.add("灭绝");
        //结合匿名内部类进行遍历
//        c.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
        //集合lambda进行简化
        c.forEach( s-> System.out.println(s));
        //方法引用,前后的参数和携带名是一致的,而println是一个out对象的方法,所以可以使用::来进行代替
        c.forEach(System.out::println);
    }
}

案例

package ww.com.bean;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;

public class Test {
    public static void main(String[] args)  {
        Collection<Movie> movies = new ArrayList<>();
        movies.add(new Movie("《肖生客的救赎》" ,9.7,"罗兵斯"));
        movies.add(new Movie("《阿甘正传》" ,9.5,"汤姆 汉克斯"));
        movies.add(new Movie("《霸王别姬》" ,9.5,"张国荣"));
        

        //第二种方式
//        for (Movie movie : movies) {
//            System.out.println("电影名称是"+movie.getName());
//            System.out.println("电影评分是"+movie.getScore());
//            System.out.println("电影主演是"+movie.getScore());
//            System.out.println("---------------------------");
//        }

        //第三种方式
//        movies.forEach( movie->  {
//            System.out.println("电影名称是"+movie.getName());
//            System.out.println("电影评分是"+movie.getScore());
//            System.out.println("电影主演是"+movie.getActor());
//            System.out.println("---------------------------");
//        });
    }
}

List集合

list集合中的特有方法

package ww.com.bean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Test {
    public static void main(String[] args)  {
        List<String> list = new ArrayList<>();
        list.add("蜘蛛精");
        list.add("至尊宝");
        list.add("至尊宝");
        list.add("牛夫人");
        System.out.println(list);

        //1.在某个索引位置处插入元素
        list.add(2,"紫霞仙子");
        System.out.println(list);
        //2.根据索引删除元素,返回被删除元素
        String remove = list.remove(2);
        System.out.println(remove);
        //3.根据索引返回集合中指定位置的元素
        System.out.println(list.get(3));
        //4. 修改某个元素处的元素,修改成功后返回原来的数据
        System.out.println(list.set(3, "牛魔王"));
        System.out.println(list);
    }
}

ArrayList

ArrayList集合的特点

​ 1.基于数组实现的

​ 2.查询速度快

​ 3.删除效率低:可能需要把后面的很多数据进行前移

​ 4.添加效率极低:可能需要把后面很多的数据后移,再添加元素,或者也可能需要进行数组的扩容

ArrayList集合底层逻辑

1.利用无参数构造器创建的集合,会在底层创建一个默认长度为0的数组

2.添加第一个元素时,底层会创建一个新的长度为10的数组

3.存满时,会扩容1.5倍

4.如果依次添加多个元素,1.5倍还放不下,则新创建的数组的长度以实际为准

LinkedList

基于双链表实现的

什么是链表呢,有啥特点

链表中的结点是独立的对象,在内存中是不连续的,每个节点包含数据值和下一个结点的地址

链表的特点1

查询慢,无论查询那个数据都要从头开始找

链表的特点2:链表增删相对较快

LinkedList集合的底层逻辑

基于双链表实现的

特点

​ 1.查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的

​ LinkedList新增了:很多首尾操作的特有方法

public void addFirst(E e) //在该列表开头中插入指定的元素
public void addLast(E e)  //将指定的元素追加到此列表的末尾
public E getFirst()       //返回此列表中的第一个元素
public E getLast          //返回列表中的最后一个元素
public E removeFirst()    //从此列表中删除并返回第一个元素
public E removeLast()     //从此例表中删除并返回最后一个元素

LinkedList的应用场景之一:可以用来设计队列,-----------------先进先出后进后出

LinkedList的应用场景之一:可以用来设计栈---------------------后进先出,先进后出

Set集合

Set系列集合特点:无序 添加数据的顺序和获取出的数据顺序不一致,不重复,无索引

java中的所有对象,都可以调用Object类提供的hashCode方法,返回该对象自己的一个致

public int hashCode():返回对象的哈希值

同一个对象多次调用hashCode()方法返回的哈希值是相同的

不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)

HashSet集合的底层原理

  • 基于哈希表实现
  • 哈希表是一种增删改查数据,性能都比较好的数据结构

哈希表

JDK8之前,哈希表=数组+链表

JDK8开始,哈希表=数组+链表+红黑树

JDK8之前使用

  1. 使用一个默认长度为16的数组,默认加载因子为0.75,数组名为table
  2. 使用元素的哈希值对数组的长度求余计算出应该存入的位置
  3. 判断当前位置是否为null,如果是null直接存入
  4. 如果不为null,表示有元素,则调用equals方法比较相等,则不存,不相等,则存入数组,JDK8之前,新元素存入数组,占老元素位置,老元素挂下面
    • JDK8开始之后,新元素直接挂在老元素下面

JDK8开始,当链表长度超过8,且数组长度>=64时,自动将链表转成红黑树

重点--比较两个对象是否相等需要重写HashCode方法和equals方法

LinkedHashSet

特点

有序,不重复,无索引

LinkedHashSet底层原理

  • 依然是基于哈希表(数组,链表,红黑树)实现的.
  • 但是,他的每个元素都额外的多了一个双链表的机制记录它前后元素的位置

TreeSet集合

特点

  • 不重复,无索引,可排序(默认升序排列,按照元素的大小,由小到大排序)
  • 底层是基于红黑树实现的排序

注意

  1. 对于数值类型:Integer,Double,默认按照数值本身的大小进行升序排序
  2. 对于字符串类型,默认按照首字符的编号升序排列
  3. 对于自定义类型如Student对象,TreeSet默认是无法直接排序的

对于自定义的类,想要实现排序的话有两种方式

  1. 让自定义的类(如学生类),实现Comparable接口,重写里面的CompareTo方法来指定比较规则

    //Student对象,实现Comparable接口,重写CompareTo方法来指定比较规则
    package ww.com.bean;
    
    public class Student implements Comparable<Student> {
        private String name;
        private int age;
        private double height;
    
        public Student() {
        }
    
        public Student(String name, int age, double height) {
            this.name = name;
            this.age = age;
            this.height = height;
        }
    
        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;
        }
    
        public double getHeight() {
            return height;
        }
    
        public void setHeight(double height) {
            this.height = height;
        }
    
        @Override
        public int compareTo(Student o) {
            return this.age-o.age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", height=" + height +
                    '}';
        }
    }
    //主函数的实现
    package ww.com.bean;
    
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Test {
        public static void main(String[] args)  {
            Set<Student> set1 = new TreeSet<>();
            set1.add(new Student("蜘蛛精",13,167.8));
            set1.add(new Student("至尊宝",14,167.1));
            set1.add(new Student("紫霞",15,167.2));
            System.out.println(set1);
        }
    }
    
    
  2. 通过调用TreeSet集合有参数的构造器,可以设置Comparator对象(比较器对象,用于指定比较规则)

    package ww.com.bean;
    import java.util.Comparator;
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Test {
        public static void main(String[] args)  {
            Set<Student> set1 = new TreeSet<>((o1,o2)->  Double.compare(o1.getHeight(), o2.getHeight())
            );
            set1.add(new Student("蜘蛛精",13,167.8));
            set1.add(new Student("至尊宝",14,167.1));
            set1.add(new Student("紫霞",15,167.2));
            System.out.println(set1);
    
        }
    }
    
    

    常用使用方法

    1. 如果希望记住元素的顺序,需要存储重复的元素,又要频繁的根据索引查询数据(用ArrayList(有序,可重复,有索引),底层是基于数组的.)

    2. 如果希望记住元素的添加顺序,且增删首尾数据的情况较多?(用LinkedList集合(有序,可重复,有索引)),底层基于双链表实现的

    3. 如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?(用HashSet集合()无序,不重复,无索引),底层基于哈希表实现的(常用)

    4. 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删该查都快(用LinkedHashList集合(有序,不重复,无索引))底层基于哈希表和双链表

    5. 如果要对元素进行排序,也没有重复元素需要存储,且希望增删改查都快?(用TreeSet集合,基于红黑树实现)

      集合中出现的问题

      怎么保证遍历集合同时删除数据时不出bug?

      使用迭代器遍历集合,但用迭代器自己删除方法删除数据即可

      如果能用for循环遍历时,可以倒着遍历,但删除元素后需要做i--操作

可变参数

  • 可变参数就是一种特殊形参,定义在方法,构造器的形参列表里,格式是:数据类型...参数名称

可变参数的特点和好处

  • 特点:可以不传数据给它,可以传一个或者同时传多个数据给它,也可以传一个数组给它
  • 好处:常常用来灵活的接收数据

可变参数的注意事项

  • 可变参数在方法内部就是一个数组
  • 一个形参列表中可变参数只能有一个
  • 可变参数必须放在形参列表的最后面

Collections

  • 是一个用来操作集合的工具类

Collections提供的常用静态方法

public static <T> boolean addAll(Collection<? super T>c,T...elements)-----------给集合添加元素
public static void shuffle(List<?> list)-----------打乱list集合中的元素顺序
public static <T> void sort(List<T> list)
-------------------对list集合中的元素进行升序排列
public static <T> void sort(List<T> list,Comparator<? super T> c)--------------对List集合中元素,按照比较器对象指定的规则来进行比较

Collections只能支持对List集合进行排序

public static void sort(List list)对List集合中,就按照默认规则排序

排序方式2

public static void sort(List list,Comparator<? super T> c)对List集合中元素,按照比较器对象的规则来进行排序

Map集合

  • Map集合称为双列集合,格式:{key1=value1,key2=value2,key3=value3,...}一次需要存入一对数据做为一个元素

  • Map集合的每个元素key=value称为一个键值对/键值对对象/一个Enyry对象,Map集合也被叫做"键值对集合"

  • Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值

Map集合体系的特点

注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

  • HashMap(由键决定特点):无序,不重复,无索引(用的最多)
  • LinkedHashMap(由键决定特点):由键决定的特点:有序,不重复,无索引
  • TreeMap(由键决定特点):按照大小默认升序排序,不重复,无索引
//1.添加元素:无序,不重复,无索引
public static void put()
//2.获取集合的大小
public int size()
//3.清空集合
public void clear()
//4.判断集合是否为空,为空返回true,反之
public boolean isEmpty()
//5.根据键获取对应值
public V get(Object key)
//6.根据键删除整个元素(删除键会返回键的值)
public V remove(Object key)
//7.判断是否包含某个值,包含返回true,反之
public boolean containsKey()
//8.判断是否包含某个值
public boolean containsValue(Object Value)
//9.获取Map集合的全部值
public Set<k> keySet()
//10.获取Map集合的全部值
public Collection <V> values()
//11.把其他Map集合的数据倒入到自己的集合中来
    map1.putAll(map2);

Map集合的遍历方式

//第一种方式----------------------使用keySet方法 
package ww.com.bean;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args)  {
        Map<String,Double> map = new HashMap<>();
        map.put("蜘蛛精", 162.5);
        map.put("紫霞", 169.8);
        map.put("牛魔王", 169.5);

        Set<String> keys = map.keySet();
        for (String key : keys) {
            Double value = map.get(key);
            System.out.println(key+"-----------"+value);
        }
    }
}
//第二种方式-----------------------------------使用entrySet方法
package ww.com.bean;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args)  {
        Map<String,Double> map = new HashMap<>();
        map.put("蜘蛛精", 162.5);
        map.put("紫霞", 169.8);
        map.put("牛魔王", 169.5);

        Set<Map.Entry<String, Double>> entries = map.entrySet();
        for (Map.Entry<String, Double> entry : entries) {
            String key = entry.getKey();
            Double value = entry.getValue();
            System.out.println(key+"-------"+value);
        }
    }
}
//第三种方式-----------------------使用Lambda表达式
package ww.com.bean;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args)  {
        Map<String,Double> map = new HashMap<>();
        map.put("蜘蛛精", 162.5);
        map.put("紫霞", 169.8);
        map.put("牛魔王", 169.5);

        map.forEach((k,v)-> System.out.println(k+"----"+v));
    }
}

HashMap底层是基于哈希表实现的

  • HashMap集合是一种增删改查数据,性能都比较好的集合
  • 但是它是无序,不能重复,没有索引支持的(由键决定特点)
  • HashMap的键依赖hashCode方法和equals方法保证键的唯一
  • 如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的

LinkedHashMap集合的原理

  • 底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外多了一个双链表的机制记录元素顺序(保证有序).实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap

TreeMap

  • 特点:不重复,无索引,可排序(按照键的大小默认升序排序,只能对键排序)
  • 原理:TreeMap跟TreeSet集合的底层原理都是一样的,都是基于红黑树的排序

TreeMap集合同样支持两种方式来指定排序规则

  • 让类实现Comparable接口,重写比较规则
  • TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则

集合的嵌套

  • 指的是集合中元素又是一个集合

Stream

  • 也叫做Stream流,是jdk8开始新增的一套API(java.uitl.stream)用于操作集合或数组的数据
  • 优势:Stream流大量集合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更加简洁,可读性更好

初次使用

package ww.com.bean;


import java.util.*;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args)  {
        List<String> names = new ArrayList<>();
        Collections.addAll(names, "张三分","张无忌","李白");

        Stream<String> stream = names.stream();
        stream.filter((s)->s.startsWith("张")).forEach((s)-> System.out.println(s));
    }
}



package ww.com.bean;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args)  {
        List<String> names = new ArrayList<>();
        Collections.addAll(names, "张三分","张无忌","李白");

        Stream<String> stream = names.stream();
        List<String> newList = stream.filter((s) -> s.startsWith("张")).filter(a -> a.length() == 3).collect(Collectors.toList());
        System.out.println(newList);
    }
}


Stream流的使用步骤

  • 获取Stream流-------Stream流代表了一条流水线,并能与数据源建立连接
  • 过滤,排序,去重-------调用流水线按的各种方法对数据进行处理,计算
  • 获得结果--------------获取处理的结果,遍历,统计,收集到一个新的集合中返回

获取Stream流

  • 获取集合的Stream流
  • default Stream stream()---------------------------------获取当前集合对象的Stream流

获取数组的Stream流

public static Stream stream(T[] array)-------------获取当前数组的Stream流

public static Stream of(T...values)-------------------获取当前数据的Stream流

案例说明

package ww.com.bean;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args)  {
        //1.如何通过集合获取到Stream流
       List<String> names = new ArrayList<>();
       Collections.addAll(names, "张三丰","张无忌","照明","张强");
        Stream<String> stream = names.stream();

        //2.如何获取Set集合中的Stream流
        Set<String> set = new HashSet<>();
        Collections.addAll(set,"刘德华","张曼玉","蜘蛛精","玛德");
        Stream<String> stream1 = set.stream();

        //3.如何获取Map集合的Stream流
        Map<String,Double> map = new HashMap<>();
        map.put("古力娜扎", 172.3);
        map.put("迪丽热巴", 168.3);
        map.put("马儿扎哈", 166.3);
        Set<Map.Entry<String, Double>> entries = map.entrySet();
        Stream<Map.Entry<String, Double>> stream2 = entries.stream();
        stream2.filter( k-> k.getKey()=="迪丽热巴").forEach(s-> System.out.println(s));

        //4.如何获取数组中的Stream流
        String[] name2 = {"不知道","刘宇航","高三傻"};
        Stream<String> stream3 = Arrays.stream(name2);
    }
}

中间方法

Stream<T> filter(Predicate<super T> predicate)-------对于流中的数据进行过滤
Stream<T> sorted()-----------------------------------对元素进行升序排列
Stream<T> sorted(Comparator<? super T>comparator)----按照指定规则排序
Stream<T> limit(long maxSize)------------------------获取前几个元素
Stream<T> skip(long n)-------------------------------跳过前几个元素
Stream<T> distinct()---------------------------------去除流中重复的元素----------如果是自定义对象,需要重写hashCode方法和equals方法
<R> Stream<R> map(Function<? super T ? extends R> mapper)--对元素进行加工,并返回对应的新流
    static<T> Stream<T> concat(Stream a,Stream b)----合并a和b两个流为一个流对象
 
    
//案例介绍
package ww.com.bean;


import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args)  {
       List<Double> scores = new ArrayList<>();
       Collections.addAll(scores, 88.5,100.0,60.0,99.0,9.5,99.6,25.0);
        Stream<Double> stream = scores.stream();
        //需求一:找出成绩大于60的数据,先升序排序之后再进行输出
        stream.filter(s->s>60).sorted().forEach(s-> System.out.println(s));
        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精",26,172.5);
        Student s2 = new Student("蜘蛛精",26,172.5);
        Student s3 = new Student("紫霞",23,167.6);
        Student s4 = new Student("白晶晶",25,169.0);
        Student s5 = new Student("牛魔王",35,183.3);
        Student s6 = new Student("牛夫人",34,168.5);
        Collections.addAll(students, s1,s2,s3,s4,s5,s6);
        //需求2:找出年龄大大于等于23,🐧且年龄小于等于30岁的学生,并按照年龄降序输出
        Stream<Student> stream1 = students.stream();
        stream1.filter(s->s.getAge()>=23&&s.getAge()<=30).sorted(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o2.getAge()-o1.getAge();
            }
        }).forEach(s-> System.out.println(s.getName()+"---------"+s.getAge()));
        //需求3:取出身高最高的三名学生,并输出
        Stream<Student> stream2 = students.stream();
        stream2.sorted(new Comparator<Student>() {
           @Override
           public int compare(Student o1, Student o2) {
               return Double.compare(o2.getHeight(), o1.getHeight());
           }
       }).limit(3).forEach(s-> System.out.println(s.getName()+"----------"+s.getHeight()));
        //需求4:取出身高倒数的两名学生,并进行输出
        Stream<Student> stream3 = students.stream();
        stream3.sorted(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o2.getHeight(), o1.getHeight());
            }
        }).skip(students.size()-2).forEach(s-> System.out.println(s.getName()+"-------------------"+s.getHeight()));
        //需求5:找出身高超过168的学生叫什么名字,需求去除重复的名字,再输出
        //这里如果是想要删除重复的值,就要重写hashCode方法和equals方法
        Stream<Student> stream4 = students.stream();
        stream4.filter(s->s.getHeight()>168).distinct().forEach(s-> System.out.println(s.getName()));
    }
}

终结方法

  • 中介方法指的是调用完成后,不会返回新的Stream了,没有办法继续使用流对象了
void forEach(Consumer action)-------------对此流运算后的元素执行遍历
long count()------------------------------统计此流运算后的元素个数
Optional<T> max(Comparator<? super T> comparator)------获取此流运算后的最大值元素
Optional<T> min(Comparator<? super T> comparator)------获取此流运算后的最小值元素
collect(Collectors.toList())可以将一个流转换为新的集合,然后输出
package ww.com.bean;


import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args)  {
        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精",26,172.5);
        Student s2 = new Student("蜘蛛精",26,172.5);
        Student s3 = new Student("紫霞",23,167.6);
        Student s4 = new Student("白晶晶",25,169.0);
        Student s5 = new Student("牛魔王",35,183.3);
        Student s6 = new Student("牛夫人",34,168.5);
        Collections.addAll(students, s1,s2,s3,s4,s5,s6);
        //需求1 请计算出身高超过168的学生有几个人
        System.out.println(students.stream().filter(s -> s.getHeight() > 168).count());
        //需求2:请找出身高最高的学生对象,并输出
        System.out.println(students.stream().max(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(), o2.getHeight());
            }
        }));
        //需求3 请找出身高最矮的学生对象并输出
        System.out.println(students.stream().min(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(), o2.getHeight());
            }
        }));
        //需求4:请找出身高超过170的学生对象,并把他们放置到一个新的集合里面
        List<Student> students1 = students.stream().filter(s -> s.getHeight() > 170).collect(Collectors.toList());
        System.out.println(students1);
        //需求5 请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合中去
        //下面加了一步distinect函数,目的是去除重复的对象,返回一个新的stream流对象
        Map<String, Double> collect = students.stream().filter(s -> s.getHeight() > 170).distinct().collect(Collectors.toMap(a -> a.getName(), a -> a.getHeight()));
        System.out.println(collect);

        //也可以将所有的对象转换为一个新的数组并输出
        Object[] objects = students.stream().filter(s -> s.getHeight() > 170).toArray();
        System.out.println(Arrays.toString(objects));
    }
}

期中测试题

//第一题囚犯解决问题
//第一次方法
package ww.com.bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
    public static List<People> peoples = new ArrayList<>();
    public static void main(String[] args)  {
        //定义一个集合将所有的囚犯都放进去

        Random r  = new Random();
        for (int i = 1; i <= 100; i++) {
            while (true) {
                int code = r.nextInt(200)+1;
                if(seekCode(code)){
                    peoples.add(new People(code,i));
                    break;
                }
            }
        }
        System.out.println(peoples);
        //成功生成囚犯数据
        while (peoples.size()>1){
            List<People> temPeoples = new ArrayList<>();
            for (int i = 1; i <peoples.size() ; i+=2) {
                People people = peoples.get(i);
                temPeoples.add(people);
            }
            peoples = temPeoples;
        }
        People luckPeople = peoples.get(0);
        System.out.println(luckPeople);
    }
    public static boolean seekCode(int code){
        for (People people : peoples) {
            if(people.getCode() == code){
                return false;
            }
        }
        return true;
    }
}
//第二次方法
package ww.com.bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
    public static void main(String[] args)  {
        //完成幸存者的案例
        List<Integer> peoples = new ArrayList<>();
        Random r = new Random();
        for (int i = 1; i <=100 ; i++) {
            int code = r.nextInt(200)+1;
            if(peoples.contains(code)){
                i--;
            }else{
                peoples.add(code);
            }
        }
        List<Integer> peoplesBak = new ArrayList<>();
        peoplesBak.addAll(peoples);
        while (peoples.size()>1){
            for (int i = peoples.size()%2 == 0?peoples.size()-2:peoples.size()-1; i >=0 ; i-=2) {
                peoples.remove(i);
            }
        }
        Integer code = peoples.get(0);
        System.out.println("幸存者编号"+code);
        int i = peoplesBak.indexOf(code);
        System.out.println("幸存者的位置是"+(i+1));
    }
}

第二题
String userStrs = "10001:张三:男:1990-01-01#10002:李四:女:1989-01-09#10003:王五:男:1999-09-09";
        List<User> users = new ArrayList<>();
        String[] userArray = userStrs.split("#");
        for (String userStr : userArray) {
            User user = new User();
            String[] split2 = userStr.split(":");
            user.setId(Long.valueOf(split2[0]));
            user.setGender(split2[2]);
            user.setBirthday(LocalDate.parse(split2[3]));
            //把这个用户存入到集合中去
            users.add(user);

        }
        System.out.println(users);
        System.out.println("----------------------------------------------");
//第三题-------高考倒计时-=-----------------自己写的
package ww.com.bean;


import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test {
    public static void main(String[] args)  {

        LocalDateTime endData = LocalDateTime.of(2024, 6, 7, 8, 0);
        LocalDate endDateDay = LocalDate.of(2024, 6, 7);
        DateTimeFormatter distance = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        String endTime = distance.format(endDateDay);
        int weekDay = endData.getDayOfWeek().getValue();
        System.out.println("==========2024年高考成绩倒计时===============");
        System.out.println("==========="+endData.getYear()+"年高考时间:"+endTime+weekDay+"============");
        System.out.println("===========现在距离"+endData.getYear()+"年高考还有============");
        while (true) {
            LocalDateTime currentData = LocalDateTime.now();

            Duration duration = Duration.between(currentData, endData);
            long day = duration.toDays();
            long hour = duration.toHoursPart();
            long minutes = duration.toMinutesPart();
            long seconds = duration.toSecondsPart();
            try {
                Thread.sleep(1000);

                System.out.println("==========="+day+"天"+hour+"时"+minutes+"分"+seconds+"秒=============");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }


    }
}
//跟着老师写的
package ww.com.bean.Timer;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimerTask;


//继承TimerTask实现run 方法
public class TimeTask extends TimerTask {
    private LocalDateTime startTime;

    //构造器,对高考时间进行初始化
    public TimeTask(){
        String s = "2024-06-07 09:00:00";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        startTime = LocalDateTime.parse(s, dtf);
        System.out.println("2024年高考倒计时");
        System.out.println("2024年高考时间 : 2024年06年07日"+"星期"+startTime.getDayOfWeek().getValue());
    }
    //每一秒执行一次该方法
    @Override
    public void run() {
        //拿到当前时间
        LocalDateTime now = LocalDateTime.now();
        Duration between = Duration.between(now, startTime);
    System.out.println(between.toDays()+"天"+between.toHoursPart()+"时"+between.toMinutesPart()+"分"+between.toSecondsPart()+"秒");
    }
}

//主函数方法区
package ww.com.bean.Timer;

import java.util.Timer;

public class Test {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //可以做到一秒执行一次,0代表起始时间,1000代表1秒执行一次
        timer.schedule(new TimeTask(), 0,1000);
    }
}

//第五题,二分查找算法------------------------------跟着老师来写
package ww.com.bean.demo5;

public class Test {
    public static void main(String[] args) {
        int[] nums = {5,7,7,7,8,8,9};
        int target = 7;
        int leftIndex = getLeftIndex(nums, target);
        int rightIndex = getRightIndex(nums, target);
        System.out.println(leftIndex+"======"+rightIndex);
    }
    public static int getLeftIndex(int[] nums,int target){
        int start = 0;
        int end = nums.length-1;
        int rs = -1;
        while (start<=end){
            int middle = (start+end)/2;
            if(target>nums[middle]){
                start = middle+1;
            }else if(target<nums[middle]){
                end = middle-1;
            }else{
                //找到这个数据出现在middle
                rs = middle;
                //继续二分查找往左边找
                end = middle-1;
            }
        }
        return rs;
    }
    public static int getRightIndex(int[] nums,int target){
        int start = 0;
        int end = nums.length-1;
        int rs = -1;
        while (start<=end){
            int middle = (start+end)/2;
            if(target>nums[middle]){
                start = middle+1;
            }else if(target<nums[middle]){
                end = middle-11;
            }else{
                //找到这个数据出现在middle
                rs = middle;
                //继续二分查找往左边找
                start = middle+1;
            }
        }
        return rs;
    }
}

FIle---IO流

  • File:代表文本
  • IO流:读写数据

File的初次使用

package ww.com.bean.File;

import java.io.File;

public class Demo1 {
    public static void main(String[] args) {
        File file = new File("C:\\Users\\浩劫\\Desktop\\git.txt");
        //获取文件的名字
        String name = file.getName();
        //获取文件的大小
        long length = file.length();
        System.out.println("文件名字"+name+",文件大小是"+length);
        //路径分隔符的形式
        //第一种=============\\两个反斜杠代表的就是路径分隔符的意思
        //第二种=============/一个斜杠代表的也是路径分隔符
        //第三种=============File.separator代表的就是路径分隔符,这里是一种通用解决办法,可以解决任何的操作系统
        File file1 = new File("C:"+File.separator+"Users"+File.separator+"浩劫"+File.separator+"Desktop"+File.separator+"git.txt");
        System.out.println(file1);

        //注意:File对象可以指代一个不存在的文件路径
        File f3 = new File("D:/resource/aaaa.txt");
        System.out.println(f3.length());
        System.out.println(f3.exists());//这个方法是判断是否有这个文件的

        //相对路径
        File f4 = new File("java_hello\\src\\ww\\com\\bean\\File\\itheima.txt");
        System.out.println(f4.length());
    }
}

File常见的方法使用

package ww.com.bean.File;

import java.io.File;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.logging.SimpleFormatter;

public class Demo1 {
    public static void main(String[] args) {
        //1.创建文件脆响,指代某个文件
        File f1 = new File("C:\\Users\\浩劫\\Desktop\\git.txt");
        //2.public boolean exists.判断当前对象,指定文件路径是否存在,存在返回true
        System.out.println(f1.exists());
        //3.public boolean isFile()判断当前对象指代的是否是文件,是文件返回true,反之
        System.out.println(f1.isFile());
        //4.public boolean isDirectory():判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之
        System.out.println(f1.isDirectory());
        //5.public String getName():获取文件名称(包含后缀)
        System.out.println(f1.getName());
        //6.public long length()获取文件大小,返回字节个数
        System.out.println(f1.length());
        //7.public long lastModified()获取文件最后修改时间
        System.out.println(f1.lastModified());
        long time = f1.lastModified();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        String format = sdf.format(time);
        System.out.println(format);
        //8.public String getPath();获取创建文件对象时,使用的绝对路径
        System.out.println(f1.getPath());
        //9.public String getAbsolutepath():获取绝对路径
        System.out.println(f1.getAbsolutePath());
    }
}

  • public boolean exists()-----------判断当前文件对象,对应的文件路径是否存在,存在返回true
  • public boolean isFile()------------判断当前文件对象指代的是否是文件,是文件返回true,反之
  • public boolean isDirectory()---判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之
  • public String getName()---------获取当前文件的名称(包含后缀)
  • public long length()---------------获取文件的大小,返回字节个数
  • public long lastModified()------获取文件最后的修改时间
  • public String getPath()----------获取创建文件对象时,使用的路径
  • public String getAbsolutepath()------获取绝对路径

创建文件和删除文件对应的方法

  • public boolean createNewFile()------创建一个新文件,若文件内容为空,能创建成功,返回true,反之返回false
  • public boolean mkdir():-------------用于创建文件夹,注意只能创建一级文件夹
  • public boolean mkdirs:用于创建文件夹,注意:可以创建多级文件夹
  • public boolean delete():删除文件,或者空文件,注意,不能删除非空文件夹
package ww.com.bean.File;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.logging.SimpleFormatter;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //创建文件成功
        File file = new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\File\\123.txt");
        //如果文件存在的话就不会创建了
        //public boolean createNewFile()------创建一个新文件,若文件内容为空,能创建成功,返回true,反之返回false
        System.out.println(file.createNewFile());
        //public boolean mkdir():-------------用于创建文件夹,注意只能创建一级文件夹
        File f2 = new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\File\\123");
        System.out.println(f2.mkdir());
        //public boolean mkdirs:用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\File\\123\\456");
        System.out.println(f3.mkdirs());
        //public boolean delete():删除文件,或者空文件,注意,不能删除非空文件夹
        System.out.println(f3.delete());
        System.out.println(file.delete());
        System.out.println(f2.delete());
    }
}

遍历文件夹的两种方式

  • 方式一---------第一种只是可以拿到当前文件夹下一级目录的名字
package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //遍历文件夹操作
        //1.public String[] list():获取当前目录下的所有的一级文件名称,到一个字符串数组中去
        File f1 = new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\Timer");
        String[] list = f1.list();
        for (String name : list) {
            System.out.println(name);
        }
    }
}

  • 方式二--------这一种是可以拿到当前目录下面的一级目录下面的文字
 //2.public File[] listFiles():重点:获取当前目录下面所有的一级文件对象到一个文件对象数组中去返回
        File f2 = new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\Timer");
        File[] files = f2.listFiles();
        for (File file : files) {
            System.out.println(file.getName());
        }
方法名称说明
public String[] list()获取当前目录下面所有的以及文件名称到一个字符串数组中去返回
public File[] listFiles()获取当前目录下面所有的一级文件对象到一个文件对象数组中去返回(重点)

使用listFiles方法时的注意事项

  • 当主调是文件,或者路径不存在时,返回null
  • 当主调时是文件夹是,返回一个长度为0的数组
  • 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放到File数组中返回
  • 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

更改文件夹名字

package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\大鹏教育学习\\前端\\精品小课\\纯原生前端技术打造仿小米电商网站视频千锋\\视频");
        File[] videos = file.listFiles();
        for (File video : videos) {
            String name = video.getName();
            String index = name.substring(9, name.indexOf(":"));
            String lastName = name.substring(name.indexOf(":"));
            //将名字重新拼装组合
            String newName = (index + lastName).substring(1);
            //修改文件夹中的名字
            video.renameTo(new File(file,newName));
        }
    }
}

方法递归

什么是方法递归?

  • 递归是一种算法,在程序设计语言中广泛使用
  • 从形式上说:方法调用自身的形式称为方法递归

递归的形式

  • 直接递归:方法自己调用自己
  • 间接递归:方法调用其他方法,其他方法又回调方法自己

使用方法递归时需要注意的问题

  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误
  • 下面的代码就是一个典型的递归算法
package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        System.out.println(f(5));
    }
    public static int f(int n){
        if(n==1){
            return 1;
        }else{
            return n*f(n-1);
        }
    }
}

递归三要素

  • 递归的公式:f(n) = f(n-1)*n
  • 递归的终结点:f(1)
  • 递归的方向必须走向终结点;
  • 重点其实就是,先退出然后返回,直到返回到最后一个

案例:猴子吃桃

package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
    //猴子吃桃的问题
        //f(10) = 1;
        //第二天的桃子等于第一天的桃子-吃掉的一半桃子再多吃一颗
        //f(x+1) = f(x)-f(x)/2-1;
        //2*f(x+1) = 2f(x)-f(x)-2;
        //f(x) = 2*f(x+1) +2;
        System.out.println(f(1));
    }

    public static int f(int x){
        if(x==10){
            return 1;
        }else{
            return 2*f(x+1)+2;
        }
    }
}

查找文件案例

package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //查找文件案例
        searchFile(new File("D:/"),"Photoshop.exe");

    }
    public static void searchFile(File dir,String fileName){
        //排除一切文件夹给的错误的情况
        if(dir.isFile()||dir==null||!dir.exists()){
            return;
        }
        File[] files = dir.listFiles();
        //判断这个文件夹对象是否为不为空,判断他的大小是否是0,如果是的话在继续
        if(files!=null||files.length>0){
            //遍历文件夹中所有的文件
            for (File file : files) {
                //判断当前是否是一个文件
                if(file.isFile()){
                    //如果是判断名字和给出的文件内容是否一样
                    if(file.getName().equals(fileName)){
                        System.out.println(file.getAbsolutePath());
                    }
                    //如果不是一个文件,则再次进入到文件夹里面继续
                }else{
                    searchFile(file, fileName);
                }
            }
        }
    }
}

删除非空文件夹

package ww.com.bean.File;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //删除非空文件夹
       deleteDir(new File("D:\\大鹏教育学习\\java-code\\java_hello\\src\\ww\\com\\bean\\feikong"));
    }
    public static void deleteDir(File dir){
        //判断当前文件夹是否不存在或者是否为空
        if(dir == null||!dir.exists()){
            return;
        }
        //判断这个是否是一个文件,如果是文件的话就会删除
        if(dir.isFile()){
            dir.delete();
            return;
        }
        //接下来知道是一个文件夹了
        File[] files = dir.listFiles();
        //判断files是否为空
        if(files==null){
            return;
        }
        //遍历文件夹下面的内容,如果是file的话,默认删除文件
        for (File file : files) {
            if(file.isFile()){
                file.delete();
            }
            //判断如果是文件夹的话再删一次
            else{
                deleteDir(file);
            }
        }
        //最后删除这个dir文件夹
        dir.delete();
    }
}

字符集