JavaSE

面向对象 OOP

什么是面向对象

面向对象本质:以类的方式组织代码,以对象的组织(封装)数据.

抽象

三大特征:

  • 封装
  • 继承
  • 多态

回顾方法的定义

break:跳出switch,结束循环

return:结束方法,返回一个结果

public class Demo01 {
    //修饰符  返回值类型  方法名(){
    //  方法体
    //  return 返回值;
    //}
    public String sayHello() {
        return "hello world";
    }
    // return 结束方法,返回一个结果
    public void hello() {
        return;
    }

    public int max(int a, int b) {
        return a > b ? a : b;//三元运算
    }

    public void readFile(String file)throws IOException{

    }

回顾方法的调用

public class Demo02 {
    //静态方法  static
    //非静态方法
    public static void main(String[] args) {
        //实例化这个类 new
        //对象类型  对象名字  =  对象值
        Student student = new Student();
//        student.say();

    }
public static void main(String[] args) {
        Demo03 demo03 = new Demo03();
        //实际参数和形式参数的类型要对应
        int add = demo03.add(1, 2);
        System.out.println(add);
    }

    public int add(int a, int b) {
        return a + b;

    }
public static void main(String[] args) {
        int a =1;
        System.out.println(a);

        Demo04.change(a);
        System.out.println(a);

    }
    //返回值为空
    public static void change(int a){
        a =10;
    }
public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);//null

        Demo05.change(person);
        System.out.println(person.name);//南子旭

    }

    public static void change(Person person) {
        //person是一个对象:指向的--->Person person = new Person();这是一个具体的人,可以改变属性!
        person.name = "南子旭";

    }

}

//定义了一个Person类.有一个属性
class Person {
    String name;
    String sex;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
//学生类
public class Student {

    public static void main(String[] args) {
        student1();

    }

    public static void student1() {
        student s = new student();

        s.setName("张三");
        s.setSex("男");

//        s.toString();
        System.out.println(s.getName() + s.getSex());
    }
        /* //方法
         public static void say(){
             System.out.println("学生说话了");
         }*/

}

类和对象的创建

//学生类
public class Student {

    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println(this.name+"在学习");
    }


    /*public static void main(String[] args) {
        //一个项目应该只存在一个main方法
        //类:是抽象的,实例化
        //类实例化后会返回一个自己的对象
        //student对象就是一个Student累的具体实例!
        Student student = new Student();
        Student xiaoming = new Student();

        xiaoming.name = "小明";
        xiaoming.age = 3;

        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);

        student.name = "小红";
        student.age = 3;

        System.out.println(student.name);
        System.out.println(student.age);
    }*/

构造器★

public class Person {
    //一个类即使什么都不写,它也会存在一个方法
    //显示的定义构造器

    String name;

    //实例化初始值
    //1.使用new关键字 本质实在调用构造器
    //用来初始化值
    public Person() {
        this.name = "南子旭";
    }


    //有参构造: 一旦定义了有参构造,无参构造就必须显示定义
    public Person(String name) {
        this.name = name;
    }

}
/*
    public static void main(String[] args) {
        //new 实例化了一个对象
        Person person = new Person();

        System.out.println(person.name);


    }
    构造器:
        1.和类名相同
        2.没有返回值
    作用:
        1.new 本质在调用构造器
        2.初始化对象的值
    注意点:
        1.定义了有参构造之后,如果想使用无参构造,显示的定义一个无参的构造

    快捷键生成构造器 Alt + Insert

*/

创建对象内存分析

public class Pet {
    public String name;
    public int age;

    //无参构造
    public void shout(){
        System.out.println("叫了一声");
    }
}
/*
 *
 *  public static void main(String[] args) {
 *         Pet dog = new Pet();
 *             dog.name = "旺财";
 *             dog.age = 3;
 *             dog.shout();
 *
 *         System.out.println(dog.name);
 *         System.out.println(dog.age);
 *     }
 *
 **/

简单小结与对象

public class Application {
    public static void main(String[] args) {
        /**
         * 1.类与对象
         *      类是一个模板:抽象,对象是一个具体的实例
         * 2.方法
         *      定义 & 调用
         * 3.对应的引用
         *      引用类型:基本数据类型
         *      对象是通过引用来操作的:  栈---->堆
         * 4.属性: 字段Field 成员变量
         *         默认初始化:
         *              数字: 0     0.0
         *              char:   u0000
         *              boolean:   false
         *              引用:  null
         *
         *      修饰符  属性类型  属性名  =  属性值 !
         * 5.对象的创建和使用
         *      - 必须使用new 关键字创造对象,构造器 Person nanzixu = new Person
         *      - 对象的属性 nanzixu.name
         *      - 对象的方法 nanzixu.student()
         * 6.类:
         *      静态的属性     属性
         *      动态的行为     方法
         */
    }
}

封装:属性私有,get/set

“高内聚,低耦合”

/**
 * 1.提高程序的安全性,保护数据
 * 2.隐藏代码的实现细节
 * 3.统一接口
 * 4.系统可维护性增加了
 * public class Application {
 * public static void main(String[] args) {
 * Student s1 = new Student();
 * <p>
 * s1.setName("南子旭");
 * System.out.println(s1.getName());
 * <p>
 * s1.setAge(119);
 * System.out.println(s1.getAge());
 * }
 * }
 */
//类
public class Student {

    //名字
    private String name;
    //学号
    private int id;
    //性别
    private char sex;
    private int age;

    //提供一些可以操作这个属性的方法!
    //提供一些public 的get set方法
    //get 获得这个数据
    public String getName() {
        return this.name;
    }

    //set 给这个数据设置值
    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 120 || age < 0) { //判断不合法
            age = 3;
        } else {
            this.age = age;
        }
    }
}

继承:extends

//Java中所有的类,都默认直接或者间接继承object
//Person 人 :  父类
public class Person {

    private int money = 1_0000_0000;

    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
import com.soft.demo01.Person;
import com.soft.demo01.Student;

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

//        Student student = new Student();
//        student.say();
//        student.setMoney(200);
//        System.out.println(student.getMoney());
        Person person = new Person();
//        person.

    }
}
import com.soft.demo01.Person;
import com.soft.demo01.Student;

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

//        Student student = new Student();
//        student.say();
//        student.setMoney(200);
//        System.out.println(student.getMoney());
        Person person = new Person();
//        person.

    }
}
//学生 is 人  : 派生类,子类
//子类继承了父类,就会拥有父类是的全部方法!
public class Student extends Person{
}
// 老师  is 人
public class Teacher extends Person{
}

super

注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super 必须只能出现在子类的方法或者构造方法中
  3. super 和this 不能同时调用构造方法

Vs this:

​ 代表的对象不同:

​ this: 本身调用者这个对象

​ super: 代表父类对象的引用

​ 前提

​ this: 没有继承也可以使用

​ super: 只能在继承条件下才可以使用

​ 构造方法:

​ this(): 本类的构造

​ super(): 父类的构造!

public class Person {
    public Person() {
        System.out.println("person无参执行了");
    }

    protected String name = "小南";

    public void print(){
        System.out.println("person");
    }
    
}
public class Student extends Person {
    public Student() {
        //隐藏代码:调用了父类的无参构造
        super();//调用父类的构造器,必须要在子类构造器的第一行
        System.out.println("student无参执行了");
    }

    private String name = "南子旭";

    public void print(){
        System.out.println("student");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }

    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }

}
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
//        student.test("南");
//        student.test1();
    }
}

方法重写:需要有继承关系,子类重写父类的方法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符 : 范围可以扩大 : public > protected > default > private
  4. 抛出异常 : 范围 : 可以被缩小,但不能被扩大; ClassNotFoundException --> Exception(大)

重写,子类的方法和父类必须一致 ; 方法体不同!

为什么需要重写:

  1. 父类的功能,子类不一定需要,或者不一定满足!

    Alt + Insert : override;

//重写都是方法的重写,和属性无关
public class B {
    public void test(){
        System.out.println("B=>test");
    }
}
//继承
public class A extends B{

    //Override : 重写
    @Override //注解 : 有功能的注释
    public void test() {
        System.out.println("A=>test");
    }
    //    public void test(){
//        System.out.println("A=>test");
//    }
}
public class Application {

    //静态的方法和非静态的方法区别很大!
    //静态方法 : //方法的调用只和左边定义的数据类型有关

    //非静态: 重写
    public static void main(String[] args) {


        A a = new A();
        a.test();

        //父类引用指向了子类
        B b = new A(); // 子类重写了父类的方法
        b.test();
    }
}

多态

多态注意事项:

  1. 多态是方法的多态,属性没有多态
  2. 父类和子类,有联系
  3. 存在条件: 继承关系,方法需要重写,父类引用指向子类对象! father f1 = new Son();
public class Person {
    public void run(){
        System.out.println("跑");
    }
}
public class Student extends Person{
    @Override
    public void run() {
        System.out.println("停");
    }
    public void eat(){
        System.out.println("吃");
    }
}
public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //new Student();


        //可以指向的引用类型就不确定了 : 父类的引用指向子类

        //Student 能调用的方法都是自己的或者继承父类的!
        Student s1 = new Student();
        // Person 父类型,可以指向子类,但是不能调用子类独有的方法
        Person s2 = new Student();
        Object s3 = new Student();

        //对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
        //s2.eat();
        //子类重写了父类的方法,执行子类的方法
        s1.run();


    }
}

instance of 和类型转换

public class Student extends Person{

    public void go(){
        System.out.println("go");
    }
}
/**
 * Object object = new Student();
 *         System.out.println(object instanceof Student);
 *         System.out.println(object instanceof Person);
 *         System.out.println(object instanceof Object);
 *         System.out.println(object instanceof Teacher);
 *         System.out.println(object instanceof String);
 *
 *         Person person = new Student();
 *         System.out.println(person instanceof Student);
 *         System.out.println(person instanceof Person);
 *         System.out.println(person instanceof Object);
 *         System.out.println(person instanceof Teacher);
 * //        System.out.println(person instanceof String); 编译报错
 *         Student student = new Student();
 *         System.out.println(student instanceof Student);
 *         System.out.println(student instanceof Person);
 *         System.out.println(student instanceof Object);
 * //        System.out.println(student instanceof Teacher);编译报错
 * //        System.out.println(student instanceof String);编译报错
 */
public static void main(String[] args) {
        //类型之间的转化: 父  子

        //高                    低
//        Person student = new Student();
//        student将这个对象转换为Student类型,我们就可以使用Student类型的方法了!
//        Student student1 = (Student) student;
//        student1.go();

        //子类转换为父类,可能会丢失自己的本来的一些方法!
        Student student = new Student();
        student.go();
        Person person = student;

    }
}
/*
    1.父类引用指向子类的对象
    2.把子类转换为父类,向上转型;
    3.把父类转换为子类,向下转型: 强制转换
    4.方便方法的调用,减少重复的代码!
 */

static关键字

静态导入包

//静态导入包
import static java.lang.Math.PI;
import static java.lang.Math.random;

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

        System.out.println(random());
        System.out.println(PI);

    }
}
//static
public class Student {
    private static int age; //静态的变量
    private double score;  //非静态变量

    public void run(){

    }
    public static void go(){

    }

    public static void main(String[] args) {

        Student s1 = new Student();

        System.out.println(Student.age);
//        System.out.println(Student.s);
        System.out.println(s1.age);
        System.out.println(s1.score);

    }
}
public class Person {
    //2:赋初值
    {
        System.out.println("匿名代码块");
    }
    //1
    static {
        //静态代码块,只执行一次
        System.out.println("静态代码块");
    }
    //3
    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = new Person();

    }
}

final关键字

主要用法有以下四种:

  1. 用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来 讲,我们必须在声明时或者构造方法中对它赋值;
  2. 用来修饰方法参数,表示在变量的生存期中它的值不能被改变;
  3. 修饰方法,表示该方法无法被重写;
  4. 修饰类,表示该类无法被继承。 上面的四种方法中,第三种和第四种方法需要谨慎使用,因为在大多数情况下,如果是仅仅为了一点设计上的考 虑,我们并不需要使用final来修饰方法和类。
public class Test1
{
     final static int a = 100;
     final int b;
     public Test1()
     {
         this.b = 2;
     }

    public static void main(String[] args)
    {
        //局部变量
        final int c = 10;
        //c = 20;
        final int d;
//        d = 2;
//        System.out.println(d);
//        d = 3;
        boolean flag = true;
        if(flag)
        {
            d = 10;
        }
        else
        {
            d = 20;
        }

        System.out.println(d);
    }
}
class Father
{
    public void say()
    {
        System.out.println("爸爸说:儿子,钱够花么?");
    }

    public final void hello()
    {
        System.out.println("爸爸天天笑哈哈");
    }
}
class Son extends  Father
{
    public void  say()
    {

    }

}
public class Test
{
    public static void main(String[] args)
    {
        Father f = new Father();
        f.hello();
        f.say();

        Father son = new Son();
        son.say();
        son.hello();

    }
}
class Student
{
    String name = "王五";

    public void say(final int x,final Student s)
    {
        //x = 10;
        //s = new Student();
        s.name = "田七";
    }
}

public class Test2
{
    public static void main(String[] args)
    {
       final Student s = new Student();
      // s = new Student(); 因为被final修饰后,地址不能改变
        //地址对应的内存空间中的数据还是可以改变的
       s.name = "张三";
       s.name = "李四";
    }
}

abstract 抽象类

//abstract 抽象类           extends: 单继承~      (接口可以多继承)
public abstract class Action {

    //约束~有人帮我们实现
    //abstract , 抽象方法只有方法名字 没有方法的实现
    public abstract void doSomething();

//    1.不能new这个抽象类,只能靠子类去实现它 :约束
//    2.抽象类中可以写普通的方法~
//    3.抽象方法必须在抽象类中~
//    抽象的抽象:约束
}
public class A extends Action{

    //抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非也是抽象类
    @Override
    public void doSomething() {

    }
}

接口的定义与实现 interface

作用:
    1. 约束
    2. 定义一些方法,让不同的人实现
    3. public abstract
    4. public static final
    5. 接口不能被实例化~ 接口中没有构造方法
    6. implements可以实现多个接口
    7. 必须要重写接口中的方法
// 抽象类:   extends
//类 可以实现接口  implements  接口
//实现了接口中的类,就需要重写接口中的方法~

//多继承~利用接口实现多继承
public class UserServiceImpl implements UserService,TimeService{

    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}
//interface 定义的关键字,接口都需要有实现类
public interface UserService {

    //接口中的所有定义的方法其实都是抽象的  public abstract

    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
public interface TimeService {
    void timer();
}

接口与抽象类的区别

语法层面上的区别

1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

N种内部类

public class Outer {

    private int id = 1;
    public void out(){
        System.out.println("这是外部类的方法");
    }

    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }

        //获得外部类的私有属性
        public void getID(){
            System.out.println(id);
        }
    }

}

枚举

public class EnumDemo{
public static void main(String[] args){
//直接引用
Day day =Day.MONDAY;
}
}
//定义枚举类型
enum Day{
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

编译器生成的 Values 方法与 ValueOf 方法

values()方法和valueOf(String name) 方法是编译器生成的 static方法,因此从前面的分析 中,在 Enum 类中并没出现 values() 方法,但 valueOf() 方法还是有出现的,只不过编译器生成的 valueOf() 方法需传递一个 name 参数,而 Enum 自带的静态方法 valueOf() 则需要传递两个方法,从前 面反编译后的代码可以看出,编译器生成的 valueOf() 方法最终还是调用了 Enum 类的valueOf 方法,下 面通过代码来演示这两个方法的作用:

Day[] days2 = Day.values();
System.out.println("day2:"+Arrays.toString(days2));
Day day = Day.valueOf("MONDAY");
System.out.println("day:"+day);
/**
输出结果:
day2:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
day

向enum类添加方法与自定义构造函数

public enum Day2{
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");//记住要用分号结束
private String desc;//中文描述
/**
* 私有构造,防止被外部调用
* @param desc
*/
private Day2(String desc){
this.desc=desc;
}
/**
* 定义方法,返回描述,跟常规类的定义没区别
* @return
*/
public String getDesc(){
return desc;
}
/**
* 覆盖
* @return
*/
@Override
public String toString(){
return desc;
}
    public static void main(String[] args){
for (Day2 day:Day2.values()){
System.out.println("name:"+day.name()+
",desc:"+day.getDesc());
}
}
/**
输出结果:
name:MONDAY,desc:星期一
name:TUESDAY,desc:星期二
name:WEDNESDAY,desc:星期三
name:THURSDAY,desc:星期四
name:FRIDAY,desc:星期五
name:SATURDAY,desc:星期六
name:SUNDAY,desc:星期日
*/
}

枚举与switch

enum Color{
GREEN,RED,BLUE
}
public class EnumDemo4{
public static void printName(Color color){
switch (color){
case BLUE: //无需使用Color进行引用
System.out.println("蓝色");
break;
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
        break;
}
}
public static void main(String[] args){
//调用
printName(Color.BLUE);
printName(Color.RED);
printName(Color.GREEN);
/*结果*/
//蓝色
//红色
//绿色
}
}

异常

Error和Exception

捕获和抛出异常

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

        try {
            new Test().test(1,0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }

        //假设要捕获多个异常: 从小到大!

/*
        try {//try监控区域
            if (b==0){   // throw throws
                throw new ArithmeticException();//主动抛出异常
            }


            System.out.println(a/b);


        }catch (Error e){ //catch(想要捕获的异常类型!) 捕获异常
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable e){
            System.out.println("Throwable");
        } finally { //处理善后工作
            System.out.println("finally");
        }
*/



    }

    //假设这个方法中,处理不了这个异常.方法上抛出异常
    public void test(int a,int b) throws ArithmeticException{
        if (b==0){   // throw throws
            throw new ArithmeticException();//主动抛出异常, 一般在方法中使用
        }
    }
}
public class Test2 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        //Ctrl + Alt + T
        try {
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace(); //打印错误的栈信息
        } finally {
        }

    }
}

常用类API

1.包装类

1.1、包装类概述

Byte b = new Byte((byte) 1);
Short s = new Short((short)1);
Integer i = new Integer(1);
Long l = new Long(1);
Float f = new Float(1.1);
Double d = new Double(1.1);
Boolean boo = new Boolean(true);
Character c = new Character('A');

或者使用valueOf()方法

Byte b = Byte.valueOf((byte)1);
Short s = Short.valueOf((short)1);
Integer i = Integer.valueOf(1);
Long l = Long.valueOf(1);
Float f = Float.valueOf(1.1f);
Double d = Double.valueOf(1.1);
Boolean boo = Boolean.valueOf(true);
Character c = Character.valueOf('A');

1.2、包装类的自动装箱、自动拆箱机制

在应用中我们经常需要进行基本类型数据和包装类对 象之间的互转。

Integer num1 = new Integer(1); //基本数据类型转为包装类
int num2 = num1.intValue(); //包装类型转为基本数据类型
System.out.println(num1 +" "+ num2);

而Java为了方便我们使用,以及出于其他目的如性能调优,给我们提供了自动装箱、拆箱机制。这种机制简化了基 本类型和包装类型的转换。

//1、包装类中的自动装箱拆箱机制
Integer num1 = 1; //自动装箱
int num2 = num1; //自动拆箱
System.out.println(num1 +" "+ num2);

2.String类

String类常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PsnOXSo-1618990152973)(JavaSE.assets/image-20201222171951020.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SBPJKWJP-1618990152978)(JavaSE.assets/image-20201222172037259.png)]

3.StringBuffer

String对象表示的是不可更改的字符串对象,如果需要修改String对象所表示的内容,必须重新创建一个对象.当修 改操作频繁,或字符串的值很大时,会额外分配大量内存 因此,Java语言引入了一个 StringBuffer类 ,用来表示 内容可以扩充和修改 字符串对象

StringBuffer dest = new StringBuffer("hello,world");

StringBuffer常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqU72mxN-1618990152982)(JavaSE.assets/image-20201222172311560.png)]

String拼接字符串所用时间

long begin = System.currentTimeMillis();
String s = "a";
for (int i = 0 ; i < 10000 ; i ++)
{
s += "b";
}
long end = System.currentTimeMillis();
long result = end - begin;
System.out.println("运行了:"+result);

StringBuffer拼接字符串所用时间

long begin = System.currentTimeMillis();
StringBuffer buffer = new StringBuffer("a");
for (int i = 0 ; i < 10000 ; i ++)
{
buffer.append("b");
}
long end = System.currentTimeMillis();
long result = end - begin;
System.out.println("运行了:"+result);

通过对比我们可以发现StringBuffer在运行上,明显要快很多。

4.StringBuilder

StringBuffer 与 StringBuilder中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用 了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安 全的。在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都 需要判断锁,效率相对更低。

三种字符串比较

  1. 三者在执行速度方面的比较:StringBuilder > StringBuffer > String
  2. StringBuilder:线程非安全的;StringBuffer:线程安全的
  3. 应用场景
    • 单线程操作字符串缓冲区 下操作大量数据用StringBuilder
    • 多线程操作字符串缓冲区 下操作大量数据用 StringBuffer
    • 如果要操作少量的数据用 String

5.Date

Date类表示日期和时间提供操纵日期和时间各组成部分的方法,Date类的最佳应用之一是获取当前系统时间获取 的当前系统时间是一个长整型数据Long。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EzNkT6hE-1618990152986)(JavaSE.assets/image-20201222172557795.png)]

6.SimpleDateFormat

将日期值(java.util.Date)转换成某种格式的字符串,将字符串转换成某种格式的日期。

6.1日期格式化模板标记

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vzjNjqv-1618990152990)(JavaSE.assets/image-20201222172645974.png)]

6.2SimpleDateFormat的常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drqQ1smm-1618990152991)(JavaSE.assets/image-20201222172707823.png)]

6.3parse()方法说明

parse():该方法是将指定格式的字符串转换成日期类型(java.util.Date)要转的字符串格式要和SimpleDateFromat() 构造方法中的参数的格式一致。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String strDate = "1999/09/09";
Date d = sdf.parse(strDate);
System.out.println(d);

6.4format()方法说明

可以将一个日期类型(java.util.Date)转换成某种格式的字符串类型,这种格式是通过SimpleDateFromat(“格式”)里 面的参数格式决定的。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = new Date();
String st = sdf.format(date);
System.out.println(st);

通过代码,我们发现format方法可以将Date对象转换成为规定好格式的字符串。

7.Calendar

Calendar是一个抽象类,提供了一个类方法getInstance(),以获得此类型的通用对象。 这个类通常可运用于日期类型的计算及日期特殊需求的处理。

7.1Calendar类常见属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5eGBYytk-1618990152995)(JavaSE.assets/image-20201222172833005.png)]

7.2Calendar类常见方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PPGLBCDz-1618990152997)(JavaSE.assets/image-20201222172906260.png)]

//代码如下,值得指出的是由于我们的时区设置是GMT+8,
// 所以打印格林威治时间得到的是1970-01-01 08:00:00.
Calendar cal = Calendar.getInstance();//得到当前时间
System.out.println(cal);
//重置时间
// cal.setTimeInMillis(0);
System.out.println(cal);
//获取值
int year = cal.get(Calendar.YEAR);//年
int month = cal.get(Calendar.MONTH) + 1;//月(必须要+1)
int date = cal.get(Calendar.DATE);//日
int hour = cal.get(Calendar.HOUR_OF_DAY);//时
int min = cal.get(Calendar.MINUTE);//分
int s = cal.get(Calendar.SECOND);//秒
int week = cal.get(Calendar.DAY_OF_WEEK);//星期(Locale.ENGLISH情况下,周日是1,剩下自己推
算)
//如果拿时间不是为了计算而是展示出来,肯定用SimpleDateFormart了,模式为yyyy-MM-dd HH:mm:ss
System.out.println(year +"/"+month+"/"+date+" "+hour+":"+min+":"+s+" 星期"+week);
//4、设置值
cal.set(2013, 5, 4, 13, 44, 51);//年月日时分秒(月份0代表1月)
cal.set(Calendar.YEAR, 2014);//年
cal.set(Calendar.MONTH, 7);//月(月份0代表1月)
cal.set(Calendar.DATE, 11);//日
cal.set(Calendar.HOUR_OF_DAY, 15);//时
cal.set(Calendar.MINUTE, 33);//分
cal.set(Calendar.SECOND, 32);//秒
//获取值
year = cal.get(Calendar.YEAR);//年
month = cal.get(Calendar.MONTH) + 1;//月(必须要+1)
date = cal.get(Calendar.DATE);//日
hour = cal.get(Calendar.HOUR_OF_DAY);//时
min = cal.get(Calendar.MINUTE);//分
s = cal.get(Calendar.SECOND);//秒
week = cal.get(Calendar.DAY_OF_WEEK);//星期(Locale.ENGLISH情况下,周日是1,剩下自己推算)
//如果拿时间不是为了计算而是展示出来,肯定用SimpleDateFormart了,模式为yyyy-MM-dd HH:mm:ss
System.out.println(year +"/"+month+"/"+date+" "+hour+":"+min+":"+s+" 星期"+week);
//5、运算值
cal.add(Calendar.YEAR, 1);//年
cal.add(Calendar.MONTH, 1);//月
cal.add(Calendar.DATE, 1);//日
cal.add(Calendar.HOUR_OF_DAY, -1);//时
cal.add(Calendar.MINUTE, 1);//分
cal.add(Calendar.SECOND, 1);//秒
cal.add(Calendar.DATE, 7);//周
//获取值
year = cal.get(Calendar.YEAR);//年
month = cal.get(Calendar.MONTH) + 1;//月(必须要+1)
date = cal.get(Calendar.DATE);//日
hour = cal.get(Calendar.HOUR_OF_DAY);//时
min = cal.get(Calendar.MINUTE);//分
s = cal.get(Calendar.SECOND);//秒
week = cal.get(Calendar.DAY_OF_WEEK);//星期(Locale.ENGLISH情况下,周日是1,剩下自己推算)
//如果拿时间不是为了计算而是展示出来,肯定用SimpleDateFormart了,模式为yyyy-MM-dd HH:mm:ss
System.out.println(year +"/"+month+"/"+date+" "+hour+":"+min+":"+s+" 星期"+week);

8.BigDecimal

Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高精 度计算.

其中 BigInteger 类是针对大整数的处理类,而 BigDecimal 类则是针对大小数的处理类.

BigDecimal 类的实现用到了 BigInteger类,不同的是 BigDecimal 加入了小数的概念.

float和Double只能用来 做科学计算或者是工程计算;在商业计算中,对数字精度要求较高,必须使用 BigInteger 类和 BigDecimal 类,它支持任 何精度的定点数,可以用它来精确计算货币值。

8.1、构造BigDecimal 对象常用方法

1、方法一
BigDecimal BigDecimal(double d); //不允许使用
2、方法二
BigDecimal BigDecimal(String s); //常用,推荐使用
3、方法三
static BigDecimal valueOf(double d); //常用,推荐使用

注意:

  1. double 参数的构造方法,不允许使用!!!因为它不能精确的得到相应的值,值会变大;
  2. String 构造方法 是完全可预知的: 写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的0.1; 因此,通常建议优 先使用 String 构造方法;
  3. 静态方法 valueOf(double val) 内部实现,仍是将 double 类型转为 String 类型; 这通常是将 double(或float)转化为 BigDecimal 的首选方法;
double d1 = 0.10334;
double d2 = 1234.0;
System.out.println("new BigDecimal("+d1+")=" + new BigDecimal(d1)); //此种方式绝对不允!!!!!
System.out.println("new BigDecimal("+d2+")=" + new BigDecimal(d2)); //此种方式绝对不允!!!!!
System.out.println("");
System.out.println("new BigDecimal(String.valueOf("+d1+"))=" + new
BigDecimal(String.valueOf(d1)));
System.out.println("new BigDecimal(String.valueOf("+d2+"))=" + new
BigDecimal(String.valueOf(d2)));
System.out.println("");
System.out.println("new BigDecimal(String.valueOf("+d1+"))=" + new
BigDecimal(Double.toString(d1)));
System.out.println("new BigDecimal(String.valueOf("+d2+"))=" + new
BigDecimal(Double.toString(d2)));
System.out.println("");
System.out.println("BigDecimal.valueOf("+d1+")=" + BigDecimal.valueOf(d1));
System.out.println("BigDecimal.valueOf("+d2+")=" + BigDecimal.valueOf(d2));
System.out.println("");
BigDecimal b1 = BigDecimal.valueOf(1);
BigDecimal b2 = BigDecimal.valueOf(1.00000);
System.out.println(b1.equals(b2));

输出如下:

new BigDecimal(0.10334)=0.10334000000000000130118138486068346537649631500244140625
new BigDecimal(1234.0)=1234
new BigDecimal(String.valueOf(0.10334))=0.10334
new BigDecimal(String.valueOf(1234.0))=1234.0
new BigDecimal(String.valueOf(0.10334))=0.10334
new BigDecimal(String.valueOf(1234.0))=1234.0
BigDecimal.valueOf(0.10334)=0.10334
BigDecimal.valueOf(1234.0)=1234.0
false

通过代码,我们发现 BigDecimal BigDecimal(double d) 构造方法会使值变大

8.2BigDecimal保留小数位

BigDecimal decimal = new BigDecimal("1.12345");
System.out.println(decimal);
BigDecimal setScale = decimal.setScale(4,BigDecimal.ROUND_HALF_DOWN);
System.out.println(setScale);
BigDecimal setScale1 = decimal.setScale(4,BigDecimal.ROUND_HALF_UP);
System.out.println(setScale1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JbuExb2-1618990152999)(JavaSE.assets/image-20201222173406083.png)]

参数定义
ROUND_CEILING
Rounding mode to round towards positive infinity.
向正无穷方向舍入
ROUND_DOWN
Rounding mode to round towards zero.
向零方向舍入
ROUND_FLOOR
Rounding mode to round towards negative infinity.
向负无穷方向舍入
ROUND_HALF_DOWN
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in
which case round down.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
ROUND_HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in
which case, round towards the even neighbor.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP ,
如果是偶数,使用ROUND_HALF_DOWN
ROUND_HALF_UP
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in
which case round up.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6
    ROUND_UNNECESSARY
Rounding mode to assert that the requested operation has an exact result, hence no rounding is
necessary.
计算结果是精确的,不需要舍入模式
ROUND_UP
Rounding mode to round away from zero.
向远离0的方向舍入

8.3提供精确的浮点数运算(包括加、减、乘、除、四舍五入)的工具类源码

public class ArithUtil {
// 除法运算默认精度
private static final int DEF_DIV_SCALE = 10;
private ArithUtil() {
}
/**
* 精确加法
*/
public static double add(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.add(b2).doubleValue();
}
/**
* 精确减法
*/
public static double sub(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.subtract(b2).doubleValue();
}
/**
* 精确乘法
*/
public static double mul(double value1, double value2) {
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
return b1.multiply(b2).doubleValue();
}
/**
* 精确除法 使用默认精度
*/
public static double div(double value1, double value2) throws IllegalAccessException {
    return div(value1, value2, DEF_DIV_SCALE);
}
/**
* 精确除法
* @param scale 精度
*/
public static double div(double value1, double value2, int scale) throws
IllegalAccessException {
if(scale < 0) {
throw new IllegalAccessException("精确度不能小于0");
}
BigDecimal b1 = BigDecimal.valueOf(value1);
BigDecimal b2 = BigDecimal.valueOf(value2);
// return b1.divide(b2, scale).doubleValue();
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 四舍五入
* @param scale 小数点后保留几位
*/
public static double round(double v, int scale) throws IllegalAccessException {
return div(v, 1, scale);
}
/**
* 比较大小
*/
public static boolean equalTo(BigDecimal b1, BigDecimal b2) {
if(b1 == null || b2 == null) {
return false;
}
return 0 == b1.compareTo(b2);
}
public static void main(String[] args) throws IllegalAccessException {
double value1=1.2345678912311;
double value2=9.1234567890123;
BigDecimal value3=new BigDecimal(Double.toString(value1));
BigDecimal value4=new BigDecimal(Double.toString(value2));
System.out.println("精确加法================="+ArithUtil.add(value1, value2));
System.out.println("精确减法================="+ArithUtil.sub(value1, value2));
System.out.println("精确乘法================="+ArithUtil.mul(value1, value2));
System.out.println("精确除法 使用默认精度 ================="+ArithUtil.div(value1,
value2));
System.out.println("精确除法 设置精度================="+ArithUtil.div(value1,
value2,20));
System.out.println("四舍五入 小数点后保留几位 ================="+ArithUtil.round(value1,
10));
System.out.println("比较大小 ================="+ArithUtil.equalTo(value3, value4));
}
}

9.Math

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1h5dsxG-1618990153002)(JavaSE.assets/image-20201222173541233.png)]

10.Random

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NvsuK6EU-1618990153004)(JavaSE.assets/image-20201222173547040.png)]

11.System

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7QAPTcX-1618990153005)(JavaSE.assets/image-20201222173601520.png)]

集合框架

单列集合 Collection

List

/**
 * List特点:
 *  1存储单个元素
 *  2、有下标(有序--有序指存入顺序和取出顺序一致)
 *  3、可重复
 */
ArrayList
public class ListDemo {

    /**
     * ArrayList:
     *          底层原理:扩容机制了解即可。自己业务程序无序操作
     *          初始容量: 10
     *          扩容机制(自动扩容):扩容规则:原始容量+原始容量/2  扩至原容量的1.5倍
     *  特点:
     *
     *     1  存储单个元素
     *  *  2、有下标(有序--有序指存入顺序和取出顺序一致)
     *  *  3、可重复
     *
     *     4、底层机制(数据结构):动态数组存储结构(扩容1.5倍);
     *           特点:取数据,性能高;更新(插入和删除)数据 ,性能低
     */
    
    public  void testArraylist(){
        //泛型指定  可以规定 存储元素的数据类型
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        //添加  存储元素
        arrayList1.add(10);
        arrayList1.add(60);
        arrayList1.add(50);
        
        //插入
        // arrayList1.add(1,70);
        
        //修改
        //arrayList1.set(3,100);
        //arrayList1.remove(Integer.valueOf(100)); //删除元素
        //arrayList1.remove(5);//删某个下标指定的元素
        
        // 集合合并
        /* ArrayList<Integer> arrayList2 = new ArrayList<>();
        arrayList2.add(100);
        arrayList2.add(600);
        arrayList2.add(500);
        arrayList1.addAll(arrayList2);*/ 
        
        // 判断是否包含某个元素
        if(arrayList1.contains(500)){
            System.out.println("包含");
        }
        
        // subList(int fromIndex, int toIndex)  arrayList截取
        /*List<Integer> listNew = arrayList1.subList(1, 4);// 包头不包尾
        listNew.forEach(v -> System.out.println(v));*/
        
        //面试问题 集合和数组怎么相互转换
        Object[] objects2 = arrayList1.toArray();//集合转数组
        System.out.println(Arrays.toString(objects2));

        Integer[] nums = {10,60,50};
        List<Integer> list = Arrays.asList(nums);//数组转集合
        
        //取单个元素
        Integer num1 = arrayList1.get(0);//取第一个元素
        System.out.println(num1);
        
        //取所有元素
        //取值方式1
        System.out.println(arrayList1.size());//size() 取得是存储元素的个数  思路:循环所有的下标 根据下标取值
        for(int i=0; i<arrayList1.size(); i++){
            System.out.println(arrayList1.get(i));
        }
        //取值方式2 增强型for循环  思路:不关心下标   循环找值 jdk1.5之后 引进
        for(Integer num:arrayList1){
            System.out.println(num);
        }
        //取值方式3 迭代器
        Iterator<Integer> iterator = arrayList1.iterator();
        while (iterator.hasNext()){//hasNext 判断是否找到元素   找到返回True  找不到返回fase
            Integer num = iterator.next();//next() 获取元素

            System.out.println(num);
        }
        //取值方式4 jdk1.8 提供的方法 forEach()
        arrayList1.forEach(v -> System.out.println(v));
        
    }
public void testArrayList2(){
            List<Student>  stus = new ArrayList<>();

            Student stu1 = new Student();
            stu1.setSno("1001");
            stu1.setName("小红");
            stu1.setAge(10);
            stu1.setSex("男");

            Student stu2 = new Student();
            stu2.setSno("1002");
            stu2.setName("小红2");
            stu2.setAge(10);
            stu2.setSex("男");

            Student stu3 = new Student();
            stu3.setSno("1003");
            stu3.setName("小红3");
            stu3.setAge(10);
            stu3.setSex("男");


            //把学生 放进集合容器
            stus.add(stu1);
            stus.add(stu2);
            stus.add(stu3);



            //查询学生信息
           /* for(Student stu:stus){
                System.out.println(stu.getSno()+"=="+stu.getName()+"=="+stu.getSex());
            }*/

        Iterator<Student> iterator = stus.iterator();
            while (iterator.hasNext()){

                //next() 指针滑动   要求每次循环只能指针滑动一次
               // System.out.println(iterator.next().getSno()+"=="+iterator.next().getName());  会发生NoSuchElementException

                Student stu = iterator.next();
                System.out.println(stu.getSno()+stu.getName());
            }
    }
public class Student {

    private  String sno;
    private  String name;
    private  String sex;
    private  Integer age;

    public String getSno() {
        return sno;
    }

    public void setSno(String sno) {
        this.sno = sno;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
ArrayList练习题
/*
1.	使用迭代(迭代即循环处理)的方式 进行屏幕输入字符或数字,输入内容保存在 ArrayList中,直到输入#end结束输入,将ArrayList中的内容迭代输出,2种方式,
要求1  输入的内容不能重复,如果ArrayList已经包含输入的内容,提示“已经包含,请继续输入:”。
*/
public class Work1 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        while (true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入字符或数字 输入#end结束输入");
            String str = sc.next();
            if (arrayList.contains(str)){
                System.out.println("已经包含,请继续输入:");
                continue;
            }
            if (str.equals("#end")){
                break;
            }
            arrayList.add(str);

        }
        arrayList.forEach(v -> System.out.println(v));
    }
}
/*
2 . 编写一个学生类,有id,name,sex,age四个属性,
    用循环的方式 进行屏幕输入 格式:1001,张三,男,25   然后进行解析创建 学生类,
存入 ArrayList中,
直到输入#end结束循环, 
*/
public class Work2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Student> arrayList = new ArrayList<>();
        while (true) {
            System.out.println("请输入格式为 1001,张三,男,25  输入#end结束");
            String str = sc.next();
            if (str.equals("#end")) {
                break;
            }
            String str1 = sc.next();
            String str2 = sc.next();
            String str3 = sc.next();

            Student student = new Student();
            student.setId(str);
            student.setName(str1);
            student.setSex(str2);
            student.setAge(str3);

            arrayList.add(student);
            System.out.println("请输入id进行查询");
            String strId = sc.next();
            boolean flag = false;

            for (Student stu : arrayList) {
                if (strId.equals(stu.getId())) {
                    flag = true;
                    System.out.println(stu.getId() + "==" + stu.getName() + "==" + stu.getSex() + "==" + stu.getAge());
                }
            }
            if (flag == false){
                System.out.println("查无此人");
            }
        }
    }
}
public class Student {
    private String id;
    private String name;
    private String sex;
    private String age;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
/**
 * 从控制台输入一组数字,存放到集合中,统计数字大于10的个数并输出。删除小于10的所有元素,输出元素内容。
 */
public class Task3 {


    public static void main(String[] args) {
        System.out.println("1,2,10,80,6");
        Scanner scanner = new Scanner(System.in);
        String infoNum = scanner.next();
        String[] nums = infoNum.split(",");
        List<String> strings = Arrays.asList(nums);
        ArrayList<String> listNums = new ArrayList<>(strings);

        Iterator<String> iterator = listNums.iterator();
       int count = 0;
        while(iterator.hasNext()){
            int num = Integer.parseInt(iterator.next());
            if(num > 10){
                //统计个数
                count++;
            }else{
                iterator.remove();
            }
        }
        System.out.println("大于10的个数"+count);
        System.out.println(listNums);
    }
}
LinkedList
/**
     * LinkedList的特点:
     *            1  存储单个元素
     *      *  *  2、有下标(有序--有序指存入顺序和取出顺序一致)
     *      *  *  3、可重复
     *            4、底层结构(数据结构):双向链表存储结构(没有初始容量):查询速度慢、更新(插入和删除)速度快
     *
     *            面试点:Arralist和linkdedList的区别?
     *
     *
     *   常用方法:      addFirst(E e)  addLast(E e)
     *                  getFirst() getLast()
     *                  removeFirst() removeLast()
     *                  小面试点: peek() poll()区别
     *                  peek() 检索但不删除此列表的头(第一个元素)。
     *                  poll() 检索并删除此列表的头(第一个元素)。
     */
public  void testLinkedList(){
            LinkedList<Integer> linkedList = new LinkedList<>();
            //其他常用方法
            linkedList.add(10);
            linkedList.add(60);
            linkedList.add(50);
            linkedList.add(10);

            for(int i=0; i<linkedList.size(); i++){
                System.out.println(linkedList.get(i));
            }

        }
Vector
    /**
     *Vector的特点:
     *      *            1 存储单个元素
     *      *      *  *  2、有下标(有序--有序指存入顺序和取出顺序一致)
     *      *      *  *  3、可重复
     *      *            4、底层结构(数据结构):动态数组结构(扩容未原来的1倍);
     *                    5、线程同步,线程安全,性能低  比较早期的类
     *      *
     *      *            面试点:Arralist和linkdedList\Vector的区别?
     */
    public  void testVector(){
       // Vector

        }



    public static void main(String[] args) {
        ListDemo listDemo = new ListDemo();
        listDemo.testArraylist();
    }

Set

/**
 * Set的特点:
 *      存储单个元素
 *      无下标(没位置)
 *      不可重复
 */
HashSet
/** HashSet特点:
 * *底层结构:哈希表(数组+链表)(基于hashMap实例的哈希表实现)
 *                       存储单个元素
 *             *  *      无下标
 *             *  *      不可重复
 *                       (无序-指存入顺序和取出顺序不一致)
 *              
 *       
 *      *去重原理:hashCode() equals() 暂保留
 */
public  void testHashSet(){

        HashSet<String> hashSet = new HashSet<>();

        hashSet.add("a1");
        hashSet.add("cc");
        hashSet.add("bb");
        hashSet.add("g1");
        hashSet.add("ff");
        boolean bb = hashSet.add("bb");
       // System.out.println(bb); // 重复元素 没有放入(不是覆盖)

       // System.out.println(hashSet.size());

        //修改 (间接操作,先删除  后添加)

        //删除
        hashSet.remove("bb");
    
   	    //取
        //取值方式1
        for(String str:hashSet){
            System.out.println(str);
        }
        System.out.println("===");
        // 取值方式2
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("===");
        //取值方式3
        hashSet.forEach(v -> System.out.println(v) );
TreeSet
 /**  TreeSet的特点:
 *          底层结构:二叉树(基于TreeMap实例实现)
 *          存储单个元素
 *  *       无下标
 *  *       不可重复
 *  *      (排序--默认按照升序排序)
 */
public  void testTreeSet(){
        TreeSet<String> treeSet = new TreeSet<>();

        treeSet.add("aa");
        treeSet.add("cc");
        treeSet.add("bb");
        treeSet.add("ee");
        treeSet.add("dd");
        boolean bb = treeSet.add("bb");

        for(String str:treeSet){
            System.out.println(str);
        }
    }
LinkedHashSet
/**   linkedHashSet的特点:
 *  *          底层结构:双向链表+哈希表
 *  *          存储单个元素
 *  *  *       无下标
 *  *  *       不可重复
 *  *  *      (有序--存入顺序和取出顺序一致)
 */
public  void testLinkedHashSet(){
        LinkedHashSet<String> treeSet = new LinkedHashSet<>();

        treeSet.add("aa");
        treeSet.add("cc");
        treeSet.add("bb");
        treeSet.add("ee");
        treeSet.add("dd");
        treeSet.add("dd");
        boolean bb = treeSet.add("bb");

        for(String str:treeSet){
            System.out.println(str);
        }
    }

双列集合 Map

Map

/**
 * Map的特点:
 *   1 键(key) 值(value)  对形式存储
 *   2 key不可重复(重复数据覆盖操作),value可重复
 *
 * 底层机制:哈希表(数组+单向链表(单向链数据超过8 变成红黑二叉树) )
 *         初始容量: HashMap() 16;扩容因子0.75(当前容量/原容量的比例  超过0.75 扩容,扩容为原来的一倍)
 *
 *         HashMap特点:
 *                1 键(key) 值(value)  对形式存储
 *                2 key不可重复(重复数据覆盖操作),value可重复
 *                3 key无序
 *                4 key 允许为null, value也允许null
 */
HashMap
public  void testHashMap(){

        //
        HashMap<String,Integer> hashMap = new HashMap<>();

        //增
        hashMap.put(null,100);
        hashMap.put("bb",300);
        hashMap.put("e1",200);
        hashMap.put("1f",null);
        hashMap.put("dd",100);
        hashMap.put("dd",300);
    
    //putAll(Map<? extends K,? extends V> m)  两个双列集合合并
    //  重复数据(键重复)   是覆盖还是  没放进去? 放进取  相当于  修改操作
	
    //删除
        hashMap.remove("1f");
        //remove(Object key, Object value)
    	// containsKey(Object key)
        //containsValue(Object value)
    
    //根据key 取value
       System.out.println(hashMap.get("ff"));
    //取所有所有数据
        //取值方式1
        //先找所有的key,然后根绝每个key找到每个value
        Set<String> keys =  hashMap.keySet();
        for(String key:keys){
            System.out.println(key+"=="+hashMap.get(key));
        }

        //取值方式2
        // 直接找所有的 key和value
        //面试点:HashMap取值方式 keySet() 和entrySet()的区别?
        // keySet()先找所有的key,然后根绝每个key找到每个value;找所有key和value  经过两次计算
        //entrySet()直接找到所有的(key+value)一体的集合,然后直接获取key或者value; 找所有key和value 1次计算
        Set<Map.Entry<String, Integer>> keyValueS = hashMap.entrySet();
        for(Map.Entry<String, Integer> kv:keyValueS){
            System.out.println(kv.getKey()+"=="+kv.getValue());
        }

        //取值方式3 jdk1.8提供
        hashMap.forEach((k,v) -> {
            System.out.println(k+"=="+v);
        });
}
HashMap练习题

习题1

public class Book {

    private String bookName;
    private  Integer price;

    public  Book(){

    }

    public Book(String bookName, Integer price, String authorName) {
        this.bookName = bookName;
        this.price = price;
        this.authorName = authorName;
    }

    private  String authorName;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }
}
/**
 * 1.	使用HashMap存储图书信息,ISBN作为键,图书对象(书名、价格)作为值,分别实现添加、查找和删除、遍历输出所有图书信息
 */
public class Task21 {


    public  void test(){


        HashMap<String,Book> hashMap = new HashMap<>();

        Book book1 = new Book("小说",10,"aa");
        Book book2 = new Book("小说2",20,"aa");
        Book book3 = new Book("小说3",30,"aa");


        hashMap.put("1001",book1);
        hashMap.put("1002",book2);
        hashMap.put("1003",book3);



        //取值方式1

        Set<String> keys = hashMap.keySet();
        for(String key:keys){
            Book book = hashMap.get(key);
            System.out.println(book.getBookName()+book.getPrice()+book.getAuthorName());
        }


        //方式2
        Set<Map.Entry<String, Book>> keyValues = hashMap.entrySet();
        for(Map.Entry<String, Book>  kv: keyValues){
                Book book = kv.getValue();
                System.out.println(book.getBookName()+book.getPrice()+book.getAuthorName());
        }



    }
}

习题2

public class Student {

    private  String sno;
    private  String name;
    private  String sex;
    private  Integer age;
    
    public Student() {

    }

    public Student(String sno, String name, String sex, Integer age) {
        this.sno = sno;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getSno() {
        return sno;
    }

    public void setSno(String sno) {
        this.sno = sno;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

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

}
/**
 * 模拟省市级联动使用HashMap存储班级—学生信息
 */
public class Task24 {

    @Test
    public  void test(){

        //班级1
       //管理每个学生信息.封装学生实体
        Student student1 = new Student("001","小红","nv",10);
        Student student2 = new Student("002","小红2","nv",10);
        Student student3 = new Student("003","小红","nv",10);
        Student student4 = new Student("004","小红1","nv",10);


        //管理每个班所有学生信息容器
        List<Student> list1 = new ArrayList<>();
        list1.add(student1);
        list1.add(student2);
        list1.add(student3);
        list1.add(student4);


        //班级2
        //管理每个学生信息.封装学生实体
        Student student21 = new Student("0021","小红","nv",10);
        Student student22 = new Student("0022","小红2","nv",10);
        Student student23 = new Student("0023","小红","nv",10);
        Student student24 = new Student("0024","小红1","nv",10);


        //管理每个班所有学生信息容器
        List<Student> list2 = new ArrayList<>();
        list2.add(student21);
        list2.add(student22);
        list2.add(student23);
        list2.add(student24);

        //<“班级名”,"所有学生信息">
        HashMap<String,List<Student>> hashMapClass = new HashMap<>();
        hashMapClass.put("class1",list1);
        hashMapClass.put("class2",list2);



        //查询班级2的所有学生信息
        List<Student> listStu2 = hashMapClass.get("class2");


        //查询所有每个班级的学生信息
        Set<Map.Entry<String, List<Student>>> keyValues = hashMapClass.entrySet();
        for(Map.Entry<String, List<Student>> kv:keyValues){

            if("class1".equals(kv.getKey())){
                    //输入班级1的所有学生信息
                List<Student> stulist1 = kv.getValue();
                stulist1.forEach(v -> System.out.println(v.getSno()+v.getName()+v.getSex()+v.getAge()));

            }

            if("class2".equals(kv.getKey())){
                //输入班级1的所有学生信息
                List<Student> stulist2 = kv.getValue();
                stulist2.forEach(v -> System.out.println(v.getSno()+v.getName()+v.getSex()+v.getAge()));
            }


        }


    }


    public static void main(String[] args) {
        Task24 task24 = new Task24();
        task24.test();
    }


}
TreeMap
/**
     * 底层机制:二叉树

     *         TreeMap的特点:
     *                1 键(key) 值(value)  对形式存储
     *  *             2 key不可重复(重复数据覆盖操作),value可重复
     *                3 key 排序(默认升序操作)
     *                4 key 不允许为null, value允许null
     *
     */
    @Test
    public  void testTreeMap(){
        //
        TreeMap<String,Integer> hashMap = new TreeMap<>();

        //增
        //hashMap.put(null,100);
        hashMap.put("bb",300);
        hashMap.put("e1",200);
        hashMap.put("1f",null);
        hashMap.put("dd",100);
        hashMap.put("dd",300);
        //取值方式3 jdk1.8提供
        hashMap.forEach((k,v) -> {
            System.out.println(k+"=="+v);
        });
    }
LinkedHashMap
/**
     * 底层机制:双向链表+哈希表

     *         LinkedHashMap的特点:
     *                1 键(key) 值(value)  对形式存储
     *  *             2 key不可重复(重复数据覆盖操作),value可重复
     *                3 key 有序(指存入顺序和取出顺序一直)
     *                4 key 不允许为null, value也允许null
     *
     */
    @Test
    public void testLinkedHashMap(){
        //
        LinkedHashMap<String,Integer> hashMap = new LinkedHashMap<>();

        //增
        hashMap.put(null,100);
        hashMap.put("bb",300);
        hashMap.put("e1",200);
        hashMap.put("1f",null);
        hashMap.put("dd",100);
        hashMap.put("dd",300);
        //取值方式3 jdk1.8提供
        hashMap.forEach((k,v) -> {
            System.out.println(k+"=="+v);
        });
    }
Hashtable
/**
     * 底层机制:哈希表(数组+单向链表(单向链数据超过8 变成红黑二叉树) )
     *         初始容量: Hashtable() 11;扩容因子0.75(当前容量/原容量的比例  超过0.75 扩容,扩容为原来的一倍)
     *
     *         Hashtable特点:
     *                1 键(key) 值(value)  对形式存储
     *  *             2 key不可重复(重复数据覆盖操作),value可重复
     *                3 key无序()
     *                4 key 不允许为null, value不允许null
     *                5 线程安全,性能低
     *                6 jdk1.4之前的 了解历史
     *
     *                面试点:HashMap和Hashtable的 区别?
     *                相同点:
     *                不同点:
     *
     */
    @Test
    public void testHashtable(){
        //
        Hashtable<String,Integer> hashMap = new Hashtable<>();

        //增
       // hashMap.put(null,100);
        hashMap.put("bb",300);
        hashMap.put("e1",200);
       // hashMap.put("1f",null);
        hashMap.put("dd",100);
        hashMap.put("dd",300);
        //取值方式3 jdk1.8提供
        hashMap.forEach((k,v) -> {
            System.out.println(k+"=="+v);
        });
    }
testProperties
@Test
    public  void testProperties(){
        Properties properties = new Properties();
        // 路径:绝对路径 和相对路径
        try{
            properties.load(MapDemo.class.getClassLoader().getResourceAsStream("jdbc.properties"));
            System.out.println(properties.getProperty("jdbc.pwd"));
            System.out.println(properties.getProperty("jdbc.uname"));

        }catch (IOException e){
            e.printStackTrace();
        }
    }

知识补充

自定义泛型

/**
 * 类自定已泛型
 * @param <T>
 */
public class Demo01<T> {
    public void test(T pram1){
        System.out.println(pram1);
    }

    public static void main(String[] args) {
        Demo01<Integer> demo01 = new Demo01<>();

        demo01.test(1);

        Demo01<String> demo02 = new Demo01<>();
        demo02.test("as");

    }
}
/**
 * 泛型作用在方法
 */
public class Demo02 {

    public <T>T test(T pram){
        return pram;
    }

    public static void main(String[] args) {
        Demo02 demo02 = new Demo02();
        Integer test = demo02.test(123);

        String hah = demo02.test("hah");
        
    }
}

排序

比较器
Comparator和Comparable区别

Comparator
1、当对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。
2、不改变对象自身,而用一个策略对象来改变它的行为。
3、相当于外部比较器
public interface Comparator<T> {
int compare(T o1, T o2);
}

Comparable
1、Comparable是一个对象,本身就已经支持自比较所需要实现的接口
2、自定义类要在加入list容器中后能够排序,也可以实现Comparable接口。
3、相当于内部比较器
public interface Comparable<T> {
public int compareTo(T o);
}

如果一个类实现了Comparable接口,又在排序的时候,使用了Comparator制定排序规则,会出现什么样的情况?
外比较器优先
工具类Collections 中的sort(传比较器)
/**
 * sort(List<T> list)  根据元素的自然顺序 对指定列表按升序进行排序
 * sort(List<T> list, Comparator<? super T> c)  根据指定比较器产生的顺序对指定列表进行排序。
 */
public class Demo03 {
    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(60);
        arrayList.add(50);
        arrayList.add(30);
        arrayList.add(20);
        arrayList.add(10);

        Collections.sort(arrayList);

        Collections.sort(arrayList,((o1, o2) -> o2.compareTo(o1)));

        System.out.println(arrayList);

    }
}
List集合中的 sort(传比较器)
public class Demo04 {
    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList<>();

        arrayList.add(10);
        arrayList.add(60);
        arrayList.add(50);
        arrayList.add(30);
        arrayList.add(20);
        arrayList.add(10);

        /*arrayList.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });*/

        arrayList.sort(((o1, o2) -> o2.compareTo(o1)));

        System.out.println(arrayList);
    }

}
TreeSet 传比较器
public void setTreeSet1(){
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 重写   降序规则
                return o2.compareTo(o1);
            }
        });
        treeSet.add("aa");
        treeSet.add("ba");
        treeSet.add("ab");
        treeSet.add("cc");
        treeSet.add("aa");

        for (String str:treeSet
             ) {
            System.out.println(str);
        }

    }
public void setTreeSet2(){
        Student student1 = new Student("001","张一","男",10);
        Student student2 = new Student("002","张二","男",10);
        Student student3 = new Student("004","张四","男",10);
        Student student4 = new Student("003","张三","男",10);


        /*TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getSno().compareTo(o2.getSno()); // 重写升序
            }
        });*/

        TreeSet<Student> treeSet = new TreeSet<>((o1,o2) -> o2.getSno().compareTo(o1.getSno()));// 重写降序

        treeSet.add(student1);
        treeSet.add(student2);
        treeSet.add(student3);
        treeSet.add(student4);

        for (Student stu:treeSet
             ) {
            System.out.println(stu.getSno());
        }

    }

去重

public void testHashSet(){

        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("aa");
        hashSet.add("ba");
        hashSet.add("aa");
        // System.out.println(hashSet.size());

        // 重写hashCode的原则: 相同对象的hashcode值相同,不同对象的hashCode值不同
        // 重写equals()   判断是否是同一个对象
        Student student21 = new Student("0021","小红1","nv1",10);
        Student student22 = new Student("0022","小红","nv2",10);
        Student student23 = new Student("0022","小红","nv3",10);
        Student student24 = new Student("0024","小红2","nv4",10);
        HashSet<Student> hashSet3 = new HashSet<>();
        hashSet3.add(student21);
        hashSet3.add(student22);
        hashSet3.add(student23);
        hashSet3.add(student24);
        System.out.println(hashSet3.size());

    }

    public static void main(String[] args) {
        Demo06 demo06 = new Demo06();
        demo06.testHashSet();
    }

实体类 重写hashCode的原则 重写equals

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return Objects.equals(getSno(), student.getSno());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getSno());
    }

工具类

Arrays
/**
 * asList(T... a) 返回一个受指定数组支持的固定大小的列表
 * copyOf(T[] original, int newLength) 复制指定的数组,截取或用 null 填充(如有必要)
 * copyOfRange(T[] original, int from, int to)  将指定数组的指定范围复制到一个新数组。
 * sort(T[] a)  对指定类型数组的指定范围按数字升序进行排序。
 * sort(T[] a, Comparator<? super T> c) 根据指定比较器产生的顺序对指定对象数组进行排序。
 */
public class Demo07 {
    public static void main(String[] args) {

        Integer [] nums = {7,5,8,6,4,2,1,3};

//        Integer[] integers = Arrays.copyOf(nums, 2);
//        Integer[] integers = Arrays.copyOfRange(nums, 1,4);
        
        Arrays.sort(nums,(o1,o2) -> o2.compareTo(o1));


        System.out.println(Arrays.toString(nums));

    }

}
Collections
/**
 * copy(List<? super T> dest, List<? extends T> src) 从一个列表拷贝到另一个列表中
 * emptyList()  返回一个空的列表
 * emptyMap()  返回一个空的映射
 * emptySet() 返回一个空的Set集合
 * max(Collection<? extends T> coll)  根据元素的自然顺序,返回给定 collection 的最大元素
 * max(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定比较器产生的顺序,返回给定 collection 的最大元素。
 * reverse(List<?> list)  反转指定列表中元素的顺序。
 * shuffle(List<?> list) 使用默认随机源对指定列表进行置换,类似于重新洗牌。
 * sort(List<T> list)  根据元素的自然顺序 对指定列表按升序进行排序
 * sort(List<T> list, Comparator<? super T> c)  根据指定比较器产生的顺序对指定列表进行排序。
 */
public class Demo08 {
    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(60);
        arrayList.add(50);
        arrayList.add(30);
        arrayList.add(20);
        arrayList.add(10);

//        Integer max = Collections.max(arrayList);
//        Integer max = Collections.max(arrayList, (o1, o2) -> o2.compareTo(o1));
//        System.out.println(max);

        Collections.reverse(arrayList); // 反转数组

        Collections.shuffle(arrayList); // 重新洗牌

        Collections.sort(arrayList); // 升序
        Collections.sort(arrayList,(o1,o2) -> o2.compareTo(o1)); // 降序

        System.out.println(arrayList);
    }

}

IO流 *面试点待写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YAtO4TUi-1618990153007)(JavaSE.assets/IO.png)]

File类

import java.io.File;
import java.io.IOException;
import java.util.Date;

public class Demo01 {

    public void test1(){

        String pathName = "D:\\IdeaProjects\\OOP\\src\\com\\soft\\day07\\FileDemo1.java";

        File file = new File(pathName);

        if (file.exists()){
            System.out.println("合法路径");
            if (file.isFile()){
                System.out.println("文件名"+file.getName());
                System.out.println("父路径"+file.getParent());
                System.out.println("绝对路径"+file.getAbsolutePath());
                System.out.println("文件大小"+file.length());
                System.out.println("可读"+file.canRead());
                System.out.println("可写"+file.canWrite());

                System.out.println(file.lastModified());

                Date date = new Date(file.lastModified());
                System.out.println("文件的最后修改时间"+date);
            }
            if (file.isDirectory()){
                System.out.println("是路径");
            }
        }

    }

    public void test2(){
        String pathName = "D:\\testFle\\subTestFile\\aa.txt";
        File file = new File(pathName);

        //构建父类路径  file实例
        File file1 = new File(file.getParent());

        //创建单级目录
        // file1.mkdir();
        //创建多级目录
        file1.mkdirs();

        try {
            //生成文件
            file.createNewFile();
            System.out.println("创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void test3(){
        String pathName = "D:\\testFle\\subTestFile\\aa.txt";
        File file = new File(pathName);
        // 删除注意点  1 有删除权限,程序才能删除. 2 只删除指定文件,所在目录保留
        file.delete();
        System.out.println("删除成功");
    }

    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
//        demo01.test1();
//        demo01.test2();
        demo01.test3();
    }

}
import org.junit.Test;
import java.io.File;
/**
 * 递归示例
 * 查询指定目录所有文件的文件名
 */
public class Demo02 {

    @Test
    public void getFileInfo() {
        String pathName = "D:\\testFle";
        File file = new File(pathName);
        File[] files = file.listFiles();

        //调用方法  取所有文件信息
        outPutFileInfo(files);

    }

    public void outPutFileInfo(File[] files) {
        for (File f : files
        ) {
            if (f.isFile()) { //判断是文件
                System.out.println(f.getName());
            } else {
                //递归(一定要注意 有结束的条件)
                outPutFileInfo(f.listFiles());
            }
        }
    }

}

IO分类

字节流

  • InputStream
  • OutPutStream
package com.soft.day07;

import org.junit.Test;

import java.io.*;

public class Demo03 {

    /**
     * 单个字节读取
     */
    @Test
    public void test1(){
        String pathName = "D:\\IdeaProjects\\OOP\\src\\com\\soft\\day07\\FileStreamDemo.java";
        File file = new File(pathName);
        FileInputStream fileInputStream = null;

        try {
            //创建 FileInputStream实例
            fileInputStream = new FileInputStream(file);

            while (true){
                int read = fileInputStream.read();//read()方法的返回值 式ascii码值

                //读完文件结束循环
                if (read == -1){
                    break;
                }
                System.out.print((char)read);

            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 指定字节长度读取
     */
    @Test
    public void test2(){
        String pathName = "D:\\IdeaProjects\\OOP\\src\\com\\soft\\day07\\FileStreamDemo.java";
        File file = new File(pathName);
        FileInputStream fileInputStream = null;

        try {
            fileInputStream = new FileInputStream(file);
            byte[] bytes = new byte[fileInputStream.available()];//一次(fileInputStream.available())读完

            while (true){
                //指定跳过字节数读取
                fileInputStream.skip(3);

                int read = fileInputStream.read(bytes);
                if (read == -1){
                    break;
                }
                System.out.println(new String(bytes));

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
    /**
     * 文件复制
     */
    @Test
    public void test3(){
        String pathName = "D:\\IdeaProjects\\OOP\\src\\com\\soft\\day07\\FileStreamDemo.java";
        String pathToName = "D:\\OOP\\src\\com\\soft\\day07\\FileStreamDemo.java";

        File file = new File(pathName);     //原路径
        File fileTo = new File(pathToName);// 复制路径

        //创建复制路径的 父目录
        new File(fileTo.getParent()).mkdirs();

        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        // 指定读取字节长度
        byte[] bytes = new byte[10];

        try {
            fileInputStream = new FileInputStream(file);
            fileOutputStream = new FileOutputStream(fileTo);

            while (true){
                //read 代表读取的字节个数
                int read = fileInputStream.read(bytes);

                if (read == -1){
                    break;
                }
                System.out.println("文件复制中...");
                //写入复制文件地址
                fileOutputStream.write(bytes,0,read);

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

字符流

  • Reader
  • Writer
/**
 * 字符流:字节流+编码表
 * 要求:程序的编码格式要和  被度文件的编码格式一致
 *
 *
 * 对比字符流使用注意事项:
 * 1 注意编码格式 要求:程序的编码格式要和  被度文件的编码格式一致
 * 2 有缓冲区,写文件操作刷新缓冲区
 * 3 关闭流资源时,会自动同步刷新缓冲区
 */
public class FileReaderWriter {


    public  void test1(){
        String pathName = "D:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\book1.txt";
        File  file = new File(pathName);

        try {
            //构建字符流实例
            FileReader fileReader = new FileReader(file);
            while (true){
                int rs = fileReader.read(); //单个字节读取


                if(rs == -1){//代表读到文件的末尾
                    break;
                }


                Thread.sleep(500);

                System.out.print((char)rs);

            }

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public  void test2(){


        String pathName = "D:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\book1.txt";
        File file = new File(pathName);

        try {
            char[] chars = new char[10];
            //构建字符流实例
            FileReader fileReader = new FileReader(file);
            while (true){

                //返回值 代表读取的字符个数
                int len = fileReader.read(chars);//指定字符读取


                if(len == -1){//代表读到文件的末尾
                    break;
                }

                System.out.print( new String(chars,0,len));

            }

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 字符流  文件复制
     */
    public  void test3(){
        String pathName = "D:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\Book.java";
        String pathNameTo = "F:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\Book.java";

        File  file = new File(pathName);
        File fileTo = new File(pathNameTo);
        new File(fileTo.getParent()).mkdirs();//

        char[] chars = new char[10];
        FileReader fileReader = null;
        FileWriter fileWriter = null;

        try {
            //构建字符流实例
            fileReader = new FileReader(file);//字符读取流
            fileWriter = new FileWriter(fileTo);//字符写入流

            while (true){

                //返回值 代表读取的字符个数
                int len = fileReader.read(chars);//指定字符读取


                if(len == -1){//代表读到文件的末尾
                    break;
                }


                System.out.println("文件复制中......");

                // fileWriter.flush();//刷新缓冲区
                //字符流  输出
                fileWriter.write(chars,0,len);

            }

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fileWriter != null){
                try {
                    fileWriter.close();//关闭是  字符流同步刷缓冲区
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        FileReaderWriter fileReaderWriter = new FileReaderWriter();
        fileReaderWriter.test3();
    }
}

缓冲流

缓冲字节流
  • BufferedInputStream
  • BufferedOutputStream
/**
 * 缓冲流:
 * 1 不直接和文件做交互,可以提高性能
 * 2 有缓冲区,并且可以手动设置缓冲区的大小
 *
 */
public class BufferedStream {

    public  void test(){

        String pathName = "D:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\Book.java";
        String pathNameTo = "F:\\idea2Workspace\\java289\\src\\com\\jiHe\\taskDemo\\Book.java";

        File file = new File(pathName);
        File fileTo = new File(pathNameTo);
        new File(fileTo.getParent()).mkdirs();

        FileInputStream fileInputStream = null;
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            fileInputStream = new FileInputStream(file);//直接和文件交互
            bufferedInputStream = new BufferedInputStream(fileInputStream);//实现了间接操作文件

            fileOutputStream = new FileOutputStream(fileTo);//直接和文件交互
            bufferedOutputStream = new BufferedOutputStream(fileOutputStream,1024);//简介和文件交互 手动设置缓冲区大小

            byte[] bytes = new byte[12];

            int count = 0;
            while (true){
                int len = bufferedInputStream.read(bytes);
                if(len == -1){
                    break;
                }

                count += len;

               // System.out.print(new String(bytes,0,len));
                bufferedOutputStream.write(bytes,0,len); //写入缓冲区

                if(count == 1024){//缓冲内容 满1024,再把缓冲区的内容写入文件,可以减少和硬盘文件的交互次数
                    //刷新缓冲区
                    bufferedOutputStream.flush();//强制性把缓冲区的内容 写入文件
                    count = 0;
                }

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
                e.printStackTrace();
        }finally {
            //关闭资源 由近及远
            try {
                if(bufferedInputStream != null){
                    bufferedInputStream.close(); //关闭时  会强制性刷新缓冲区
                }

                if(fileInputStream != null){
                    fileInputStream.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }


            try {
                if(bufferedOutputStream != null){
                    bufferedOutputStream.close();
                }

                if(fileOutputStream != null){
                    fileOutputStream.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    public static void main(String[] args) {
        BufferedStream bufferedStream = new BufferedStream();
        bufferedStream.test();
    }
}
缓冲字符流
  • BufferedReader可以按行操作,方便读取CSV文件
  • BufferedWriter
/**
 * 字符缓冲流  可以按行读取
 */
public class BufferedReaderWriter {


    public  void test(){

        String path = "D:\\idea2Workspace\\java289\\src\\com\\ioDemo\\student.csv";
        File file = new File(path);

        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            fileReader = new FileReader(file);
            bufferedReader = new BufferedReader(fileReader);//间接和文件交互

            while (true){
                //按行读取操作
                String studentInfo = bufferedReader.readLine();
                if(studentInfo == null){//代表读完
                        break;
                }

                String[] stus = studentInfo.split(",");
                System.out.println(stus[0]+stus[1]);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭
        }


    }

    /**
     *
     */
    public  void test2(){

        String path = "D:\\idea2Workspace\\java289\\src\\com\\ioDemo\\student.csv";
        String pathTo = "F:\\idea2Workspace\\java289\\src\\com\\ioDemo\\student.csv";
        File file = new File(path);
        File file1 = new File(pathTo);
        new File(file1.getParent()).mkdirs();

        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        FileWriter fileWriter = null;
        try {
            fileReader = new FileReader(file);
            bufferedReader = new BufferedReader(fileReader);//间接和文件交互

            fileWriter = new FileWriter(file1);
            bufferedWriter = new BufferedWriter(fileWriter);

            while (true){
                //按行读取操作
                String studentInfo = bufferedReader.readLine();
                if(studentInfo == null){//代表读完
                    break;
                }

                //按行写
                bufferedWriter.write(studentInfo);
                bufferedWriter.newLine();//换行操作

                //刷新缓冲区
                bufferedWriter.flush();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) {
        BufferedReaderWriter bufferedReaderWriter = new BufferedReaderWriter();
        bufferedReaderWriter.test2();
    }

}

IO使用三部曲

    1. 创建流
    1. 使用
    1. 关闭

IO应用

  • 操作csv文件
public class ReadCSVFile {

    public  void test(){

        String path = "D:\\idea2Workspace\\java289\\src\\com\\ioDemo\\student.csv";
        File file = new File(path);

        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            fileReader = new FileReader(file);
            bufferedReader = new BufferedReader(fileReader);//间接和文件交互

            while (true){
                //按行读取操作
                String studentInfo = bufferedReader.readLine();
                if(studentInfo == null){//代表读完
                    break;
                }

                String[] stus = studentInfo.split(",");
                System.out.println(stus[0]+stus[1]);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭
        }

    }

    public static void main(String[] args) {
        ReadCSVFile readCSVFile = new ReadCSVFile();
        readCSVFile.test();
    }
}
  • 操作Proteries文件
public class ReadProteries {

    public  void testProperties(){
        String path = "D:\\idea2Workspace\\java289\\src\\jdbc.properties";
        File file = new File(path);
        Properties properties = new Properties();
        // 路径:绝对路径 和相对路径

        try {
           // properties.load(ReadProteries.class.getClassLoader().getResourceAsStream("jdbc.properties"));

            FileInputStream fileInputStream = new FileInputStream(file);
            properties.load(fileInputStream);
            System.out.println(properties.getProperty("jdbc.pwd"));
            System.out.println(properties.getProperty("jdbc.uname"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        ReadProteries readProteries = new ReadProteries();
        readProteries.testProperties();
    }
}

IO面试点 *待写

  • IO流在什么包中?
  • IO 字节流和字符流都有哪些?
  • 对象序列化流了解吗?
  • 怎么获取CSV文件中的数据?
  • 解释下递归?

多线程 *面试点待写

线程的创建

继承Thread类 (重写run() run()是执行体)
  • 特征:

    1.子类继承 Thread类,线程任务和线程本身是绑定

    2.子类继承 Thread类,有一定扩展局限性,因为JAVA是单继承,不利于程序的再扩展

  • 缺点:

    1.继承Thread 不利程序的扩展

    2.线程和线程任务本省是绑定的,线程任务和线程本身不分离

public class MyThread extends  Thread{

    @Override
    public void run() {
        for(int i=1; i<=30; i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"执行"+i);
        }
    }
}
public class TestMyThread {

    public static void main(String[] args) {

        System.out.println("主线程 main方法开始");
        //线程1
        MyThread myThread1 = new MyThread();
        myThread1.setName("线程1");//给线程起名字   不起 有默认名
        myThread1.start(); //start() 启动线程  让线程进入 就绪状态。

        //线程2
        MyThread myThread2 = new MyThread();
        myThread2.setName("线程2");
        myThread2.start();
        //设置线程优先级 优先级别 1--10   默认5 注意点:优先级只是相对拥有优先权限,实际仍是抢占CPU资源
        myThread2.setPriority(10);

        System.out.println("主线程 main方法结束");
    }
}
实现Runable接口 (重写run() run()执行体)
  • 优点:
    1. 实现Runnable接口 利程序的扩展
    2. 线程和线程任务本身没绑定,线程本身和任务 是分离
public class MyRunableDemo  implements Runnable {

    @Override
    public void run() {//线程执行体方法

        for(int i=0; i<=10; i++){
            System.out.println(Thread.currentThread().getName()+"执行"+i);
        }
    }
}
public class TestMyRunableDemo {

    public static void main(String[] args) {

        //任务实例
        MyRunableDemo myRunableDemo = new MyRunableDemo();

        Thread thread1 = new Thread(myRunableDemo);//创建1个线程实例
        thread1.setName("线程1");
        thread1.start();//启动线程

        Thread thread2 = new Thread(myRunableDemo);
        thread2.setName("线程2");
        thread2.start();
    }
}
实现Callable接口 (重写 call()方法 call()方法是执行体)
  • 特征
    1.灵活性 扩展性强
    2.有返回值
    3.可以处理异常
public class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {

        int sum = 0;
        for(int i=0; i<100; i++){
            System.out.println(Thread.currentThread().getName()+"执行"+i);
            sum += i;

            Thread.sleep(100);
        }
        return sum;
    }
}
public class TestCallable {

    public static void main(String[] args) {

        MyCallable myCallable = new MyCallable();

        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        Thread thread1 = new Thread(futureTask);
        thread1.setName("线程1");
        thread1.start();
        try {
            Integer rs = futureTask.get();//获取线程任务 call()的返回值
            System.out.println(rs);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        FutureTask<Integer> futureTask2 = new FutureTask<>(myCallable);
        Thread thread2 = new Thread(futureTask2);
        thread2.setName("线程2");
        thread2.start();
        try {
            Integer rs2 = futureTask2.get();//获取线程任务 call()的返回值
            System.out.println(rs2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

线程状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2x0LEpZs-1618990153008)(JavaSE.assets/image-20210106173330608.png)]

  1. 线程刚创建时,是new状态

  2. 线程调用了start()方法后,进入runnable状态,此时并未真正执行,需要和其他线程竞争cpu资源

  3. 当该线程竞争到了CPU资源,进入running状态

  4. 线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态之间处于blocked状态

    (1)等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等 待池”中,进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被 唤醒,

    (2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程 放入“锁池”中。

    (3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻 塞状态。 当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

  5. 当线程正常执行结束会进入dead状态(一个未捕获的异常也会使线程终止)

同步锁机制

  • 三种加锁方式
    1.共享代码块 加锁 ,利用synchronized(锁对象)
    2.共享方法加锁 关键字synchronized加在方法体上
    3 .private Lock lock = new ReentrantLock(); 加锁lock.lock(); 解锁lock.unlock();
/**
 * 线程同步时,线程不安全 ;解决此问题,需要同步锁,保证 线程安全
 * 线程同步锁实现方式
 * 	1 把代码块 加上同步锁 关键字synchronized
 * 	2 方法加 同步锁 关键字synchronized
 * 	3 加锁 private Lock lock = new ReentrantLock();  加锁lock.lock(); 解锁lock.unlock();
 *
 */
public class SaleTicket implements Runnable {

    // 100账票
    int count = 100;

    private Lock lock = new ReentrantLock();//同步锁第三种实现方式

    Object obj = new Object();//公用锁对象

    @Override
    public void run() {

        while (true){
            //方式1
            //把代码块加上同步锁
            /*synchronized (obj){//可用常字符串代替
                if (count > 0) {//有票才能卖
                    //count-- 先使用后减法
                    System.out.println(Thread.currentThread().getName() + "在卖第" + (count--) + "张票");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }*/

            //方式2
            // 调用test()方法  test()方法加线程安全synchronized
           // test();

            //方式3
            //锁开始
            lock.lock();
            if (count > 0) {//有票才能卖
                //count-- 先使用后减法
                System.out.println(Thread.currentThread().getName() + "在卖第" + (count--) + "张票");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //解锁
            lock.unlock();
        }
    }

    public synchronized void test(){
        if (count > 0) {//有票才能卖
            //count-- 先使用后减法
            System.out.println(Thread.currentThread().getName() + "在卖第" + (count--) + "张票");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestSaleTicket {

    public static void main(String[] args) {

        SaleTicket saleTicket = new SaleTicket();//卖票任务

        Thread thread1 = new Thread(saleTicket);//线程创建
        thread1.setName("窗口1");
        thread1.start();//调用start()  让其进入就绪状态

        Thread thread2 = new Thread(saleTicket);
        thread2.setName("窗口2");
        thread2.start();

        Thread thread3 = new Thread(saleTicket);
        thread3.setName("窗口3");
        thread3.start();

    }
}

线程通信

wait()和sleep的区别?

  1. 释放资源:sleep释放cpu 但是不释放锁对象;wait()释放cpu同时释放锁对象

  2. 唤醒条件:sleep() 达到睡眠时间后自动进入就绪状态;wait()须等待被唤醒(即用notify()或者notfiyAll())

  3. 作用位置:sleep()可作用于同步或异步位置;wait()只能再同步条件下

public class PrintNum  implements  Runnable {

    int num = 1;
    Object obj = new Object();
    @Override
    public void run() {


        synchronized (obj){//同步锁 保证线程安全
            while (num <=10){
                System.out.println(Thread.currentThread().getName()+"打印值"+num++);

                if(num == 6){//打印够 5个数字
                    try {
                        obj.wait();//让点前线程等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            //唤醒下一个线程
            obj.notify();
        }

    }
}
public class TestPrintNum {

    public static void main(String[] args) {

        PrintNum printNum = new PrintNum();//两个线程的共享任务

        //创建两个线程
        Thread thread1 = new Thread(printNum);
        thread1.setName("线程1");
        thread1.start();

        Thread thread2 = new Thread(printNum);
        thread2.setName("线程2");
        thread2.start();
    }
}

notify()或者notifyall()

public class Account {

	private  int  balance = 1000;


	/**
	 * 存钱
	 * @param m
	 */
	public synchronized void  add(int m){
		
		if(balance > 1000){
			// 调用notifyAll()唤醒其他等待该对象的线程。
			notifyAll();
			try {
				//wait() 线程休眠  释放对象锁 
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			balance = balance + m;
			String name = Thread.currentThread().getName();
			System.out.println(name+ " 存钱金额:"+m+", 当前金额:"+balance);
		}
		
	}

	/**
	 * 取钱
	 * @param m
	 */
	public synchronized void  fetch(int m){
		
		if(balance < m){
			// 调用notifyAll()唤醒其他等待该对象的线程。
			notifyAll();
			try {
				//线程等待  释放对象锁
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			balance = balance - m;
			String name = Thread.currentThread().getName();
			System.out.println(name+ " 取钱金额:"+m+", 当前金额:"+balance);
		}
		
	}
	
}
public class Parent extends Thread{

	private Account acc ;

	public Parent(Account a) {
		 this.acc = a;
	}

	public void setAcc(Account a){
		 this.acc = a;
	}

	@Override
	public void run() {
	    while(true){
	    	try {
		    	// 产生随机数 0 - 500;
		    	int m = (int)Math.round((Math.random()*500));
		    	acc.add(m);
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	    }
	}
}
public class Child extends Thread {

	private Account acc ;
	
	public Child(Account a) {
		 this.acc = a;
	}

	public void setAcc(Account a){
		 this.acc = a;
	}

	@Override
	public void run() {
	    while(true){
	    	try {
		    	// 产生随机数 0 - 500;
		    	int m = (int)Math.round((Math.random()*500));
		    	acc.fetch(m);
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	    } 
	}
}
public class Test {

	public static void main(String[] args) {
		Account a = new Account();

		Child c1 = new Child(a);//孩子1
		c1.setName("boy1");
		c1.start();

		Child c2 = new Child(a);//孩子2
		c2.setName("boy2");
		c2.start();
        
        Parent p = new Parent(a);//父母
        p.setName("父母");
        p.start();
	}

}

需要掌握方法总结

  • start() 启动线程
  • run() 线程执行体
  • sleep() 休眠
  • wait() 线程等待 掌握wati和sleep的区别
  • notify() notifyall() 线程唤醒
  • 设置优先级 setPriority(10);优先级别 1–10 默认5 注意点:优先级只是相对拥有优先权限,实际仍是抢占CPU资源
    • Thread.currentThread().getName()获取线程名 setName()线程起名
  • join() 线程礼让 interrupt() 打破睡眠阻塞 stop() 死亡 yield() CPU时间片到期

线程池了解

线程池:容纳多个线程资源的容器,容器内的线程资源可以重复使用,其实是对多线程使用的一种优化(提高性能,放置线程资源过多消耗和创建)

/**
 * 是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作, 无需反复创建线程而消耗过多资源,是对线程使用的一种优化。
 */
public class TestPool {

    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        //4个线程
        MyRunableDemo runableDemo1 = new MyRunableDemo();
        MyRunableDemo runableDemo2 = new MyRunableDemo();
        MyRunableDemo runableDemo3 = new MyRunableDemo();
        MyRunableDemo runableDemo4 = new MyRunableDemo();

        //提交任务
        executorService.submit(runableDemo1);
        executorService.submit(runableDemo2);
        executorService.submit(runableDemo3);
        executorService.submit(runableDemo4);

        //关闭池子
        executorService.shutdown();
    }
}
public class MyRunableDemo implements Runnable {

    @Override
    public void run() {//线程执行体方法

        for(int i=0; i<=10; i++){
            System.out.println(Thread.currentThread().getName()+"执行"+i);
        }
    }
}

多线程小Demo

/**
 *2.	写两个线程,一个线程打印 1-52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。
 */
public class ThreadDemo {

    public static void main(String[] args) throws Exception
    {
        Object obj = new Object();//锁对象共享
        // 启动两个线程
        Thread1 t1 = new Thread1(obj);

        Thread2 t2 = new Thread2(obj);

        t1.start();
        t2.start();
    }
}
/**
 * 打数字
 */
public class Thread1 extends  Thread {
    private Object obj;

    public Thread1(Object obj) {
        this.obj = obj;
    }

    public void run() {
        synchronized (obj) {//共享锁
            // 打印1-52
            for (int i = 1; i < 53; i++) {
                System.out.print(i + " ");
       
         if (i % 2 == 0) {
                    // 不能忘了 唤醒其它线程
                    obj.notifyAll();
                    try {
                        obj.wait();//自己等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
/**
 * 打字母
 */
public class Thread2 extends Thread {
    private Object obj;

    public Thread2(Object obj) {
        this.obj = obj;
    }

    public void run() {
        synchronized (obj) {//共享锁
            // 打印A-Z
            for (int i = 0; i < 26; i++) {
                System.out.print((char)('A' + i) + " ");
                // 不能忘了 唤醒其它线程
                obj.notifyAll();
                try {
                    // 最后一个就不要等了
                    if (i != 25) {
                        obj.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

面试问题点 *待写

  • 线程的创建方式有哪些?
  • 线程同步锁机制有哪些?怎么加线程同步锁? 重点 掌握 synchronized的运用
  • 线程有哪些状态?
  • 线程怎么启动?线程执行体是哪个方法?
  • wait()和sleep的区别?
    • 1释放资源:sleep释放cpu 但是不释放锁对象;wait()释放cpu同时释放锁对象
    • 2唤醒条件:sleep() 达到睡眠时间后自动进入就绪状态;wait()须等待被唤醒(即用notify()或者notfiyAll())
    • 3作用位置:sleep()可作用于同步或异步位置;wait()只能再同步条件下
  • 线程的常用方法有哪些?

JDK8 新特性

接口增强

  • Java 8 新增了接口的默认方法。
  • 简单说,默认方法就是接口可以有实现方法,而且不需要实现类 去实现其方法。
  • 我们只需在方法名前面加个 default 关键字即可实现默认方法。

为什么要有这个特性?

​ 首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口 时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的 解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口 添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现 有的实现不兼容的问题。

接口增强-默认方法

由于同一个方法可以从不同接口引入, 自然而然的会有冲突的现象,规则如下: 1)一个声明在类里面的方法优先于 任何默认方法 2)优先选取最具体的实现

public interface Vehicle {
 /** 默认方法 */
 default void print() {
 System.out.println("我是一个默认方法");
 }
 /** 抽象方法 */
 public void method();
}
class Demo implements Vehicle {
 @Override
 public void method() {
 System.out.println("我是抽象方法的实现");
 }
 @Test
 public static void main(String[] args) {
 Vehicle demo = new Demo();
 demo.method(); // 我是抽象方法的实现
 demo.print(); // 我是一个默认方法
 }
}

接口增强-静态方法

public interface Vehicle {
 /** 默认方法 */
 default void print() {
 System.out.println("我是一个默认方法");
 }
 /** 抽象方法 */
 public void method();
 /** 静态方法 */
 public static void staticMethod() {
 System.out.println("我是一个静态方法");
 }
}
class Demo implements Vehicle {
 @Override
 public void method() {
 System.out.println("我是抽象方法的实现");
 }
@Test
public static void main(String[] args) {
 Vehicle demo = new Demo();
 Vehicle.staticMethod(); // 我是一个静态方法
 demo.method(); // 我是抽象方法的实现
 demo.print(); // 我是一个默认方法
}

方法引用

Lambda 表达式:函数式接口实例创建时匿名内部类写法的简化方式

方法引用: 是 Lambda 表达式简化

前提:

  1. lambda表达式的实现体已经提供的实现方法
  2. 函数式接口中的抽象方法的参数和返回值 要和 方法引用中的方法的参数和返回值一致

4种方式:

  • 引用静态方法–>类名称::static 方法名称;
  • 引用某个对象的实例的普通方法–>实例化对象::普通方法;
  • 引用特定类型的任意对象的实例方法–>特定类::普通方法;
  • 引用构造方法–>类名称::new
public class Demo1 {

    /**
     * 引用构造方法-->类名称::new
     */
    public  void test1(){

        //Student student = new Student("1001","小红");

        BiFunction<String,String,Student> fun = Student::new;
        Student student = fun.apply("1001", "小红");

        //Student student1 = new Student();
        Supplier<Student> fun2 = Student::new;
        Student student2 = fun2.get();

        //应用场景
        Stream<String> stream = Stream.of("e", "d", "c", "a", "f", "b");
        ArrayList<String> alist = stream.collect(Collectors.toCollection(ArrayList::new));

    }

    /**
     * 引用静态方法-->类名称::static 方法名称;
     */
    public  void test2(){
       // int i = Integer.parseInt("123");
        //Function<String,Integer> fun = (str)->Integer.parseInt(str);
        Function<String,Integer> fun = Integer::parseInt;
        Integer i = fun.apply("123");

    }

    /**
     * 引用某个对象的实例的普通方法-->实例化对象::普通方法;
     */
    @Test
    public  void test4(){
       Random random = new Random();
        /*  int i = random.nextInt();*/

        Supplier<Integer> fun = random::nextInt;
        Integer randomNum = fun.get();
        System.out.println(randomNum);

    }

    /**
     * 引用特定类型的任意对象的实例方法-->特定类::普通方法;
     */
    @Test
    public void test5(){

        // Comparator<Integer> comparator = (o1,o2)->o2.compareTo(o1);
        Comparator<Integer> comparator = Integer::compareTo;  //默认排序

        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(30);
        list.add(20);

        list.sort(Integer::compareTo);//应用场景

        list.forEach(v-> System.out.println(v));
        list.forEach(System.out::println);//等同以上 lambad效果

    }
}

Lambda 表达式

Lambda 表达式:函数式接口实例创建时匿名内部类写法的简化方式

以线程为例演示Lambda 表达式和匿名内部类写法上的区别

public void test() {
 Thread th =new Thread(new Runnable() {
 @Override
 public void run() {
 System.out.println("我是通过内部类实现的线程");
 }
 });
 th.start(); // 输出:我是通过内部类实现的线}
public void test() {
 Thread th = new Thread(() -> System.out.println("我是通过Lambda表达式实现的线程"));
 th.start(); // 输出:我是通过Lambda表达式实现的线程
}

正如你所看到的,使用Lambda表达式不仅让 代码变的简单、而且可读、最重要的是代码量 也随之减少很多

我们可以自定义函数式接口,并通过Lambda表达式定义方法,实现方法的传递,那么Lambda表达式在应用过程中有什么注意事项 和技巧呢?

  • Lambda表达式格式-([参数类型 ]参数名称) ‐> { 代码语句 }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-STPIkLdR-1618990153009)(JavaSE.assets/image-20210106203947427.png)]

/**
 * jdk1.8之后 接口中可以定义非抽象方法  也可以静态方法
 *
 *函数式(功能性)接口: 定义 只有一个抽象方法的接口为 函数式接口
 *       只有函数式(功能性)接口  才支持 Lambda表达式; 语法格式:() -> {}
 */
@FunctionalInterface
public interface MyInterface {

    //void  test1(String name, int age);
    //void  test1(String name);
    int  test1(String name);


    /**
     * 接口中定义非抽象方法  要求必须有  default
     */
    public default void test4(){
        System.out.println("非抽象方法");
    }

    public  static  void test5(){
        System.out.println("静态方法");
    }
}

public class TestMyInterface  {

    public static void main(String[] args) {
        TestMyInterface testMyInterface = new TestMyInterface();
        /*testMyInterface.method1(new MyInterface() {
            @Override
            public void test1(String name, int age) {
                System.out.println(name+""+age);
            }

        });*/

        //Lambda表达式代替以上 匿名内部类的操作
     /*   testMyInterface.method2((name, age)->{

            //重写抽象方法
            System.out.println(name + age+"欢迎您");

        });*/

        //如果{}中只有一行代码 可以省略{}
       // testMyInterface.method2((name, age)-> System.out.println(name + age+"欢迎您"));

        //如果抽象方法只有一个参数 ,()可以省略
      //  testMyInterface.method2(name-> System.out.println(name +"欢迎您"));

        //如果抽象方法只有一个参数 ,()可以省略;{}只有一行  return代码 {}省略的同时  return关键字必须省略
        testMyInterface.method2(name->   10 );

    }

   /* public  void method1(MyInterface myInterface){

        myInterface.test1("小明",10);
        myInterface.test4();//调用非抽象方法
        MyInterface.test5();//调用静态方法
    }*/

    public  void method2(MyInterface myInterface){
        int rs =  myInterface.test1("小明");
        System.out.println(rs);

    }
}

函数式接口

四大内置核心函数式接口

  • Consumner : 消费型接口->有参数,无返回值类型的接口,主要作用是消费传入的形参。
public class Demo1 {
    public static void main(String[] args) {
            Demo1 demo1 = new Demo1();
            demo1.testConsumner(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            });
            demo1.testConsumner(v -> System.out.println(v));
    }

    public  void testConsumner(Consumer<String> action){

        action.accept("10");

    }

    @Test
    public  void testArraylist(){

        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(30);
        list.add(20);

        list.forEach(v -> System.out.println(v));
    }
}
  • Supplier :供给型接口->只有返回值,没有入参,主要作用是返回给调用方一个结果。
public void Test() {
 Supplier sup = () -> "张三";
 String st = (String) sup.get();
 System.out.println(st); // st="张三"
}
  • Function: Function接口->有参数和返回值,作用对传入对象进行操作,并返回结果。
public void Test() {
 Function<Integer, Integer> fun = (Integer num) -> ++num;
 int num = fun.apply(10);
 System.out.println(num);//num=11;
}
//注意:形参类型和返回值类型不必完全一致
  • Predicate:有形参和布尔类型的返回值,作用对传入对象进行判断,并返 回判断结果。
public void Test() {
 Predicate<String> pre =(name) -> {
 if (name != null) return true;
 else return false;
 };
 pre.test("张三");
}
  • 其他接口:除上述四种类型之外的接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kt3GzKEz-1618990153010)(JavaSE.assets/image-20210106194244350.png)]

Stream API

什么是 Stream

  • 数据渠道,用于操作数据源(数组等)所生生成的元素序列。"集合讲的是数据,流讲的是计算!"

  • 注意:

    • Stream 自己不会存储元素
    • Stream 不会改变源对象。相反,他们会返回一个持有结果的新 Stream
    • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
    • Stream 只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历 必须重新生成。
  • Stream 的操作三个步骤

    • 创建 Stream :一个数据源(如:集合、数组),获取一个流

    • 中间操作 :一个中间操作链,对数据源的数据进行处理

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MgsfMRCS-1618990153011)(JavaSE.assets/image-20210106194809271.png)]

    • 终止操作(终端操作) :一个终止操作,执行中间操作链,并产生结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ni6Y536T-1618990153011)(JavaSE.assets/image-20210106194838149.png)]

public class TestStream {

    /**
     * 创建流的方式
     */
    @Test
    public  void test1(){
    //    1    通过Collection中的stream()或者parallelstream()方法创建流

        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(30);
        list.add(20);

        //串行流
        Stream<Integer> stream11 = list.stream();
        //并行流 底层计算机制 是分布式(分区)计算 适用于  大批量数据计算
        Stream<Integer> stream12 = list.parallelStream();

        //    2    通过Arrays中的stream()方法创建流
        IntStream stream2 = Arrays.stream(new int[]{10, 20, 50, 30});

        //    3    通过Stream中的of()静态方法创建流 //of(T... prm) 可变参数
        Stream<String> stream3 = Stream.of("a", "b", "k", "h");


        //     4   通过Stream中的iterate()或者generate()方法创建流 创建无限流
        Stream<Double> stream4 = Stream.generate(() -> Math.random());
        Stream<Double> limitStream = stream4.limit(8);
        limitStream.forEach(v-> System.out.println(v));

    }

    /**
     * 中间操作
     * 1\筛选和切片
     * 2 映射 操作 map()  flatMap()
     * 3 排序 sorted()  sorted(可以传外比较器)
     */
    @Test
    public  void test2(){
        Stream<String> stream = Stream.of("Tom", ",", "Hello", " ", "Hello", "World");
        /*Stream<String> stringStream = stream.filter((str) -> str.equals(",") ? false : true);//过滤操作   中间操作
        Stream<String> limitStream = stringStream.limit(4);//中间操作  截流
        Stream<String> skipStream = limitStream.skip(1);//中间操作 跳过指定 数据源数
        Stream<String> distinctStream = skipStream.distinct();//去重 中间操作
        distinctStream.forEach(v-> System.out.println(v));*/

        /*stream
                .filter((str) -> str.equals(",") ? false : true)
                .limit(4)
                .skip(1)
                .distinct()
                .forEach(v-> System.out.println(v));*/

        //映射 map
       /* Stream<String> stream2 = Stream.of("a", "b", "c", "d", "e", "f");

        Stream<String> stringStream = stream2.map((str) -> str.toUpperCase());
        stringStream.forEach(v-> System.out.println(v));*/

        Stream<String> stream3 = Stream.of("a", "b", "c", "d", "e", "f");
        stream3.flatMap(str->Stream.of(str))
        .sorted((o1,o2)->o2.compareTo(o1)) //中间操作  排序
        .forEach(v-> System.out.println(v));
    }

    @Test
    /**
     * 终止操作
     * 1 查找与匹配
     * 2 规约
     * 3 收集
     */
    public  void test3(){

        /*Stream<String> stream = Stream.of("e", "d", "c", "a", "f", "b");
        boolean boo1 = stream.allMatch((str) -> str.length() == 1 ? true : false);
        System.out.println(boo1); // true*/

        Stream<String>  stream1 = Stream.of("e", "d", "c", "a", "f", "b");
        boolean boo2 = stream1.anyMatch((str) -> "e".equals(str) ? true : false);
        System.out.println(boo2);

        //求和运算  reduce
        Stream<Integer> integerStream = Stream.of(10, 20, 50, 30);
       // Optional<Integer> rs = integerStream.reduce((x, y) -> x + y);
        /*Integer rs = integerStream.reduce(100, (x, y) -> x + y);
        System.out.println(rs);*/

        //收集
        Stream<String>  stream3 = Stream.of("e", "d", "c", "a", "f", "b");
        List<String> collect = stream3.collect(Collectors.toList());
       // Set<String> collect1 = stream3.collect(Collectors.toSet());

        //计算个数
        /*Long collect1 = stream3.collect(Collectors.counting());
        stream3.count();*/


        //summarizingInt 灵活运算
        IntSummaryStatistics collect1 = integerStream.collect(Collectors.summarizingInt(t -> t));
        System.out.println(collect1.getSum());
        System.out.println(collect1.getAverage());

        //分组
        List<Student>  stus = new ArrayList<>();

        Student stu1 = new Student();
        stu1.setSno("1001");
        stu1.setName("小红1");
        stu1.setAge(10);
        stu1.setSex("男");

        Student stu2 = new Student();
        stu2.setSno("1002");
        stu2.setName("小红2");
        stu2.setAge(10);
        stu2.setSex("女");

        Student stu3 = new Student();
        stu3.setSno("1003");
        stu3.setName("小红3");
        stu3.setAge(10);
        stu3.setSex("男");

        //把学生 放进集合容器
        stus.add(stu1);
        stus.add(stu2);
        stus.add(stu3);

        //分组  必须掌握
        Stream<Student> stream2 = stus.stream();
        //分组后的数据 再MAP中键值对管理
        Map<String, List<Student>> collect2 = stream2.collect(Collectors.groupingBy(student -> student.getSex()));//按性别分组
        collect2.forEach((k,v) ->{
            v.forEach(s-> System.out.println(k+"===="+s));
        });

        Stream<String> stream = Stream.of("e", "d", "c", "a", "f", "b");
        ArrayList<String> alist = stream.collect(Collectors.toCollection(ArrayList::new));

        System.out.println(alist); // [e, d, c, a, f, b]
    }
}

Date-Time API

  • Instant
    • 表示一个精确的时间点 ,UTC 时间戳
    • UTC是世界统一时间,又称国际标准时间
    • 时间戳具体是指从格林尼治时间 1970 年 01 月 01 日 00 时 00 分 00 秒(北京时间 1970 年 01 月 01 日 08 时 00 分 00 秒)起至现在的秒数
public void testDate(){
        Instant ins = Instant.now();// UTC (和中国相差8个时区)
        System.out.println(ins);
        System.out.println(ins.getNano());

        System.out.println("-------------------");
        OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));// 时差设置
        System.out.println(odt);
        System.out.println(odt.getHour());
        System.out.println(odt.getNano());

    }
  • 本地时间 (计算日期比较方便)
    • LocalDateTime 表示 日期 + 时间
    • LocalDate 表示日期
    • LocalTime 但只包含时间
public void test2(){
        // 定义
        LocalDateTime ldt = LocalDateTime.now();
        LocalDate ld = LocalDate.now();
        LocalTime lt = LocalTime.now();

        System.out.println(ldt);
        System.out.println(ld);
        System.out.println(lt);

        LocalDateTime ld2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
        System.out.println(ld2);

        // 计算
        System.out.println("------------------");
        LocalDateTime ldt3 = ld2.plusMonths(4);//加法
        System.out.println(ldt3);
        LocalDateTime ldt4 = ld2.minusMonths(2);//减法
        System.out.println(ldt4);

        // 取值
        System.out.println(ldt.getYear());// 其他得均可
        LocalTime time =  LocalTime.now();

    }
  • Duration和Period表示两个时间点之间的时间量
    • Duration : 用于计算两个时间间隔
    • Period : 用于计算两个日期间隔
public void test3() throws InterruptedException {
        Instant ins1 = Instant.now();
        Thread.sleep(1000);
        Instant ins2 = Instant.now();
        Duration dur = Duration.between(ins1, ins2);//Duration中的between()方法计算两个时间之间的间隔

        System.out.println("所耗费时间为:" + dur.getSeconds());

        LocalDate ld1 = LocalDate.now(); // 获取当前日期
        LocalDate ld2 = LocalDate.of(2011, 10, 1); // 自定义日期
        Period pe = Period.between(ld2, ld1); // Period中的between()方法计算两个日进行比较
        System.out.println("间隔月"+pe.getMonths()); //9

    }
  • ZonedDateTime 表示一个带时区的时间
public void test5(){
        Set<String> set = ZoneId.getAvailableZoneIds();//获取所有的时区
        set.forEach(System.out::println);

        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); // 亚洲/上海
        System.out.println(ldt); //  不包括时区


        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific")); // 美国/西海岸
        System.out.println(zdt); //带时区
    }
/**
     * 解析和格式化日期或时间
     */
    @Test
    public void test4() {

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
    //LocalDateTime ldt = LocalDateTime.now();
    LocalDateTime ldt = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
    // 格式化日期
    String strDate = ldt.format(dtf);
    System.out.println(strDate);

    // 2019年06月16日 19:01:52 星期日
    LocalDateTime newLdt = ldt.parse(strDate, dtf);
    // 将String转换为日期时间
    System.out.println(newLdt); // 2019-06-16T19:01:52
    }

st collect = stream3.collect(Collectors.toList());
// Set collect1 = stream3.collect(Collectors.toSet());

    //计算个数
    /*Long collect1 = stream3.collect(Collectors.counting());
    stream3.count();*/


    //summarizingInt 灵活运算
    IntSummaryStatistics collect1 = integerStream.collect(Collectors.summarizingInt(t -> t));
    System.out.println(collect1.getSum());
    System.out.println(collect1.getAverage());

    //分组
    List<Student>  stus = new ArrayList<>();

    Student stu1 = new Student();
    stu1.setSno("1001");
    stu1.setName("小红1");
    stu1.setAge(10);
    stu1.setSex("男");

    Student stu2 = new Student();
    stu2.setSno("1002");
    stu2.setName("小红2");
    stu2.setAge(10);
    stu2.setSex("女");

    Student stu3 = new Student();
    stu3.setSno("1003");
    stu3.setName("小红3");
    stu3.setAge(10);
    stu3.setSex("男");

    //把学生 放进集合容器
    stus.add(stu1);
    stus.add(stu2);
    stus.add(stu3);

    //分组  必须掌握
    Stream<Student> stream2 = stus.stream();
    //分组后的数据 再MAP中键值对管理
    Map<String, List<Student>> collect2 = stream2.collect(Collectors.groupingBy(student -> student.getSex()));//按性别分组
    collect2.forEach((k,v) ->{
        v.forEach(s-> System.out.println(k+"===="+s));
    });

    Stream<String> stream = Stream.of("e", "d", "c", "a", "f", "b");
    ArrayList<String> alist = stream.collect(Collectors.toCollection(ArrayList::new));

    System.out.println(alist); // [e, d, c, a, f, b]
}

}


## Date-Time API

- Instant
  - 表示一个精确的时间点 ,UTC 时间戳
  - UTC是世界统一时间,又称国际标准时间
  -  时间戳具体是指从格林尼治时间 1970 年 01 月 01 日 00 时 00 分 00 秒(北京时间 1970 年 01 月 01 日 08 时 00 分 00 秒)起至现在的秒数

```java
public void testDate(){
        Instant ins = Instant.now();// UTC (和中国相差8个时区)
        System.out.println(ins);
        System.out.println(ins.getNano());

        System.out.println("-------------------");
        OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));// 时差设置
        System.out.println(odt);
        System.out.println(odt.getHour());
        System.out.println(odt.getNano());

    }
  • 本地时间 (计算日期比较方便)
    • LocalDateTime 表示 日期 + 时间
    • LocalDate 表示日期
    • LocalTime 但只包含时间
public void test2(){
        // 定义
        LocalDateTime ldt = LocalDateTime.now();
        LocalDate ld = LocalDate.now();
        LocalTime lt = LocalTime.now();

        System.out.println(ldt);
        System.out.println(ld);
        System.out.println(lt);

        LocalDateTime ld2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
        System.out.println(ld2);

        // 计算
        System.out.println("------------------");
        LocalDateTime ldt3 = ld2.plusMonths(4);//加法
        System.out.println(ldt3);
        LocalDateTime ldt4 = ld2.minusMonths(2);//减法
        System.out.println(ldt4);

        // 取值
        System.out.println(ldt.getYear());// 其他得均可
        LocalTime time =  LocalTime.now();

    }
  • Duration和Period表示两个时间点之间的时间量
    • Duration : 用于计算两个时间间隔
    • Period : 用于计算两个日期间隔
public void test3() throws InterruptedException {
        Instant ins1 = Instant.now();
        Thread.sleep(1000);
        Instant ins2 = Instant.now();
        Duration dur = Duration.between(ins1, ins2);//Duration中的between()方法计算两个时间之间的间隔

        System.out.println("所耗费时间为:" + dur.getSeconds());

        LocalDate ld1 = LocalDate.now(); // 获取当前日期
        LocalDate ld2 = LocalDate.of(2011, 10, 1); // 自定义日期
        Period pe = Period.between(ld2, ld1); // Period中的between()方法计算两个日进行比较
        System.out.println("间隔月"+pe.getMonths()); //9

    }
  • ZonedDateTime 表示一个带时区的时间
public void test5(){
        Set<String> set = ZoneId.getAvailableZoneIds();//获取所有的时区
        set.forEach(System.out::println);

        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); // 亚洲/上海
        System.out.println(ldt); //  不包括时区


        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific")); // 美国/西海岸
        System.out.println(zdt); //带时区
    }
/**
     * 解析和格式化日期或时间
     */
    @Test
    public void test4() {

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
    //LocalDateTime ldt = LocalDateTime.now();
    LocalDateTime ldt = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
    // 格式化日期
    String strDate = ldt.format(dtf);
    System.out.println(strDate);

    // 2019年06月16日 19:01:52 星期日
    LocalDateTime newLdt = ldt.parse(strDate, dtf);
    // 将String转换为日期时间
    System.out.println(newLdt); // 2019-06-16T19:01:52
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值