JavaSE基础入门
本文最后更新于872 天前,其中的信息可能已经过时,如有错误请评论留言

Java简介

Java发布于1995年5月23日,Java前身是Oak语言,衍生自C++,Java之父是詹姆斯·亚瑟·高斯林,Java最早是sun公司的产品,2009年被Oracle公司收购,现属于Oracle公司的产品。

Java的版本

最初版本

​ 1995年1.0版本;1.1版本

Java2平台

​ 1.2 1.3 1.4 1.5

走出Java2

6

易主Oracle

​ 2011年7,8

新的举措,每半年发布一个版本

9, 10 ,11 ,12,....

Java的版本类型

JavaSE,Java标准版本,可以开发Java控制台程序,桌面程序等。为JavaEE提供基础

JavaEE,Java企业级版本,现以捐献给eclipse基金会,改名为JakartaEE(雅加达EE)。它是一套规范,由第三方对他具体实现。在实际开发中,一般使用框架来代替它

Java语言特点

1.面向对象

2.跨平台

3.健壮性

4.简单易学 废弃c中的指针操作

5.多线程

6.动态性

7.分布式

Java平台的组成部分

JVM:Java虚拟机,使Java程序跨平台

JRE:Java运行环境,包含JVM以及常用类库,运行Java程序的最小单位

JDK:Java开发工具包,包含JRE,以及编译工具,打包工具,开发Java程序的最小单位

IDE:集成开发环境,eclipse,Myeclipse,idea

第一个Java程序

创建项目:File → New(Other) → Java Project → Project Name → Finish

创建包:src右键 → New → Package → Name → Finish

创建类:在包上右键 → New → Class → Name → Finish

注释:

单行注释://

多行注释:/ /

文档注释:/* /

输出语句

1.不换行输出:System.out.print();

2.换行输出:System.out.println();

转义字符

双引号:\ "

单引号:\ '

反斜线:\ \

制表符:\t(Tab键,适合不对齐输出)

换行:\n

JAVA和JAVAC命令的作用

JAVAC:作用是将.java文件编译生成.class字节码文件

JAVA:作用将.class字节码文件解释并执行

数据类型

1、基本数据类型

整数类型

​ byte 字节型 1个字节 8位 范围:-128~127

​ short 短整型 2个字节 16位 范围:-32768~32767

​ int 整型 4个字节 32位 范围:约正负21亿

​ long 长整型 8个字节 64位 范围:约为正负922亿亿 后缀:L或l

浮点类型

​ float 单精度 4个字节 32位 后缀:F或f

​ double 双精度 8个字节 64位 后缀:D或d

字符类型

​ char 字符型 2个字节 16位 范围:0~65535(\u0000~\uFFFF)

布尔类型

​ boolean 布尔型 1个或4个 8或32位 值:true false

2、引用数据类型

类类型(class)

​ 字符串(String),多个字符组成了字符串,用双引号表示,如"高斯林"

数组类型(array)

接口类型(interface)

枚举类型(enum)

注解类型(annotation)

变量

程序中可以改变的量

变量的三大要素(三大组成部分)

数据类型 变量名 变量值

1.声明变量:数据类型 变量名;int a;

2.变量赋值:变量名 = 值; a = 10;

合并:数据类型 变量名 = 值; int a = 10;

3.声明多个同一类型的变量

数据类型 变量名1,变量名2,...

变量名的建议规范

变量名遵循驼峰命名法,即首字母小写,其后每个单词首字母大写,strScore

不建议使用汉字,尽量使用英文单词或拼音,要见名知意

不建议使用单个字母命名,约定俗成的除外

不建议以下划线开头,不建议使用$

命名法:

驼峰命名法:classId

帕斯卡命名法:ClassId

蛇底式命名法:class_id

尖叫蛇底式命名法:CLASS_ID

标识符强制规范

1.可由字母,数字,下划线,$组成

2.不能以数字开头

3.字母区分大小写

4.不能使用关键字,字面量,保留字

5.在同一作用域下名称不能重名

关键字:是Java定义好的具有特定含义的单词,public ,class ,int...

字面量:是Java定义好的一些值:true,false,null

保留字:是Java的前身Oak和前代语言C、C++的关键字,但是在Java中没有使用却保留下来的,const,goto

控制台输入

Scanner是用来输入的,首先定义一个Scanner

​ Scanner sc = new Scanner(System.in);

导入Scanner

​ 1.在package下面,写上import java.util.Scanner;

​ 2.将鼠标放在Scanner上面,根据提示,选择...

​ 3.将光标放在Scanner后面,按Alt+/(?)

​ 4.使用快捷键:按Ctrl+Shift+o,会自动导入所有所需要的类

一般语法:sc.next类型(),类型要求首字母大写

​ 输入double类型:sc.nextDouble()

​ 输入int类型:sc.nextInt()

​ 输入字符串String:sc.next()

没有char类型的输入

类型转换

1.自动类型转换(隐式类型转换)

​ 范围小的类型转到范围大的类型

2.强制类型转换

​ 范围大的类型转到范围小的类型

​ (想要转到的类型)变量

​ 强制类型转换可能出现溢出(精度丢失)

3.在八大基本类型中,除了boolean之外的七种类型都可以互相转换

字符串转基本类型

​ 一般语法:数据类型.parse数据类型(字符串),数据类型首字母大写

​ double score = Double.parseDouble(strScore);

​ 1.字符串转int类型:Integer.parseInt(字符串);
​ int port = Integer.parseInt(strPort);

​ 2.对于字符串转布尔类型,如果字符串是true(不区分大小写),则结果为true,否则为false

​ 3.没有转成char类型的方法
基本类型转字符串

​ ""+基本类型变量或数值

运算符

算术运算符,赋值运算符,关系运算符,逻辑运算符,条件运算符

【算术运算符】

​ +、-、*、/、%、++、--

​ 1.两个整数相除的结果是整数(即整除),若想得到小数结果,需要将其中一个强制类型转换成浮点数

​ 2.利用整除可以去掉最后一位:整数/10

​ 3.浮点类型的计算不一定精准(加减乘除%)

​ 4.取余数

​ 1)负数取余数,以第一个数的正负为准,若第一个数是正数,则结果为正,若第一个数是负数,则结果为负

​ 2)判断奇偶,数%2,若结果是0则是偶数,若结果非0则是奇数

​ 3)获取整数的最后一位:整数%10

​ 4)判断整数:数%1,若结果是0则是整数,若结果非0则是奇数

​ 5.两种类型进行计算的结果

​ 1)都是整数类型,若由long类型参与,则结果为long类型,否则为int类型

​ 2)若有浮点类型参与,如果有double类型参与,则结果为double类型,否则为float类型

​ 6.除了boolean之外的七种类型,都可以进行算术运算

​ 7.++、--

​ ++:自加1 --自减1

​ a++:先用后加

​ ++a:先加后用

        // 习题
        int i=1;
        //int c = i++ + ++i;
        int a = i++;//a=1 i=2
        int b = ++i;//b=3 i=3
        int c = a+b;//c=4
        System.out.println(i);
        System.out.println(c);

        int x = 1;
        x = x++;
        x = x++;
        x = x++;
        // ...
        System.out.println(x);// 值永远不变

【赋值运算符】

​ 1.简单赋值运算符(普通赋值运算符):=

​ 2.复合赋值运算符:+= -= *= /= %=

​ short a = 1;

​ a+=2;//a变为3

​ a+=2和a=a+2并不完全一样,a+=2里边存在一个隐式的类型转换

​ 相当于a=(a的类型)(a+2),结果是+=左边的类型

        // 完成两值交换
        int x = 1;
        int y = 9;
        int z = x;//z=1
        x = y;//x=9
        y = z;//y=1
        System.out.println(x);//9
        System.out.println(y);//1

        short a = 1;
        //a += 2;
        a = (short)(a+2);
        System.out.println(a);

【关系运算符】

 //>,>=,<,<=,==(等于),!=(不等于)。结果是布尔类型

【逻辑运算符】

​ 与 或 非

​ 与:并且,如果两个条件同时为true,则结果是true

​ &&:短路与,如果第一个条件为false,则不会判断第二个条件

​ &:非短路与,即使第一个条件为false,也会判断第二个条件

​ 或:或者,如果有一个条件为true,则结果为true

​ ||:短路或,如果第一个条件为true,则不会判断第二个条件

​ |:非短路或,即使第一个条件为true,也会判断第二个条件

​ 非:取反 !

【条件运算符】

​ ? :

​ 布尔类型表达式 ? 结果为true则执行此部分 : 否则执行此部分

    // 求a,b,c的最大值
        int a = 50;
        int b = 10;
        int c = 30;

        int max;
        // 方式一
//      max = a > b ? a : b;
//      max = max > c ? max : c;
        // 方式二
        max = (a > b ? a : b) > c ? (a > b ? a : b) : c;
        System.out.println(max);

【按操作数划分】

一元运算符(单目运算符):只有一个操作数,如:a++,-1

二元运算符(双目运算符):有两个操作数,如a+b

三元运算符(三目运算符):有三个操作数,即?:

快捷键

万能键:alt+/(?) main=>主方法

复制:ctrl+c

粘贴:ctrl+v

剪切:ctrl+x

撤回:ctrl+z

删除一行:ctrl+d

保存:ctrl+s

单行注释:ctrl+/(?)

多行注释:ctrl+shift+/(?)

变成大写:ctrl+shift+x

变成小写:ctrl+shift+y

流程控制

1、顺序执行

分支语句

if、switch

if

一、单分支

if(条件){

​ // 如果条件为true,则执行此部分代码

}

二、双分支

if(条件){

​ // 如果条件为true,则执行此部分代码

}else{

​ // 否则执行此部分

}

三、多分支

if(条件1){

​ // 如果条件1为true,则执行此部分代码,不会判断下面的条件

}else if(条件2){

​ // 如果条件2为true,则执行此部分代码,不会判断下面的条件

}...else{

​ // 如果以上条件都不满足,则执行此部分代码

}

当代码块语句是一句执行语句时,{}可以省略不写

switch:开关语句

switch(变量){

case 值1:

​ // 如果变量和值1相等,则执行此部分代码

​ break;

case 值2:

​ // 如果变量和值2相等,则执行此部分代码

​ break;

...

default:

​ // 如果变量和以上值都不相等,则执行此部分代码

}

注意:

​ 1.case贯穿:如果没有break,会继续执行,直到遇到一个break或者程序结束

​ 2.case后面必须是一个具体的值,不能是变量,也不能是多个值,也不能表示范围

​ 3.case的值不能重复

​ 4.switch支持的6种类型:byte,short,int,char,String(Java 7),枚举(Java 5)

循环

1.while循环 2.for循环 3.do-while 4.新型for循环

while循环

确定循环次数

1.初始变量

while(2.循环条件){

​ 3.循环体

​ 4.迭代因子

}

执行顺序:1234 234 234...

for循环

for(1.初始变量;2.循环条件;4.迭代因子){

​ 3.循环体

}

执行顺序:1234 234 234...

应用场景:

1.for循环适合确定循环次数的场景

2.while循环适合不确定循环次数的场景

循环控制

1.break:终止整个循环

2.continue:终止本次循环,还会执行下次循环

do-while

1.初始变量

do{

​ 3.循环体

​ 4.迭代因子

}while(2.循环条件);

执行顺序:1342 342 ...、

do while循环至少执行一次

数组

1.声明数组:数据类型[] 数组名;

​ 数据类型 数组名[]; 不推荐

2.实例化数组:数组名 = new 数据类型[长度];

合并:声明并实例化对象:数据类型[] 数组名 = new 数据类型[长度];

​ 注意:数组长度是int类型

3.使用数组

​ 1)为元素赋值:数组名[索引] = 值

​ 索引,下标,下角标,角标,从0开始,最大索引比长度小1

​ 2)获取元素值:数组名[索引]

4.数组长度:数组名.length


        int[] scores = new int[3];
        scores[0] = 90;
        scores[1] = 80;
        scores[2] = 99;

        //遍历数组
        //方式一
//      for (int i = 0; i < scores.length; i++) {
//          System.out.println(scores[i]);
//      }

        /*
         *  新型for循环,增强for循环,foreach循序,迭代循环,for循环
         *  for(元素的数据类型  变量名 : 数组名){
         *      // 每次循环,变量的值,就是数组中每个元素值
         *  }
         */
        // 方式二
        for(int score : scores) {
            System.out.println(score);
        }

5.数组默认值

整数类型:0

​ byte:byte(0)

​ short:short(0)

​ int:0

​ long:0L

浮点类型:0.0

​ float:0.0F

​ double:0.0

字符类型:char \u0000,实际上就是0

布尔类型:false

字符串:null

6.数组初始化

1.数据类型[] 数组名 = new 数据类型[]{值1,值2,...};

2.数据类型[] 数组名 = {值1,值2,...};此方式只能在声明数组时使用

ArrayIndexOutOfBoundsException 下标越界异常

冒泡排序

    public static void main(String[] args) {
        int[] arr = { 25, 16, 7, 51, 65, 78, 91, 1 };
        for (int i = 0; i < arr.length-1; i++) {
            /*
             * i    7-i
             * 0    7
             * 1    6
             * 2    5
             * 3    4
             * 4    3
             * 5    2
             * 6    1
             */
            for(int j=0; j<arr.length-1-i; j++) {
                // 交换   小-》大
                if(arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }

数组排序:Arrays.sort(数组名); 默认是正序排序

数组转字符串:Arrays.toString(数组名);

数组扩容:Arrays.copyOf(数组名, 新长度)

​ 扩容:新长度比原长度大

​ 缩容:新长度比原长度小

二维锯齿数组

数据类型[ ] [ ] 数组名 = new 数据类型[长度] [长度]

int[] [] nums = new int[2] [3];

nums[0] [0] nums[0] [1] nums[0] [2]

nums[1] [0] nums[1] [1] nums[1] [2]

nums是一个数组,里面有2个元素,长度是2

nums[0]是一个数组,里面有3个元素,长度是3

nums[1]是一个数组,里面有3个元素,长度是3

public static void main(String[] args) {
        /*
         * 二维锯齿数组
         */
        // int[][] nums = new int[2][3];
        int[][] nums = new int[2][];
        nums[0] = new int[3];
        nums[1] = new int[2];
        // 第一行
        nums[0][0] = 1;
        nums[0][1] = 2;
        nums[0][2] = 3;
        // 第二行
        nums[1][0] = 4;
        nums[1][1] = 5;
//      System.out.println(nums.length);// 2
//      System.out.println(nums[0].length);// 3
//      System.out.println(nums[1].length);//2

        // 遍历二维锯齿数组
        for (int i = 0; i < nums.length; i++) {
            for(int j=0;j<nums[i].length;j++) {
                System.out.print(nums[i][j]+" ");
            }
            System.out.println();
        }

    }

面向对象

面向过程:是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现,注重的是具体实现 过程,每个步骤亲历亲为

​ 例:吃饺子=》和面,和馅,包,蒸,....自己弄

面向对象:是模型化的,注重的是对象与对象之间的协作,不必去一步一步的实现

​ 例:吃饺子=》点外面,商家做,骑手送,自己吃

​ 优点:易维护,易复用,易扩展,由于面向对象有封装,继承,多态的特性,可以设计出低耦合的系统,使系 统更加灵活,更加易于维护

类:是一种抽象的表示,可以把具有相同特征的事物归为一类,例:人类,车类,鸟类

对象:类别中具体的一个事物

对象的成员:

​ 1.属性:指对象的特征

​ 2.方法:指对象的动作(行为)

定义类

访问修饰符 class 类名{

}

定义方法

访问修饰符 返回值类型 方法名(参数列表){

​ 方法体

}

方法参数:方法中需要数据,但是它本身没有,需要从外部传入时,就要定义参数

形参:形式参数,在方法定义时写的参数

实参:实际参数,在方法调用时传入的参数

返回值:外部需要方法内部数据

​ 1.在定义方法时,需要指定返回值类型

​ 2.在方法体中,使用return关键字,返回一个具体的值

方法重载:方法名相同,参数列表不同(参数的个数不同,参数类型不同)

方法签名:方法名+参数列表

可变长参数/不定长参数:数据类型...变量名。可变长参数必须是最后一个参数

package com.zretc.javase.d0302.p1;

public class Cal {

    /*
     *  方法重载:方法名相同,参数列表不同(参数个数不同,参数类型不同)
     *  方法签名:方法名+参数列表
     */
    public int add(int a, int b) {
        return a + b;
    }

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

    /*
     *  可变长参数:数据类型... 变量名
     *  可变长参数必须是最后一个参数
     */
    // 求多个整数的和
    public int add(int... nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;// sum = sum+num
        }
        return sum;
    }

    public double add(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        Cal cal = new Cal();
//      double sum = cal.add(1.2, 1.3);
//      System.out.println(sum);

        //int[] nums = { 1, 2, 35, 8 };
        System.out.println(cal.add(1,2,3,4));
    }

}

成员变量(字段,域)

成员变量默认值:

整数类型:0

​ byte:(byte)0

​ short:(short)0

​ int:0

​ long:0L

浮点类型:0.0

​ float:0.0F

​ double:0.0

字符类型:\u0000

布尔类型:false

类类型:null

成员变量和局部变量区别:

1.作用域不同:

​ 局部变量的作用域仅局限于它的方法

​ 成员变量的作用域在整个类内部都是可见的,还可以在外部访问

2.初始值不同

​ Java会给成员变量一个初始值

​ Java不会给局部变量一个初始值

3.在同一方法中,不允许有同名局部变量

​ 在不同方法中,可以有同名局部变量

4.两类变量同名时,局部变量具有更高的优先级

面向对象三大特征

封装,继承,多态

封装

1.定义一个方法是一种封装

2.成员变量或方法用private修饰是一种封装

属性组成部分:属性变量和属性访问器

属性变量:用于表示属性的成员变量

属性访问器:setter和getter

属性名:setter和getter去掉set和get后,剩下部分首字母小写

只读属性:只有getter没有setter

    private String name;
    // 赋值方法 setter set访问器
    public void setName(String name) {//name
        // this:本类对象
        this.name = name;
    }

    // 取值方法 getter get访问器
    public String getName() {
        return name;
    }

构造器(构造方法)

没有返回值类型,名称和类名相同

默认构造方法

​ 1.如果不创建构造方法,也有一个默认的构造方法

​ 2.默认构造方法没有参数

​ 3.如果创建了有参构造方法,则默认构造方法消失

在构造器中调用本类其他构造器:this(参数)

this()必须写在构造器的第一行代码上

package com.zretc.javase.d0303.p2;

public class Student {

    private String name;
    private int score;

    public Student() {
        System.out.println("调用了构造方法");
    }

    public Student(String name,int score) {
        this();
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

}
    public static void main(String[] args) {
        // 构造方法是在实例化对象时自动调用
        Student st = new Student("高斯林", 90);
        System.out.println(st.getName() + "," + st.getScore());
    }

静态方法(类方法)

是属于类的,不属于对象,使用类调用

静态方法不能调用成员方法,也不能使用成员变量

静态方法不能使用this

成员方法可以调用静态方法,也可以使用静态变量

静态块,静态代码块

static{

}

在第一次使用类时自动调用,而且只调用一次

静态块的执行要优先于主方法的执行

静态块和静态方法的区别:

1.静态块自动调用,静态方法手动调用

2.静态块只能调用一次,静态方法可以调用多次

3.静态块没有访问修饰符,返回值类型,名称,参数,静态方法有

动态块:{},实例化对象时自动调用

继承

减少代码冗余,实现代码重用性

访问修饰符 class 子类 extends 父类{

}

子类又叫派生类

父类又叫基类,超类

单继承:子类只能继承一个父类,如Java

多继承:子类可以继承多个父类,如C++

继承中的构造器

1.先调用父类构造器,再调用子类构造器

2.子类默认调用父类的无参构造器

3.构造器不能继承

4.子类调用父类构造器:super(参数),super()必须写在构造器的第一行代码上

5.如果父类没有无参构造器,则子类必须手动调用父类的其他构造器

super:父类的

super.属性:父类的属性

super.方法(参数):父类的方法

super(参数):父类的构造器,必须放在第一行

this:本类对象

this.属性:当前对象属性

this.方法:当前对象的方法

this(参数):当前构造方法,必须放在第一行

访问修饰符

本类 本包其他类 其他包子类 其他包
public (公有的)
protected (保护的)
默认的
private (私有的)

重写

重写:子类重新写父类的方法

一大两小两相同

两相同:方法名相同,参数列表相同

一大:访问修饰符要大于等于父类

两小:1)返回值类型要小于等于父类的

如果是基本类型和void,必须保持一致

2)抛出异常的类型要小于等于父类的

不能重写的方法:

1.构造方法不能重写

2.私有方法不能重写

3.静态方法不能重写

4.final修饰的方法不能重写

重载与重写的相同点和不同点

重写与重载 重写(override) 重载(overload)
作用域 子重写父的 同一作用域(子重载父的,重载自己)
方法名 必须一致 必须一致
参数列表 必须一致 必须不一致
返回值类型 返回值类型要小于等于父类的,如果是基本类型和void必须保持一致 无所谓
访问修饰符 子大于等于父 无所谓
异常 抛出异常的类型要小于等于父类的 无所谓
次数 一次 多次

多态

同一种行为,产生的结果不同

满足多态的条件:继承 重写 向上转型

面向对象三大特征:封装 继承 多态

面向对象四大特征:封装 继承 多态 抽象

final能修饰什么

1.修饰类,不能被继承

2.修饰方法,不能被重写

3.修饰变量,不能被重复赋值

​ 1)成员变量用final修饰,可以在定义时赋值,也可以在构造器和动态块中赋值

​ 2)常量:一般是公有静态常量,public static final修饰

​ 命名规范:所有字母都大写,每个单词之间用下划线分隔(尖叫蛇底式命名法)

​ 3)局部变量用final修饰,在使用前赋值即可,但只能赋值一次

4.参数上用final修饰,不可以赋值,值是通过方法调用传过来的,在方法内部不能改值

JVM内存

栈帧:JVM为每一个方法都定义了一个栈帧,栈帧中存放局部变量

堆:实例化出来的对象,成员变量

方法区:静态变量,方法信息

抽象

抽象类:类上用abstract修饰

抽象方法:方法上用abstract修饰,没有方法体

抽象类不能实例化对象

抽象类可以有抽象方法,也可以有非抽象方法

如果子类不是抽象类,则必须实现父类的抽象方法

如果子类也是抽象类,则可以不实现父类的抽象方法

private 和 abstract 不能连用

final和abstract 不能连用

接口

是一种公共的规范标准,引用数据类型

定义接口:

[访问修饰符] interface 接口名{

}

1.在默认情况下,接口中的方法都是公有抽象方法(public abstract)

2.接口不能实例化

3.接口中没有构造器

4.接口中的变量,都是公有静态常量(public static final修饰)

5.在Java8中,提供了接口的默认方法(default)和静态方法

6.在Java9中,提供了接口的私有方法

7.定义一个类实现接口的语法:

访问修饰符 class 类名 implements 接口名1,接口名2...{

}

8.类是单继承,接口可以多实现,多继承

9.实现类既可以继承父类,又可以实现接口

访问修饰符 class 类名 extends 父类 implements 接口名1,接口名2...{

}

10.接口继承接口

访问修饰符 interface 接口名 extends 接口名1,接口名2...{

}

11.抽象类与接口

抽象类 接口
定义关键字 abstract class interface
继承关系 单继承 多继承
构造方法 没有
实例化对象 不能 不能
普通成员 可以 不能有变量,普通方法是jdk8之后可以
与接口的关系 多实现【implements】 多继承【extends】

instanceof

判断左边的对象是否属于右边类的实例,结果是boolean类型,是返回true,不是返回false

class Tree{} 
class Pine extends Tree{} 
class Oak extends Tree{} 
public class Forest { 
    public static void main( String[] args ) { 
        Tree tree = new Pine(); 
        if( tree instanceof Pine ) // true
            System.out.println( "Pine" ); 
        if( tree instanceof Tree ) // true
            System.out.println( "Tree" ); 
        if( tree instanceof Oak ) // false
            System.out.println( "Oak" ); 
        else 
            System.out.println( "Oops" ); 
    } 
}
则输出结果中有哪些? ABD
A.Pine  B.Tree  C.Forest  D.Oops E.无输出

内部类

静态内部类 动态内部类 局部内部类 匿名内部类

静态内部类

访问修饰符 class 外部类{

​ 访问修饰符 static class 内部类{

​ }

}

public class Outer {

    private static int n = 1;

    public static class Inner {
        private int n = 2;

        public void show() {
            int n = 3;
            System.out.println(Outer.n + "," + this.n + "," + n);
        }
    }

    public void display() {
        Inner inner = new Inner();
        inner.show();
    }

}

在外部访问静态内部类:外部类.内部类 变量 = new 外部类.内部类();

Outer.Inner inner = new Outer.Inner();
inner.show();

动态内部类

访问修饰符 class 外部类{

​ 访问修饰符 class 内部类{

​ }

}

在外部访问动态内部类:

外部类 变量 = new 外部类();

外部类.内部类 变量 = 外部类变量.new 内部类();

public class Outer {
    private int n = 1;

    public class Inner {
        private int n = 2;

        public void show() {
            int n = 3;
            System.out.println(Outer.this.n + "," + this.n + "," + n);
        }
    }

    public void display() {
        Inner inner = new Inner();
        inner.show();
    }

}
    public static void main(String[] args) {
//      Outer outer = new Outer();
//      outer.display();

        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.show();
    }

局部内部类

public class Test {

    public static void main(String[] args) {
        // 局部内部类
        class Inner{
            public void show() {
                System.out.println("a");
            }
        }

        Inner inner = new Inner();
        inner.show();
    }

}

匿名内部类

public class Test {

    public static void main(String[] args) {
        /*
         *  匿名内部类
         */
        Human h = new Human() {
            @Override
            public void work() {
                System.out.println("工作");
            }
        };

        h.work();

    }

}

类能用什么访问修饰符修饰

1.对于外部类,只能用public和默认(不写)

2.对于内部类:

​ 1)如果是静态内部类和动态内部类,四种都可以

​ 2)如果是局部内部类和匿名内部类,不可以写

String

字符串

charAt(int index) :依据索引查找字符

compareTo():字符串比较,正数:第一个串大,负数:第二个串大,0:相等

compareToIgnoreCase:不区分大小写比较

contains:判断是否存在

startsWith:判断是否以某子串开头

endsWith:判断是否以某子串结尾

equals:判断字符串相等

equalsIgnoreCase:不区分大小写判断字符串相等

getBytes():将字符串转成byte数组

indexOf():依据元素查找索引(从左往右查找第一个)

lastIndexOf():依据元素查找索引(从左往右查找最后一个)

length():字符串长度

isEmpty():判断是否是空串

replace(旧串, 新串):字符串替换

split(分隔符):字符串分隔,返回值类型是字符串数组,注意:如果遇到分隔符出现错误,需要将分隔符用\ \转义

substring(开始位置,结束位置):截取子串,不包含结尾位置,含头不含尾、

substring(开始位置):从开始位置截取到最后

toCharArray():字符串转char类型数组

toLowerCase():转成小写

toUpperCase():转成大写

trim():去掉左右两边空格

package com.zretc.javase.d0309;

import java.util.Arrays;

public class StringDemo {

    public static void main(String[] args) {
        // 01234567
        String str = "abcdefga";
        // 依据索引查找字符 索引从0开始,最大索引比长度小1
        System.out.println(str.charAt(0));
        String s1 = "abc";
        String s2 = "ABC";
        // 字符串比较,正数:第一个串大,负数:第二个串大,0:相等
        System.out.println(s2.compareTo(s1));
        // 不区分大小写的比较
        System.out.println(s1.compareToIgnoreCase(s2));
        // 判断是否存在
        System.out.println(str.contains("df"));
        // 判断是否以某子串开头
        System.out.println(str.startsWith("ab"));
        // 判断是否以某子串结尾
        System.out.println(str.endsWith("ab"));
        // 判断字符串相等
        System.out.println(s1.equals(s2));
        // 不区分大小写判断字符串相等
        System.out.println(s1.equalsIgnoreCase(s2));
        // 将字符串转成字节数组
        byte[] bs = str.getBytes();
        // 将数组转字符串输出
        System.out.println(Arrays.toString(bs));
        // 依据元素查找索引(从左往右)
        System.out.println(str.indexOf("a"));
        // 依据元素查找索引(从左往右找最后一个)
        System.out.println(str.lastIndexOf("a"));
        // 判断是否是空串
        System.out.println(str.isEmpty());
        // 字符串长度:str.length()
        System.out.println(str.length() == 0);
        // 字符串替换
        System.out.println(str.replace("ab", "q"));
        /*
         *  字符串分割:返回值类型是字符串类型数组
         *  如果遇到分隔符出现错误,需要将分隔符用\\转义
         */
        String strArr = "tom.amy.john";
        String[] arr = strArr.split("\\.");
        System.out.println(Arrays.toString(arr));

        /*
         *  截取子串:字符串.substring(开始位置,结束位置):不包含结尾位置,含头不含尾、
         *          字符串.substring(开始位置):从开始位置截取到最后
         */
        String str2 = "ABC";
        System.out.println(str2.substring(1));
        // 字符串转char类型数组
        char[] cs = str2.toCharArray();
        System.out.println(Arrays.toString(cs));
        // 转成大写
        System.out.println(str2.toUpperCase());
        // 转成小写
        System.out.println(str2.toLowerCase());

        String ss = "    abc   ";
        // 去掉左右两边空格
        System.out.println(ss.trim());

    }

}

字符串常量池:程序当中直接写上的双引号字符串,就在你的字符串常量池里

对于基本类型:==是进行数值的比较

对于引用类型:==是进行地址值的比较

地址相同的情况:

情况1:

​ String str1 = "abc";

​ String str2 = "abc";
情况2:

​ String str1 = "abc";

​ String str2 = "ab"+"c";

地址不相同的情况:

情况1:

​ String str1 = "abc";

​ String s = "c";

​ String str2 = "ab" + s;

情况2:

​ String str1 = new String("abc");

​ String str2 = new String("abc");

情况3:

​ Scanner sc = new Scanner(System.in);

​ String str1 = "abc";

​ String str2 = sc.next();

StringBuilder,StringBuffer

​ 专门用来字符串拼接的,拼接时不生成新的对象,拼接速度快

String,StringBuilder,StringBuffer的区别:

1.String是常量,值不能改变,拼接字符串时生成新的对象,拼接速度慢

​ StringBuilder和StringBuffer是动态拼接,拼接时不生成新的对象,拼接速度快

2.StringBuilder和StringBuffer提供了更多的方法,如插入删除等

3.StringBuilder是线程不安全的,拼接速度稍快

​ StringBuffer是线程安全的,拼接速度稍慢

        StringBuilder s = new StringBuilder();
        // 添加字符串
        s.append("ab");
        s.append("Hello");
        System.out.println(s);
        // 插入字符串
        s.insert(1, "q");
        System.out.println(s);
        // 删除字符串 含头不含尾
        s.delete(1, 4);
        System.out.println(s);

        StringBuilder ss = new StringBuilder("abcd");
        // 字符串反转
        System.out.println(ss.reverse());

包装类型

每一个基本类型,都对应着一个类,它将基本类型封装到类中,添加了额为得功能,还可以赋值为null。

基本类型 包装类型 父类型
byte Byte Number
short Short Number
int Integer Number
long Long Number
float Float Number
double Double Number
char Character Object
boolean Boolean Object

装箱:基本类型转换成包装类型的过程

拆箱:包装类型转换成基本类型的过程

【手动拆装箱】

Java 5 之前

手动装箱:将基本数据写在包装类型的构造器中

手动拆箱:包装类型变量.xxxValue();

【自动拆装箱】

自动装箱:包装类型 变量 = 基本类型值 Integer a = 12;

自动拆箱:基本类型 变量 = 包装类型变量 int b = a;

自动装箱的注意事项:赋值时,要严格对应上类型。

如:Long num = 1L;

​ Double num2 = 10D;

包装类型比较用equals方法

【整型池】

整型缓存池,整型常量池

范围:-128~127

Integer a = 128;

Integer b = 128;

System.out.println(a >= b);// true

首先将两个包装类型变量自动拆箱成基本类型,然后比较基本类型的值

类型转换:

包装类型.parse类型(字符串):返回基本类型

包装类型.valueOf(字符串):返回包装类型

String str = "12";

int num = Integer.parseInt(str);

Integer num2 = Integer.valueOf(str);

MAX_VALUE:最大值

MIN_VALUE:最小值

SIZE:位数

Double

NaN:Not a Number

NaN和任何一个数都不相等,包括它自己

Double.isNaN():判断是否是NaN

Double.NaN:0.0d / 0.0

Infinity:正无穷大

-Infinity:负无穷大

Double.POSITIVE_INFINITY:1.0/0.0

Double.NEGATIVE_INFINITY:-1.0/0.0

        double num = 0.0 / 0.0;
        System.out.println(num);// NaN:Not a Number
        System.out.println(num == num);// false, NaN和任何一个数都不相等,包括它自己
        System.out.println(Double.isNaN(num));// 判断是否是NaN

        System.out.println(Double.NaN);

        System.out.println(-1.0 / 0.0);

        System.out.println(Double.POSITIVE_INFINITY);

        System.out.println(Double.NEGATIVE_INFINITY);

        double a = Double.NEGATIVE_INFINITY;
        System.out.println((a + 1) == a);// true

Character

    public static void main(String[] args) {
        char c = ' ';
        // 判断是否是整数
        System.out.println(c >= '0' && c <= '9');
        System.out.println(Character.isDigit(c));
        // 判断是否是小写字母
        System.out.println(c >= 'a' && c <= 'z');
        System.out.println(Character.isLowerCase(c));
        // 判断是否是大写字母
        System.out.println(c >= 'A' && c <= 'Z');
        System.out.println(Character.isUpperCase(c));
        // 判断是否是字母
        System.out.println((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
        System.out.println(Character.isLetter(c));
        // 判断是否是字母或者数字
        System.out.println((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'));
        System.out.println(Character.isLetterOrDigit(c));
        // 判断是否是空白字符
        System.out.println(Character.isWhitespace(c));

    }

正则表达式

Java是从Java 1.4开始支持的正则表达式

正则表达式,简写为regex,regxp,regexp

是用于匹配、查找、替换文本等操作的表达式

正则表达式中包含普通字符和元字符

元字符就是一类特殊的字符,有具体的含义

^、$:开始和结束

[abc] :匹配abc中任意字符

[^abc] :除了abc的任意字符

[a-z] :a到z之间的字符

[a-zA-Z0-9] :a到z,A到Z,0到9之间的任意字符

\d :数字字符,等效于[0-9]

\w :单词字符,等效于[a-zA-Z0-9_]

\s :空白字符,如空格,制表符,换行,回车

\D :非数字字符

\W :非单词字符

\S :非空白字符

? :0到1个

*:0到多个

+:1到多个

. :任意字符

| :或者

\ :转义

X{n}:n个X

X{n,}:n到多个X

X{n,m}:n到m个X

^:非

():分组

    public static void main(String[] args) {
        String str = "中国";
        // 验证是否是整数
        boolean ok = str.matches("^\\d+$");
        System.out.println(ok);

        // 验证是否是小数
        boolean ok2 = str.matches("^\\d+\\.\\d+$");
        System.out.println(ok2);

        // 验证两位小数
        boolean ok3 = str.matches("^\\d+\\.\\d{2}$");
        System.out.println(ok3);

        // 验证整数或者小数
        boolean ok4 = str.matches("^\\d+(\\.\\d+)?$");
        System.out.println(ok4);

        // 验证大多数汉字  :\u4E00 \u9FA5
        boolean ok5 = str.matches("^[\u4E00-\u9FA5]+$");
        System.out.println(ok5);

    }
    public static void main(String[] args) {
        String str = "abc123dea456wers";
        // str = str.replace("123", "-");
        str = str.replaceAll("\\d+", "-");
        System.out.println(str);

        String str2 = "Java.Python.PHP";
        String[] ss = str2.split("\\.");
        System.out.println(Arrays.toString(ss));
    }
    public static void main(String[] args) {
//      String str = "Java123Python456";
//      // 模式对象,设置正则表达式
//      Pattern p = Pattern.compile("[a-zA-Z]+");
//      // 匹配对象,匹配字符串
//      Matcher m = p.matcher(str);
//      // 判断有没有找到匹配上的字符串
//      while (m.find()) {
//          System.out.println(m.group());// 匹配上的字符串
//      }

        // 键值对
        String str = "n@ame=to@%m;salary=18000;";
        Pattern p = Pattern.compile("([^=]+)=([^;]+);");
        Matcher m = p.matcher(str);
        while (m.find()) {
            // m.group(组索引):从1开始
            System.out.println(m.group(1) + "\t" + m.group(2));
        }
    }

Object

Object是所有类的父类,又叫顶级父类,也叫万类之源

如果一个类没有指定父类,也默认继承了Object

除了Object之外,剩下的所有类都有父类

Object中有一些方法,有的时候我们需要重写:

如:toString():默认是返回类全名@哈希值

​ 一般用作返回类中信息(成员变量的值),所以需要重写

对于print和println,如果传入类类型变量,就是调用toString方法

equals(),equals方法是Object中的方法,默认是判断地址相等(==)

但是官方建议你重写equals(),用于比较值相等

(比如String,在String类中定义的equals能够比较值相等,是因为String中重写了equals)

public class Emp {

    private String name;
    private double salary;

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    // 一般用作返回类中信息(成员变量的值),所以需要重写

    @Override
    public String toString() {
        return "Emp [name=" + name + ", salary=" + salary + "]";
    }

}
    public static void main(String[] args) {
        Emp emp = new Emp();
        emp.setName("tom");
        emp.setSalary(18000);
        // 对于print和println,如果传入的类类型变量,就是调用了toString方法
        System.out.println(emp);

        Emp emp2 = new Emp();
        emp2.setName("tom");
        emp2.setSalary(18000);
        System.out.println(emp.equals(emp2));// false

    }

Math

Math.max():最大值

Math.min():最小值

Math.round():四舍五入

Math.ceil():向上取整

Math.floor():向下取整

Math.pow():求幂

Math.sqrt():开平方

Math.cbrt():开立方

Math.abs():绝对值

Math.PI:Π

Random

随机数

​ 1.Math.random() 生成0~1之间的随机小数

​ 生成随机数[min,max) =》 int(Math.random()*(max-min))+min

​ 2.Random类

​ Random rand = new Random();

​ rand.nextInt(上限):[0,上限) 随机整数

​ 生成随机数[min,max) =》rand.nextInt(max-min)+min;

Date

date:日期类

Date date = new Date();调用了System.currentTimeMillis() 系统毫秒数

getTime():获取系统毫秒数

setTime():设置系统毫秒数

compareTo:日期比较,返回值:正数第一个日期大,负数第二个日期大,0相同

after:判断日期是否是另一个日期之后

before:判断日期是否是另一个日期之前

SimpleDateFormat,简单日期格式,用来做日期的格式化

格式化字符

y:年(yyyy,四位及以上;yy:两位年)

M:月(MM:两位月)

d:日(dd,两位日期)

h:12进制小时(hh,两位小时)

H:24进制小时(HH,两位小时)

m:分钟

s:秒

S:毫秒

E:星期

a:上午/下午

如果想直接显示字母,需要加上单引号

    public static void main(String[] args) throws ParseException {
        Date date = new Date();
        // 如果想直接显示字母,需要加上单引号
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy年MM月dd日 'at' HH:mm:ss");
        // Date对象转格式化字符串
        String str = fmt.format(date);
        System.out.println(str);
        // 格式化字符串转Date对象 字符串与日期模板不一致时,日期转换异常:ParseException
        // Date date2 = fmt.parse(str);
        Date date2 = fmt.parse(str,new ParsePosition(0))
        System.out.println(date2);
    }

Calendar

获取年份:cal.get(Calendar.YEAR)

获取月份:cal.get(Calendar.MONTH)+1,月份从0开始,所以真实月份需要加1

获取日期:cal.get(Calendar.DATE) 或者 cal.get(Calendar.DAY_OF_MONTH)

获取小时(12进制):cal.get(Calendar.HOUR)

获取小时(24进制):cal.get(Calendar.HOUR_OF_DAY)

获取分钟:cal.get(Calendar.MINUTE)

获取秒:cal.get(Calendar.SECOND)

获取星期,星期从1开始,星期日是1:cal.get(Calendar.DAY_OF_WEEK)-1

添加字段的值:cal.add(字段的常量,值)

滚动字段的值:cal.roll(字段的常量, 值)

add 和 roll的区别:

add:如果超出文本字段的范围,会影响到上一个字段

roll:如果超出文本字段的范围,不会影响上一个字段,会在本字段中循环滚动

当前日期是当前年份的第几天:cal.get(Calendar.DAY_OF_YEAR)

    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        // 设置字段:cal.set(字段常量,值)
        cal.set(Calendar.YEAR, 2023);
        cal.set(Calendar.MONTH, 2 - 1);
        cal.set(Calendar.MONDAY, Calendar.OCTOBER);
        // 设置年月日
        cal.set(2022, 2 - 1, 28);

        // 获取Date对象
        Date date = cal.getTime();
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(fmt.format(date));

        Calendar cal2 = Calendar.getInstance();
        // 将Date对象传到Calendar中
        cal2.setTime(date);
        System.out.println(cal2.get(Calendar.YEAR));

        // 获取系统毫秒数
        System.out.println(cal2.getTimeInMillis());
        // 设置系统毫秒数
        cal2.setTimeInMillis(1646976305614L);
    }

泛型

参数化的类型

泛型:泛型方法,泛型类

泛型不支持基本类型,不能实例化对象

Java中的泛型,是Java5增加的特性

擦除法泛型,Java的泛型是语法层面的,编译之后,泛型类型是Object

在Java7之前:类名<泛型类型> 变量 = new 类名<泛型类型>();

在Java7之后:类名<泛型类型> 变量 = new 类名<>();

集合

List是Collection的子接口,主要存储有序可重复数据

ArrayList:数组列表,使用数组实现

List list = new ArrayList<>();

追加元素:list.add(元素);

插入元素:list.add(索引,元素);

修改元素:list.set(索引, 元素);

删除元素(依据索引删除):list.remove(索引);

删除元素(依据元素删除):list.remove(元素);

​ 注意:如果泛型类型是Integer,使用remove时,传入元素,会当成索引,所以需要将元素强制类型转换成Integer或Object

依据索引获取元素:list.get(索引)

集合长度:list.size();

清空集合:list.clear();

    public static void main(String[] args) {
        // List是Collection的子接口,主要存储有序可重复数据
        List<String> list = new ArrayList<>();
        // 添加元素
        list.add("任均宇");
        list.add("何书龙");
        System.out.println(list);
        // 插入元素
        list.add(1, "王博斓");
        System.out.println(list);
        // 修改元素
        list.set(1, "任均宇");
        System.out.println(list);
        // 删除元素(依据索引删除)
        list.remove(2);
        System.out.println(list);
        // 删除元素(依据元素删除)
        list.remove("任均宇");
        System.out.println(list);
        // 获取元素
        System.out.println(list.get(0));
        // 集合长度
        System.out.println(list.size());
    }

遍历集合三种方式:

List<Integer> list = new ArrayList<>();
list.add(1433);
list.add(1521);
list.add(3306);
// 遍历集合,普通for循环
for(int i=0;i<list.size();i++){
    System.out.println(list.get(i));
}
System.out.println("=============");
// 遍历集合,增强for循环
for(Integer num : list){
    System.out.println(num);
}
System.out.println("=============");
// 遍历集合,使用迭代器
// 获取迭代器
Iterator<Integer> it = list.iterator();
// 判断有没有下一条数据
while(it.hasNext()){
    // 移动到下一条数据,并获取数据
    System.out.println(it.next());
}

Collections:集合工具类

Collections.addAll(集合, 元素,...):向集合中添加若干元素

Collection和Collections的区别

​ 1.Collection是集合的总接口,是存储单一类型的集合

​ 2.Collections是集合工具类,提供操作集合的相关方法

判断是否有某串:list.contains()

依据元素查找索引(从左往右找第一个):list.indexOf()

依据元素查找索引(从左往右找最后一个):list.lastIndexOf()

判断集合是否为空:list.isEmpty()

获取子集合(含头不含尾):list.subList()

​ 实际上是从集合中获取一部分,但是还是同一个集合,一个修改,会影响另一个

​ 如果想互不影响,需要将list.subList()放到集合实现类如ArrayList的构造器中

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        /*
         * Collections:集合工具类
         * Collections.addAll(集合, 元素,...):向集合中添加若干元素
         */
        Collections.addAll(list, 1521, 1433, 3306);
        Collections.addAll(list, 8080,1433);
        System.out.println(list);
        // 判断是否有某子串
        System.out.println(list.contains(1433));
        // 依据元素查找索引(从左往右找第一个)
        System.out.println(list.indexOf(1433));
        // 依据元素查找索引(从左往右找最后一个)
        System.out.println(list.lastIndexOf(1433));
        // 判断集合是否为空
        System.out.println(list.isEmpty());
        System.out.println(list.size() == 0);

        /*
         *  获取子集合(含头不含尾)
         *  实际上是从集合中获取一部分,但是还是同一个集合,一个修改,会影响另一个
         *  如果想互不影响,需要将list.subList()放到集合实现类的构造器中
         */
        List<Integer> sub = new ArrayList<>(list.subList(1, 3));
        sub.set(0, 9090);
        System.out.println(list);
        System.out.println(sub);
    }

数组转List:

Arrays.asList():转成了只读集合

正确做法:将Arrays.asList()放在List实现类的构造器中

List<泛型类型> 变量 = new ArrayList<>(Arrays.asList(数组));

    Integer[] nums = { 1, 2, 3 };
    List<Integer> list = new ArrayList<>(Arrays.asList(nums));
    list.add(0, 10);
    System.out.println(list);

List转数组:

方式一:类型[] 数组 = list.toArray(new 类型[0]);

方式二:类型[] 数组 = new 类型[集合长度];

​ 集合.toArray(arr);

        // 方式一
        Integer[] arr = list.toArray(new Integer[0]);
        // 方式二
//      Integer[] arr = new Integer[list.size()];
//      list.toArray(arr);
        System.out.println(Arrays.toString(arr));

排序

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, 3306, 1433, 1521);
        // 正序排序
        Collections.sort(list);
        System.out.println(list);
        /*
         *  正序排序:第一个数减第二个数
         *  倒叙排序:第二个数减第一个数
         */
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // TODO Auto-generated method stub
                return o2 - o1;
            }

        });
        System.out.println(list);

        list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // TODO Auto-generated method stub
                return o1 - o2;
            }

        });
        System.out.println(list);

        List<String> strList = new ArrayList<>();
        Collections.addAll(strList, "a", "b", "c", "z", "e");
        Collections.sort(strList);// 正序
        System.out.println(strList);
        // 倒序
        strList.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // TODO Auto-generated method stub
                return o2.compareTo(o1);
            }
        });
        System.out.println(strList);
    }

LinkedList:链表集合

是用链表实现的

ArrayList和LinkedList的区别:

​ 1.ArrayList是用数组实现的,在内存中连续的,适合遍历和追加

​ 2.LinkedLIst是用链表实现的,在内存中不是连续的,适合插入和删除

​ LinkedList能够实现队列和栈

队列:先进先出(FIFO)

栈:先进后出(FILO)

Queue<类型> queue = new LinkedList<>();

添加元素:queue.offer();

获取元素(不删除):queue.peek();

获取元素并删除:queue.poll();

Deque<类型> statck = new LinkedList<>();

进栈:stack.push();

出栈:stack.pop();

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        // 添加方法
        queue.offer(10);
        queue.offer(20);
        queue.offer(30);
        System.out.println(queue);
        // 获取元素(不删除)
//      System.out.println(queue.peek());
//      System.out.println(queue.peek());
//      // 获取元素并删除
//      System.out.println(queue.poll());
//      System.out.println(queue.poll());
//      System.out.println(queue.poll());

        for (Integer num : queue) {
            System.out.println(num);
        }

        System.out.println("================");

        Deque<Integer> stack = new LinkedList<>();
        // 进栈
        stack.push(10);
        stack.push(20);
        stack.push(30);
        System.out.println(stack);
        // 出栈
//      System.out.println(stack.pop());
//      System.out.println(stack.pop());
//      System.out.println(stack.pop());

        for(Integer n : stack) {
            System.out.println(n);
        }
        System.out.println(stack.size());
        while(stack.size()>0) {
            System.out.println(stack.pop());
        }

Set集合是Collection的子接口,无序存储,不可重复存储,可以null值

HashSet:无序的

LinkedHashSet:添加的顺序

TreeSet:排序的(默认是正序排序)

添加元素:add()

依据元素删除:remove(元素)

获取长度:size()

遍历Set集合

        // 遍历Set集合
        for (String str : phone) {
            System.out.println(str);
        }
        System.out.println("=============");
        Iterator<String> it = phone.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

Set集合转List集合,放到List集合实现类的构造器中

List集合转Set集合,放到Set集合实现类的构造器中

    public static void main(String[] args) {
        Set<String> phone = new HashSet<>();
        phone.add("13312345688");
        phone.add("13912345688");
        phone.add("13612345688");
        // Set集合转List:放到List集合实现类的构造器中
        List<String> list = new ArrayList<>(phone);
        list.add(1, "13612345688");
        System.out.println(list);

        // List集合转Set集合,放到Set集合实现类的构造器中
        Set<String> set = new HashSet<>(list);
        System.out.println(set);
    }
    public static void main(String[] args) {
        // 倒序排序:将比较器放在TreeSet的构造器中
        Set<String> phone = new TreeSet<>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // TODO Auto-generated method stub
                return o2.compareTo(o1);
            }

        });
        phone.add("13312345688");
        phone.add("13912345688");
        phone.add("13612345688");
        System.out.println(phone);
    }

Map集合以键值对的形式存在,键是不能重复的,值是可以重复的

HashMap:无序的

LinkedHashMap:添加的顺序

TreeMap:排序的(默认按照键的正序顺序)

添加:put(键, 值)

修改:put()

删除(依据键删除):remove(键)

是否包含某键:containsKey()

获取长度:size()

获取键集合:keySet()

获取值集合:values()

依据键获取值:get(键)

清空集合:clear()

    public static void main(String[] args) {
        /*
         * Map集合,是一种键值对集合
         * HashMap:无序的
         * LinkedHashMap:添加的顺序
         * TreeMap:排序的(默认按照键的正序排序)
         */
        Map<String,String> map = new HashMap<>();
        // 添加
        map.put("name", "高斯林");
        map.put("gender", "男");
        map.put("job", "架构师");
        System.out.println(map);
        // 修改
        map.put("job", "程序员");
        System.out.println(map);
        // 删除(依据键删除)
        map.remove("job");
        System.out.println(map);

        // 是否包含某键
        System.out.println(map.containsKey("name"));
        // 集合长度
        System.out.println(map.size());
        // 获取键集合
        System.out.println(map.keySet());
        // 获取值集合
        System.out.println(map.values());
        // 依据键获取值
        System.out.println(map.get("name"));
        // 清空集合
        map.clear();
        System.out.println(map.size());
    }

遍历Map集合

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("name", "高斯林");
        map.put("gender", "男");
        map.put("job", "程序员");

        // 遍历Map集合方式一,通过遍历键集合
        for (String str : map.keySet()) {
            System.out.println(str + "\t" + map.get(str));
        }
        System.out.println("=============");
        /*
         *  遍历Map集合方式二:通过遍历键值对对象 
         *  Entry:键值对对象
         *  entry.getKey():获取键
         *  entry.getValue():获取值
         */
        for (Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "\t" + entry.getValue());
        }

        System.out.println("==============");
        // 只遍历值
        for(String s : map.values()) {
            System.out.println(s);
        }
    }
    public static void main(String[] args) {
        // Map<String,String> map = new LinkedHashMap<>();
        // 倒序:将比较器放在TreeMap的构造器中
        Map<String, String> map = new TreeMap<>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        map.put("name", "高斯林");
        map.put("gender", "男");
        map.put("job", "架构师");
        System.out.println(map);
    }

Properties:属性集合,键值对都是字符串,可以保存到文件中

添加值:setProperty(键,值);

获取值:getProperty(键);

获取值:getProperty(键,默认值); 如果没有键,就返回默认值

HashMap和Hashtable的区别:

1.HashMap是线程不安全的,速度稍快,推荐使用,键值可以存放null

2.Hashtable是线程安全的,速度稍慢,不推荐使用,键值不能存放null

异常

语法:try-catch,try-catch-finally,try-finally

【try-catch】

try {

​ // 可能会出现异常的代码

} catch(异常对象) {

​ // 处理异常,捕捉到异常之后会执行的代码

}

【try-catch-finally】

try {

​ // 可能会出现异常的代码

} catch(异常对象) {

​ // 处理异常,捕捉到异常之后会执行的代码

} finally{

​ // 无论是否有异常,都会执行(注意:System.exit(0)退出程序除外)

}

【try-finally】

try {

​ // 可能会出现异常的代码

} finally{

​ // 无论是否有异常,都会执行(注意:System.exit(0)退出程序除外)

}

Throwable(Java语言中所有错误的父类) -- Exception(异常)
-- 运行时异常(非检查异常),RuntimeException
-- ArithmeticException(算术异常) -- NumberFormatException(数字格式异常) -- NullPointerException(空指针异常) -- StringIndexOutOfBoundsException(字符串索引越界异常) -- ArrayIndexOutOfBoundsException(数组索引越界异常) -- IndexOutOfBoundsException(索引越界异常) -- ClassCastException(类型转换异常)
-- 非运行时异常(编译异常,检查异常),Exception
-- Error(错误)

Exception:程序中出现的异常

Error:一般指虚拟机出现的错误

运行时异常:编写程序和编译程序时不会出现异常,但是运行的时候有可能出现异常

非运行时异常:在编写程序或编译程序时就出现了异常,需要异常处理

catch:可以有多个,但是范围必须由小到大

public class Test {

    public static void main(String[] args) {
        /*
         * try-catch     try-catch-finally    try-finally
         *  【try-catch 】
         *  try{
         *      // 可能会出现异常的代码
         *  }catch(异常对象){
         *      // 处理异常,捕捉到异常之后会执行的代码
         *  }
         * 
         *  catch可以有多个,但是范围必须是由小到大
         *  
         *  常见的运行时异常:
         *  ArithmeticException:算术异常
         *  NumberFormatException:数字格式异常
         *  NullPointerException:空指针异常
         *  StringIndexOutOfBoundsException:字符串索引越界异常
         *  ArrayIndexOutOfBoundsException:数组索引越界异常
         *  IndexOutOfBoundsException:索引越界异常
         *  ClassCastException:类型转换异常
         */
        try {

//          int a = 0 / 0;

//          Integer.parseInt("abc");

//          String str = null;
//          str.length();

//          String str = "";
//          str.charAt(0);

//          int[] nums = new int[0];
//          nums[0] = 10;

//          List<Integer> list = new ArrayList<>();
//          list.set(0, 10);

//          Object obj = "abc";
//          Integer num = (Integer)obj;

            Object[] num = {1,2,3};
            Integer[] aa = (Integer[])num;

        } catch (NumberFormatException e) {
            System.out.println("异常类型:" + e.getClass());
            System.out.println("异常信息:" + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
        } catch (Exception e) {
            System.out.println("异常类型:" + e.getClass());
            System.out.println("异常信息:" + e.getMessage());
        }
        System.out.println("good");
    }

}

抛异常:

1.在方法定义时,指定能够抛出哪些异常的类型

2.throw new 异常对象();

自定义异常:可以继承RuntimeException,调用一个父类的有参构造方法

public class Test02 {

    public static void getDate(String s) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = fmt.parse(s);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("出现了日期转换异常");
        }
        System.out.println(date);

    }
    /*
     *  重写中:
     *  子类称谢方法的异常对象要小于等于父类的异常对象
     *  父类的方法没有异常,子类重写的方法也不能有异常出现
     */
    public static void getDate2(String s) throws ParseException {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        Date date = fmt.parse(s);
        System.out.println(date);
    }

    /*
     *  抛异常:
     *  1.在方法定义时,指定能够抛出哪些类型的异常
     *  2.抛出异常:throw new 异常对象()
     */
    public static void setAge(int age) throws AgeException {
        if (age < 0) {
            throw new AgeException("年龄错误");
        }
        System.out.println("年龄:" + age);
    }

    public static void main(String[] args) {

        getDate("2000-03");
        try {
            getDate2("2022-03");
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("出现了日期转换异常");
        }
        System.out.println("=========================");
        try {
            setAge(-10);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            System.out.println("年龄异常");
        }
        System.out.println("ok");

        setAge(10);

    }

}
public class AgeException extends RuntimeException {

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

}

try:将有可能出现异常的代码放在try里

catch:通过大于等于本身异常进行捕获

finally:无论是否有异常,都会执行的代码(System.exit(0)退出程序除外)

try可以分别和catch,finally连用,也可以三个一起使用

try,catch里有return,finally也会执行,且在return之前执行

public class Test04 {

    public static int show() {
        int a = 1;
        try {
            return a++;
        }catch(Exception e) {
            return a++;
        }finally {
            return a++;
        }
    }

    public static void main(String[] args) {
        System.out.println(show());// 2
    }

}

final,finally,finalize的区别:

final修饰类不可被继承,修饰方法不可被重写,修饰变量值不能改变

finally在异常处理中,一定能执行的部分(除了System.exit(0))

finalize是Object中的方法,在销毁对象之前调用,不建议重写

File

File在io包中

IO:Input,Output,输入输出

文件路径:推荐使用相对路径,不要使用绝对路径(完整的路径,如d:\a.txt)

​ 使用绝对路径不能跨平台

相对路径,是从项目路径开始

File file = new File("files/a.txt");

判断文件是否存在:file.exists()

创建文件:file.createNewFile()

文件长度:file.length()

文件路径(相对路径):file.getPath()

路径分隔符:/(Unix、Linux的分隔符,Windows也识别)

不要使用 \ (只有DOS和Windows识别)

获取当前系统的分隔符:File.separator

文件路径(绝对路径):file.getAbsolutePath()

设置最后修改时间:file.setLastModified()

获取最后修改设置:file.lastModified()

只获取文件名(不包含路径):file.getName()

获取父级名称:file.getParent()

设置只读:file.setReadOnly()

设置是否可写:file.setWritable(false) false不可写,true可写

获取是否是可写:file.canWrite()

是否是隐藏文件:file.isHidden()

判断是否是文件:file.isFile()

判断是否是文件夹(目录):file.isDirectory()

创建文件夹:file.mkdirs()

删除文件夹:file.delete()

获取到文件夹下面的所有的文件:file.listFiles() File[]

        File[] files = file.listFiles();
        for(File f : files) {
            if(f.isFile()) {
                System.out.print("文件:");
            }else {
                System.out.print("目录:");
            }
            System.out.println(f.getName());
        }

IO流

IO流 -- 字节流(适合操作二进制数据)
-- InputStream(输入流)
-- FileInputStream(文件输入流)
-- BufferedInputStream(缓冲输入流)
-- DataInputStream(数据输入流)
-- ObjectInputStream(对象输入流)
-- ... ...
-- OutputStream(输出流)
-- FiltOutputStream(文件输出流)
-- FilterOutputStream(过滤输出流)
-- BufferedOutputStream(缓冲输入流)
-- DataOutputStream(数据输出流)
-- PrintStream(打印流) -- ObjectOutputStream(对象输出流) -- ... ...
-- 字符流(适合操作文本数据)
-- Reader(读取流)
-- InputStreamReader(输入流读取器)
-- FileReader(文件读取器)
-- BufferedReader(缓冲读取器)
-- ... ...
-- Writer(写入流)
-- OutputStreamWriter(输出流写入器)
-- FileWriter(文件写入器)
-- BufferedWriter(缓冲写入器)
-- PrintWriter(打印写入器)
-- ... ...

小Q截图-20220321142750

FileOutputStream:文件输出流,向文件中写入数据

FileOutputStream fos = new FileOutputStream("f1.txt", true);

FileOutputStream构造器参数:参数1:文件名,参数2:是否追加(默认不追加,true追加)

fos.write():向文件中写入数据

字符串.getBytes(编码):将字符串转换成指定编码格式的字节数组

        FileOutputStream fos = new FileOutputStream("f1.txt", true);
        // write():向文件中写入数据
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write('\n');
        byte[] bs = { 65, 66, 67, 68, 69 };
//      fos.write(bs);
        fos.write(bs, 1, 3);
        fos.write('\n');

        // 字符串.getBytes(编码):将字符串转换成指定编码格式的字节数组
        fos.write("Hello World".getBytes("UTF-8"));
        fos.write("Hello Java".getBytes("UTF-8"));
        fos.close();

FileInputStream:文件输入流,从文件中读取数据

FileInputStream fis = new FileInputStream("f1.txt");

fis.read(byte数组):将数据读取到byte数组中

将byte数组转字符串:new String(byte数组,开始位置,长度,编码格式);

        FileInputStream fis = new FileInputStream("f1.txt");
        byte[] bs = new byte[10240];// 每次最多能够读取的长度
        int len;// 真实的长度
        String str = "";
        while ((len = fis.read(bs)) > 0) {
            // 将byte数组转字符串:new String(bs,开始位置,长度,编码格式)
            str += new String(bs, 0, len, "UTF-8");
        }
        fis.close();
        System.out.println(str);

拷贝:

package com.zretc.javase.d0321;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class CopyTest {

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入源文件");
        String str = sc.next();
        System.out.println("请输入目标文件");
        String str2 = sc.next();
        FileInputStream fis = new FileInputStream(str);
        FileOutputStream fos = new FileOutputStream(str2);
        byte[] bs = new byte[10240];
        int len;
        while((len=fis.read(bs)) != -1) {
            fos.write(bs);
        }
        fis.close();
        fos.close();
        System.out.println("拷贝成功!!");

        File file = new File(str);
        File file2 = new File(str2);
        file2.setLastModified(file.lastModified());
    }

}

BufferedOutputStream,BufferedInputStream:缓冲流

低级流,节点流:直接操作硬件设备的流,比如FileOutputStream

高级流,处理流:不直接操作硬件设备,需要传入一个流来进行操作,如BufferedOutputStream

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("f2.txt"));
bos.write("Hello World".getBytes("UTF-8"));
bos.write("Hello World".getBytes("UTF-8"));
bos.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("f2.txt"));
byte[] bs = new byte[10240];
int len;
String str = "";
while ((len = bis.read(bs)) > 0) {
    str += new String(bs, 0, len, "UTF-8");
}
bis.close();
System.out.println(str);

DataOutputStream,DataInputStream:数据流,高级流

public static void main(String[] args) throws IOException {
// DataOutputStream,DataInputStream:数据流,高级流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("f3.txt"));
dos.writeInt(100);
dos.writeUTF("hello");
dos.writeDouble(3.14);
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("f3.txt"));
System.out.println(dis.readInt());
System.out.println(dis.readUTF());
System.out.println(dis.readDouble());
dis.close();
}

ObjectOutputStream,ObjectInputStream:对象流,高级流

ObjectOutputStream:将对象转成byte数组

ObjectInputStream:将byte数组转对象

序列化:将对象转成byte数组、字符串等

反序列化:将byte数组、字符串等转成对象

import java.io.Serializable;
// 若想进行二进制序列化,实现Serializable(可序列化接口)
public class Emp implements Serializable{

    private String name;
    private double salary;

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Emp [name=" + name + ", salary=" + salary + "]";
    }

}
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("emp.txt"));
        Emp emp = new Emp();
        emp.setName("tom");
        emp.setSalary(18000);
        // 对象写入到流中(序列化的过程)
        oos.writeObject(emp);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("emp.txt"));
        // 数据写入到对象(反序列的过程)
        Emp emp2 = (Emp) ois.readObject();
        ois.close();
        System.out.println(emp);
    }

PrintStream :打印流

    public static void main(String[] args) throws FileNotFoundException {
        // PrintStream  打印流
        // System.out.println("Hello");
        PrintStream ps = new PrintStream("p.txt");
        ps.print("hello");
        ps.close();

        // 输出在控制台
//      PrintStream ps = new PrintStream(System.out);
//      ps.print("Hello");
//      ps.close();
    }

字符流

FileWriter,FileReader,文件读写,低级流(节点流)

    public static void main(String[] args) throws IOException {
        // FileWriter,FileReader
        FileWriter fw = new FileWriter("w1.txt");
        fw.write(97);
        fw.write(98);
        fw.write(99);
        char[] cs = { '你', '好', '你', '是', '小', '丑', '!' };
        fw.write(cs);
        fw.write(cs, 0, 2);
        fw.write("helloworld", 2, 3);
        fw.write("高斯林\n");
        fw.write("埃里森");
        fw.close();

        FileReader reader = new FileReader("w1.txt");
        char[] c = new char[10240];
        int len;
        String str = "";
        while ((len = reader.read(c)) != -1) {
            str += new String(c, 0, len);
        }
        reader.close();
        System.out.println(str);
    }

BufferedWriter, BufferedReader 缓冲读写流,高级流

    public static void main(String[] args) throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter("w2.txt"));
        writer.write("高斯林");
        writer.close();

        BufferedReader reader = new BufferedReader(new FileReader("w2.txt"));
        char[] cs = new char[10240];
        int len;
        String str = "";
        while ((len = reader.read(cs)) > 0) {
            str = new String(cs, 0, len);
        }
        reader.close();
        System.out.println(str);
    }
    public static void main(String[] args) throws IOException {
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("w3.txt"),"UTF-8");
        writer.write("高斯林");
        writer.close();

        InputStreamReader reader = new InputStreamReader(new FileInputStream("w3.txt"),"UTF-8");
        char[] cs = new char[10240];
        int len;
        String str = "";
        while ((len = reader.read(cs)) > 0) {
            str = new String(cs, 0, len);
        }
        reader.close();
        System.out.println(str);
    }

PrintWriter 打印写入器

    public static void main(String[] args) throws FileNotFoundException {
        // PrintWriter 打印写入器
        PrintWriter out = new PrintWriter("p2.txt");
        out.println(100);
        out.println("Hello World");
        out.close();

//      Scanner sc = new Scanner(new File("p2.txt"));
//      System.out.println(sc.nextInt());
//      sc.nextLine();
//      System.out.println(sc.nextLine());

        Scanner sc = new Scanner(new File("p2.txt"));
        System.out.println(Integer.parseInt(sc.nextLine()));
        System.out.println(sc.nextLine());
    }

多线程

并发:指两个或多个事件在同一个时间段内发生

并行:指两个或多个事件在同一时刻(同时发生)

1648012176388

进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用
程序可以同时运行多 个进程;进程也是程序的一次执行过程,是系统运行程序的基本单
位;系统运行一个程序即是一个进程从创 建、运行到消亡的过程。

1648012266965

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

1648012534116

线程调度:

1.分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU事件

2.抢占式调用:优先让优先级高的线程使用CPU,如果线程优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度

主线程:执行主(main)方法的线程

单线程程序:java程序中只有一个线程

1648012862338

实现线程两种方式

方式一:

1.继承Thread类

2.重写run方法,设置线程的任务

3.创建Thread类的子类对象

4.调用Thread类中的start方法,开启新的线程,执行run方法

package com.zretc.javase.d0323.p2;
/*
 * Thread java.lang.Thread类:是描述线程的类,
 *  我们想要实现多线程程序,就需要继承Thread类
 */
// 1.创建一个Thread类的子类
public class MyThread extends Thread {
    // 2.在Thread类的子类中重写Thread类中的run方法,设置线程认为(开启线程要做什么)
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run:" + i);
        }
    }
}
package com.zretc.javase.d0323.p2;

/*
 * 1.创建一个Thread类的子类
 * 2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程想要做什么?)
 * 3.创建Thread类的子类对象
 * 4.调用Thread类中的方法start方法,开启新线程,执行run方法
 *   void start():使该线程开始执行;Java虚拟机调用该线程的run方法
 *  多次启动一个线程是非法的。
 * 
 * Java程序属于抢占式调度,哪个线程的优先级高,哪个线程优先执行,同一个优先级,随机选择一个执行
 *  
 */
public class Thread01 {

    public static void main(String[] args) {
        // 3.创建Thread类的子类对象
        MyThread mt = new MyThread();
        mt.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main:" + i);
        }
    }

}

方式二:

1.实现Runnable接口

2.重写run方法

3.创建一个Runnable接口的实现类对象

4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象

5.调用Thread类中的start()方法,开启新的线程

// 1.创建一个Runnable接口的实现类
public class RunnableImpl implements Runnable {
    // 2.在实现类中重写Runnable接口的run方法,设置线程任务
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);
        }
    }
}
public class RunnableImplTest {

    public static void main(String[] args) {
        // 3.创建一个Runnable接口的实现类对象
        RunnableImpl run = new RunnableImpl();

        // 4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
        // Thread t = new Thread(run);
        // 5.调用Thread类中的start()方法,开启新的线程
        // t.start();
        // 步骤4和5合并
        new Thread(run).start();

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);
        }
    }

}

第一种方式,使用简单,但是影响子类继承其他类

第二种方式,不影响继承,还可以共享实现类资源

匿名内部类方式实现多线程的创建,简化代码

public class InnerClassThread {

    public static void main(String[] args) {
        // 线程的父类是Thread
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " hello tom");
                }
            }
        }.start();

        // 线程的接口是Runnable
        Runnable run = new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " hello amy");
                }
            }
        };
        new Thread(run).start();

        // 简化接口的方法
        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " hello john");
                }
            }
        }).start();
    }

}

获取线程名称:

1.使用Thread类中的方法getName(),返回线程的名称

public class MyThread_getName extends Thread{
    @Override
    public void run() {
        // ①
        String name = getName();
        System.out.println(name);
    }
}
    public static void main(String[] args) {
        /*
         * 线程的名称:Thread-0,Thread-1,Thread-2
         */
        MyThread_getName mt = new MyThread_getName();
        mt.start();

        new MyThread_getName().start();
        new MyThread_getName().start();

    }

2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称

Thread.currentThread()返回正在执行的线程对象

public class MyThread_getName extends Thread{

    @Override
    public void run() {

        // ②
//      Thread t = Thread.currentThread();
//      System.out.println(t);
//      String name = t.getName();
//      System.out.println(name);
        // ③:将②合并
        System.out.println(Thread.currentThread().getName());
    }

}
    public static void main(String[] args) {
        /*
         * 线程的名称:Thread-0,Thread-1,Thread-2
         */
        MyThread_getName mt = new MyThread_getName();
        mt.start();

        new MyThread_getName().start();
        new MyThread_getName().start();
        // 获取主线程名称
        System.out.println(Thread.currentThread().getName());
    }

设置线程名称:

1.setName();

public class MyThread_setName extends Thread {

    @Override
    public void run() {
        // 获取线程名称并输出
        System.out.println(Thread.currentThread().getName());
    }

}
    public static void main(String[] args) {

        MyThread_setName mt = new MyThread_setName();
        // ①设置线程名称
        mt.setName("小强");
        mt.start();

    }

2.有参构造方法

public class MyThread_setName extends Thread {

    public MyThread_setName() {
    }

    public MyThread_setName(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

}
    public static void main(String[] args) {
        MyThread_setName mt = new MyThread_setName("旺财");
        mt.start();
    }

sleep:让程序睡眠

public class MyThread_sleep {
    /*
     *  public static void sleep(long millis);
     *  使当前正在执行的程序以指定的毫秒数暂停(暂时停止执行)
     *  毫秒数结束后,线程继续执行
     */
    public static void main(String[] args) {
        // 模拟秒表
        for (int i = 1; i <= 60; i++) {
            System.out.println(i);
            try {
                // Thread类的sleep方法让程序睡眠1秒钟
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

线程安全问题

1648090795239

解决线程安全问题

1.使用同步代码块解决

格式synchronized(锁对象){

​ 可能会出现线程安全问题的代码(访问了共享数据的代码)

}

package com.zretc.javase.d0324;

/*
 * 卖票案例出现了线程安全问题,卖出了不存在的票和重复的票
 * 
 * 解决线程安全问题的第一种方案:使用同步代码块
 * 格式:
 * synchronized(锁对象){
 *  可能会出现线程安全问题的代码(访问了共享数据的代码)
 * }
 * 注意:1.通过代码块中的锁对象,可以使用任意的对象
 *   2.但是必须保证多个线程使用的锁对象是同一个
 *   3.锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行
 * 
 */
public class TicketThread implements Runnable {

    private int ticket = 100;

    // 创建一个锁对象
    Object obj = new Object();

    // 设置线程任务:卖票
    @Override
    public void run() {
        // 使用死循环,让卖票操作重复执行
        while (true) {
            synchronized (obj) {
                // 先判断票是否存在
                if (ticket > 0) {
                    // 票存在,卖票,ticket--
                    System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");
                    ticket--;
                }
            }
        }
    }

}
package com.zretc.javase.d0324;

public class TicketThreadTest {

    public static void main(String[] args) {
        TicketThread t = new TicketThread();
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t0.start();
        t1.start();
        t2.start();
    }

}

2.使用同步方法解决

格式:

访问修饰符 synchronized 返回值类型 方法名(参数列表){

​ 可能会出现线程安全问题的代码(访问了共享数据的代码)

}

package com.zretc.javase.d0325;
/*
 * 解决线程安全的第二种方案:使用同步方法
 * 使用步骤:1.把访问了共享数据的代码抽取出来,放到一个方法中
 *      2.在方法上添加synchronized修饰符
 * 
 * 格式:
 *  访问修饰符  synchronized 返回值类型 方法名(参数列表){
 *      可能会出现线程安全问题的代码(访问了共享数据的代码)
 * }
 */
public class TicketThread implements Runnable {

    private int ticket = 100;

    // 设置线程任务:卖票
    @Override
    public void run() {
        // 使用死循环,让卖票操作重复执行
        while (true) {
            payTicket();
        }
    }
    /*
     * 定义一个同步方法,同步方法也会把方法内部的代码锁住,只让一个线程执行
     * 同步方法的锁对象是谁?就是实现类对象  也就是this
     */
    public synchronized void payTicket() {
        // 先判断票是否存在
        if (ticket > 0) {
            // 票存在,卖票,ticket--
            System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");
            ticket--;
        }
    }

}
package com.zretc.javase.d0325;

public class TicketThreadTest {

    public static void main(String[] args) {
        TicketThread t = new TicketThread();
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t0.start();
        t1.start();
        t2.start();
    }

}

死锁:多个线程访问共同资源,且处于互相等待状态,会导致死锁

sleep让当前线程处于休眠状态,但是不是放资源

wait让当前线程处于等待状态,释放资源,但是需要通过notify/notifyAll进行唤醒

线程的五种状态(线程生命周期)

1.新建状态:线程被建立

2.就绪状态:将新建的线程,加入到执行队列中

3.运行状态:线程被执行

4.阻塞状态:执行过程中发生了等待状态,导致线程暂停

5.消亡状态:线程结束

同步:顺序执行(ABCD接力赛)

异步:同时执行(ABCD比赛)

23种设计模式

单例模式:只有一个实例

​ 1.将构造方法私有化

​ 2.设置公共的静态方法返回当前类对象

懒汉模式:使用时才创建

饿汉模式:使用前就创建好对象

package com.zretc.javase.d0325;

public class Earth {
    // 懒汉模式,使用时才会创建
//  private static Earth earth;
//  private Earth() {
//      System.out.println("创建对象");
//  }
//  
//  public static Earth getEarth() {
//      if(earth == null) {
//          earth = new Earth();
//      }
//      return earth;
//  }
    // 饿汉模式,事先创建好对象
    private static Earth earth = new Earth();

    private Earth() {
        System.out.println("创建了对象");
    }

    public static Earth getEarth() {
        return earth;
    }

}
public class EarthTest {
    public static void main(String[] args) {
        Earth e1 = Earth.getEarth();
        Earth e2 = Earth.getEarth();

        System.out.println(e1 == e2);
    }
}

工厂模式:工厂里有n个管理类,统一由工厂来产生对象

枚举:将可以选择的数据,一一列出,只能选择给你列出的数据

public class Animal {

}
public class Cat extends Animal {

    public Cat() {
        System.out.println("Cat 对象");
    }
}
public enum AnimalType {
    CAT, DOG, PIG;
}
public class AnimalFactory {

    public static Animal getAnimal(AnimalType i) {
        Animal a = null;
        switch (i) {
        case CAT:
            a = new Cat();
            break;
        case DOG:
            a = new Dog();
            break;
        case PIG:
            a = new Pig();
            break;
        }
        return a;
    }

}
public class TestFactory {

    public static void main(String[] args) {
        AnimalFactory.getAnimal(AnimalType.PIG);
    }

}

JDK 8新特性

lamada表达式

主要针对是接口,且接口中只有一个抽象方法,替换匿名内部类的

无参数无返回值

package com.zretc.javase.d0325.p2;

public class Demo01 {
    public static void main(String[] args) {
        // ①匿名内部类
        Interface1 interface1 = new Interface1() {
            @Override
            public void method() {
                System.out.println("哈哈哈哈");
            }
        };
        interface1.method();

        // 主要针对是接口,且接口中只有一个抽象方法,替换匿名内部类的
        // ②lamada表达式方式一
        Interface1 interface2 = () -> {
            System.out.println("啦啦啦啦");
        };
        interface2.method();

        // ③由于只有一条语句,所以{}可以省略
        Interface1 interface3 = () -> System.out.println("该吃饭了");
        interface3.method();
    }

}

interface Interface1 {
    // 无参数无返回值
    public abstract void method();
}

无参数有返回值

package com.zretc.javase.d0325.p2;

public class Demo02 {

    public static void main(String[] args) {
        // ①
        Interface2 i1 = new Interface2() {
            @Override
            public int method() {
                return 100;
            }
        };
        System.out.println(i1.method());

        // ②
        Interface2 i2 = () -> {
            return 200;
        };
        System.out.println(i2.method());

        // ③
        Interface2 i3 = () -> 300;
        System.out.println(i3.method());

    }
}

interface Interface2 {
    // 无参数有返回值
    public abstract int method();
}

有参数无返回值

package com.zretc.javase.d0325.p2;

public class Demo03 {

    public static void main(String[] args) {
        // ①
        Interface3 i1 = new Interface3() {
            @Override
            public void method(int x, int y) {
                System.out.println("x=" + x + ",y=" + y);
            }
        };
        i1.method(1, 2);

        // ②
        Interface3 i2 = (int x, int y) -> {
            System.out.println("x=" + x + ",y=" + y);
        };
        i2.method(3, 4);

        // ③
        Interface3 i3 = (int x, int y) -> System.out.println("x=" + x + ",y=" + y);
        i3.method(5, 6);

        // ④
        Interface3 i4 = (x, y) -> System.out.println("x=" + x + ",y=" + y);
        i4.method(7, 8);
    }

}

interface Interface3 {
    // 有参数无返回值
    public abstract void method(int x, int y);
}

有参数有返回值

package com.zretc.javase.d0325.p2;

public class Demo04 {

    public static void main(String[] args) {
        // ①
        Interface4 i1 = new Interface4() {
            @Override
            public int method(int x, int y) {
                return x + y;
            }
        };
        System.out.println(i1.method(1, 2));

        // ②
        Interface4 i2 = (int x, int y) -> {
            return x + y;
        };
        System.out.println(i2.method(3, 4));

        // ③
        Interface4 i3 = (x, y) -> x + y;
        System.out.println(i3.method(9, 10));
    }

}

interface Interface4 {
    // 有参数有返回值
    public abstract int method(int x, int y);
}

集合遍历

package com.zretc.javase.d0325.p2;

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

public class Demo05 {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("tom");
        list.add("rose");
        list.add("jack");
        list.add("kimi");
        list.add("july");
        // 函数式接口--Consumer接口
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String t) {
                System.out.println(t);
            }
        });

        System.out.println("=======================");
        list.forEach((String t) -> System.out.println(t));

        System.out.println("=======================");
        list.forEach((t) -> System.out.println(t));

        // 就是把集合当中的每一个元素都赋值给了t,然后输出t
        System.out.println("=======================");
        list.forEach(t -> System.out.println(t));

        System.out.println("************************");
        list.forEach(System.out::println);

    }
}

可以调用静态方法

package com.zretc.javase.d0325.p2;

public class Demo06 {

    public static void main(String[] args) {
        Interface6 i1 = new Interface6() {
            @Override
            public int getInt(String s) {
                return Integer.parseInt(s);
            }
        };
        System.out.println(i1.getInt("123") + 1);

        Interface6 i2 = (s) -> Integer.parseInt(s);
        System.out.println(i2.getInt("456") + 1);
        /*
         *  这里它由于是一个参数,它把很多东西都可以省略
         *  parseInt是用类调用,说明是一个静态方法,静态方法可以直接调用
         */
        Interface6 i3 = Integer::parseInt;
        System.out.println(i3.getInt("780") + 1);
    }

}

interface Interface6 {
    int getInt(String s);
}

构造方法

package com.zretc.javase.d0325.p2;

public class Demo07 {
    public static void main(String[] args) {
        Interface7 i1 = new Interface7() {
            @Override
            public Person getPerson() {
                return new Person();
            }
        };
        i1.getPerson();
        // 构造方法
        Interface7 i2 = Person :: new;
        i2.getPerson();
    }
}
class Person {
    public Person() {
        System.out.println("创建Person对象");
    }
}
interface Interface7{
    public Person getPerson();
}
package com.zretc.javase.d0325.p2;

public class Demo08 {

    public static void main(String[] args) {
        // 有参构造方法
        Interface8 i1 = Student::new;
        i1.getStudent("tom", 18);

        Interface8 i2 = new Interface8() {
            @Override
            public Student getStudent(String name, int age) {
                return new Student(name, age);
            }
        };
        i2.getStudent("amy", 20);
    }
}
class Student {
    public Student(String name, int age) {
        System.out.println(name + "\t" + age);
    }
}
interface Interface8 {
    public Student getStudent(String name, int age);
}

时间类

LocalDate

LocalTime

LacalDateTime

package com.zretc.javase.d0325.p3;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;

public class Demo {

    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        System.out.println(cal);
        // 获取Date对象
        System.out.println(cal.getTime());
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 转成格式化字符串
        System.out.println(f.format(cal.getTime()));
        System.out.println(cal.get(Calendar.MONTH) + 1 + "月");// 0-11
        System.out.println(cal.get(Calendar.DAY_OF_WEEK) - 1);// 1-7 周日是第一天

        // jdk 8之后新增时间类
        LocalDate ld = LocalDate.now();// 获取当前系统时间
        System.out.println(ld);// 2022-03-25

        LocalDate ld2 = LocalDate.of(2023, 3, 1);// 指定时间
        System.out.println(ld2);
        // 通过控制当前赋值的正负数,完成是加还是减
        ld2 = ld2.plusYears(-3);
        System.out.println(ld2);
        // 月份
        ld2 = ld2.plusMonths(-13);
        System.out.println(ld2);
        // 日期
        ld2 = ld2.plusDays(1);
        System.out.println(ld2);
        // 周,1代表7天
        ld2 = ld2.plusWeeks(2);
        System.out.println(ld2);

        System.out.println("=========================");
        // 格式化
        DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;// 获取系统设置好的时间格式
        System.out.println(dtf);
        // 转成格式化字符串
        System.out.println(dtf.format(ld));// 2022-03-25
        // 设置时间格式
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        // 转成格式化字符串
        System.out.println(dtf2.format(ld));// 2022/03/25

        System.out.println("***************************");
        // 时分秒毫秒
        LocalTime lt = LocalTime.now();
        System.out.println(lt);
        // 格式化字符串
        DateTimeFormatter d1 = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");// HH:24进制 hh:12进制
        System.out.println(d1.format(lt));

        System.out.println("############################");
        // 年月日-十分秒毫秒
        LocalDateTime lt2 = LocalDateTime.now();
        System.out.println(lt2);
        // 格式化字符串
        DateTimeFormatter d2 = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
        String str = d2.format(lt2);
        System.out.println(str);

    }

}
山水有相逢,我们江湖再见!じゃな~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇