Java基础学习【快速回忆版】

目录

基础

面向对象

常用类


Java下载:https://www.oracle.com/java/technologies/javase-jdk14-downloads.html

C:\Users\Administrator>cd C:\Users\Administrator\Desktop\Java\Project          #进入新建的程序文件夹
C:\Users\Administrator\Desktop\Java\Project>javac HelloWorld.java             #编译
C:\Users\Administrator\Desktop\Java\Project>java HelloWorld                         #运行
Hello,World!
C:\Users\Administrator\Desktop\Java\Project>

public class [文件名,类名称] {
    public static void main(String[] args){            #程序执行起点 main
        System.out.println("Hello,World!");               #打印输出
    }
}

基础

关键字:1、小写;2、编写变色。
标识符:字母、数字、$、_。
常量:

  • 字符串常量("abc");
  • 整型常量;
  • 浮点数常量;
  • 字符常量('a'。不能为空,只能有一个字符);
  • 布尔常量(true、false);
  • 空常量(null。不能直接用来打印)。  

变量:数据类型 变量名;
基本数据类型:

  • 整数型-byte short int long;    #long后要加 L
  • 浮点型-float double;            #float后要加 F
  • 字符型-char;
  • 布尔型-boolean.

引用数据类型:字符串、数组、接口、lambda

数据类型装换:

  • 自动类型转换(隐式):数据范围从小到大
  • 强制类型装换(显式):(范围小的类型)范围大的数据

---精度损失、数据溢出
---byte、short、char在运算时,首先转化成int类型,再计算
            例如:byte num1 = 40; 
                  byte num2 = 50;
                  int result = num1 + num2;        # byte + byte ---> int + int ---> int
---boolean不能进行数据类型转换
---byte、short、char右侧赋值数值没有超过范围,编译器会补上(byte)、(short)、(char)
            例如:byte num1 = /*(byte)*/ 30;
                  char zifu = /*(char)*/ 65;
        
ASCII编码表:48 -> '0'   65 -> 'A'   97 -> 'a'
例如:

char zifu1 = 'A';
System.out.println(zifu1 + 0);
or:
int num = zifu1;
System.out.println(num);

算术运算符:四则运算符(+、-、*、/)、取模(%)、自增自减运算符(++、--)
    1、两个不同类型的数据,结果是数据类型范围大的那种
例如:

int x = 10;
double result = x + 2.5;        # int + double ---> double + double ---> double 
System.out.println(result);

   2、对于字符串String(首字母大写,不是关键字)来说,加号表示连接
例如:

String str1 = "Hello";
System.out.println(str1);        #cmd打印:Hello
System.out.println("Hello" + "World");    #cmd打印:HelloWorld
System.out.println(str + 20);        #cmd打印:Hello20
#String + int ---> String
System.out.println(str + 20 + 30);    #cmd打印:Hello2030   优先级
#(String + int) + int ---> String + int ---> String     

赋值运算符:基本赋值运算符 =、符合赋值运算符 +=、-=、*=、/=、%=
比较运算符:==、<、>、<=、>=、!=
逻辑运算符:&&、||、!
三元运算符:数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;

方法定义:(类似于C语言的函数)

public static void [方法名称](){
     方法体;
}

方法调用:方法名称();

顺序结构:
判断结构:

1、    if(关系表达式){
            语句体;
       }
2、    if(关系表达式){
            语句体1;
       }
        else{
            语句体2;
        }
3、    if(判断条件1){
            语句体1;
       }
        else if(判断条件2){
            语句体2;
        }
            .
            .
            .
        else{
            语句体n;
        }

选择结构:[表达式:byte、short、char、int、String、enum]

switch(表达式){
   case 常量值1: 
       语句体1; 
       break;
   case 常量值2: 
       语句体2; 
       break;
     .
     .
     .
   default: 
       语句体n+1; 
       break;
}

循环结构:
    基本组成部分:初始化语句、条件判断、循环体、步进语句。
for循环:

for(初始化表达式;布尔表达式;步进表达式){
    循环体;
}

while循环:

1、    while(条件判断){
          循环体;
        }
            
2、 初始化语句;
        while(条件判断){
           循环体;
           步进语句;
        }

do-while循环:

 1、do{
          循环体;
    }while(条件判断);
            
2、 初始化语句;
    do{
          循环体;
          步进语句;
     }while(条件判断);

循环控制:break、continue
循环嵌套:

面向对象

IDE:集成开发环境----Eclipse
                     IDEA:https://pan.baidu.com/s/1HZ1_uyM1HCVxmMytvnWfDQ?提取码:en46
方法:参数、返回值
 

修饰符 返回值类型 方法名称(参数类型 参数名称, ...){
     方法体;
     return 返回值;
}

方法的三种调用格式:

  • 单独调用:方法名称(参数);
  • 打印调用:System.out.println(方法名称(参数));
  • 赋值调用:数据类型 变量名称  = 方法名称(参数);

返回值类型为void不能使用打印调用和赋值调用。

方法注意事项:

  • 1、方法不能嵌套;
  • 2、方法定义前后顺序无所谓;
  • 3、方法定义后要调用;
  • 4、方法有返回值必须有return且必须和方法的类型一致;
  • 5、方法void没有返回值不写return或者[return;];
  • 6、一个方法可以有多个return但是同时只能执行一个;

方法重载:overlord
    方法名称一样,但是参数列表不一样(参数类型:个数不同,类型不同,多类型顺序不同)
    与参数的名称无关、与方法的返回值类型无关

数组:引用数据类型、多个数据的类型必须统一、长度在运行期间不可更改
数组初始化:
    1)动态初始化:(指定长度) 
    ---> 它的每一个值 整数为0 浮点数为0.0 字符类型'\u0000' 布尔类型false 引用类型null
        数据类型[] 数组名称 = new 数据类型[数组长度];
            拆分两步:
                数据类型[] 数组名称;
                数组名称 = new 数据类型[数组长度];
    2)静态初始化:(指定内容)
        数据类型[] 数组名称 = new 数据类型[]{元素1, 元素2...};
            拆分两步:
                数据类型[] 数组名称; 
                数组名称 = new 数据类型[]{元素1, 元素2...};
        数据类型[] 数组名称 = {元素1, 元素2...};
            不可拆分两步

获取数组元素:
    System.out.println(数组名称);  --->  打印的是数组对应内存地址的哈希值
    数组名称[索引值];
    数组的长度:数组名称.length

面向过程:
面向对象:        [封装、继承、多态]
    JDK提供一个Array类:

import java.util.Arrays;
System.out.println(Arrays.toString(array));

类:一组相关属性和行为的集合。 ---> 抽象的
对象:  ---> 具体的
类是对象的模板,对象是类的实体。

public class 类名称{
    成员变量;
    成员方法;   --->  定义时没有static
}

一个类不能直接使用,要创建一个对象才可以使用。
1、导包
        import 包名称.类名称;
        与类在同一个包,可以省略导包语句不写。
2、创建
        类名称 对象名 = new 类名称();
        Student stu = new Student();
3、使用
        使用成员变量:对象名.成员变量名
        使用成员方法:对象名.成员方法名(参数)

局部变量与成员变量的区别:
1、定义的位置不一样。
        局部变量:在方法内部
        成员变量:在方法外部,直接写在类当中
2、作用范围不一样。
        局部变量:只有方法当中可以使用,出了方法就不可以用了
        成员变量:整个类全部都可以通用
3、默认值不一样。
        局部变量:没有默认值,如果想要使用,必须手动进行赋值
        成员变量:如果没有赋值,会有默认值,规则与数组一样
4、内存的位置不一样。
        局部变量:位置位于栈
        成员变量:位于堆内存
5、生命周期不一样。
        局部变量:随着方法进栈而产生,随着方法出栈而消失
        成员变量:随着对象被创建而产生(new),随着对象被垃圾回收而消失
面向对象三大特性之封装性:
封装性体现:
        1、方法就是一种封装;
        2、关键字private也是一种封装。 
            --->本类可以直接访问,超出本类以外就不在直接访问        

private int age;    //private关键字,此类以外不能用
            
//这个成员方法,专门用于向age设置数据
public void setAge(int num){
    if(num > 0 && num < 100){
       age = num;
    }else{
       System.out.println("数据不合理!");
    }
}    
            
//这个成员方法,专门用于获取age的数据
public int getAge(){
    return age;
}

对于boolean类型,setXxx不变,getXxx改为isXxx。

this关键字:

  • 当方法的局部变量与类的成员变量重名时,优先使用局部变量
  • 想用本类的成员变量:this.成员变量名
  • 谁调用方法,谁就是this

构造方法:专门用来创建对象的方法,通过new创建对象时就是在调用构造方法。

public 类名称(参数类型 参数名称){
    方法体
}

注意:

  • 1、构造方法的名称必须和类名称完全一样
  • 2、构造方法不写返回值类型,连void也不写
  • 3、构造方法不能return一个返回值
  • 4、如果没有编写任何构造方法,编译器会默认赠送一个构造方法,没有参数,方法体什么也不做
  • 5、一旦编写了至少一个构造方法,编译器将不再赠送
  • 6、构造方法也是可以重载的
Student类
    private String name;
    private int age;
    public Student(){    ---> 无参构造方法
    
    }
    public Student(String name, int age){   ---> 全参构造方法
        this.name = name;
        this.age = age;
    }
    加上get(name/age)、set(name/age)
useStudent文件
    Student stu1 = new Student();
    Student stu2 = new Student("Jiao", 23);
    System.out.println("Name:" + stu2.getName() + ",Age:" + stu2.getAge());

定义一个标准的类:[Java Bean]

  • 1、所有的成员变量都要加private关键字修饰
  • 2、为每一个成员变量编写一对setter、getter方法 
  • 3、编写一个无参数的构造方法
  • 4、编写一个全参数的构造方法

API:
Scanner类:键盘输入

import java.util.Scanner;
    
//System.in表示从键盘输入
Scanner sc = new Scanner(System.in);

//获取键盘int数字, int num = sc.nextInt();
//获取键盘String字符串, String str = sc.next();

int num = sc.nextInt();
System.out.println("输入的数字是:" + num);
        
String str = sc.next();
System.out.println("输入的字符串是:" + str);

匿名对象:        传统:Student stu1 = new Student();

  • 只有右边的对象,没有左边的名字和赋值语句
  • 只能使用唯一的一次,下次再用不得不再创建一个新对象。

int num = new Scanner(System.in).nextInt();

使用匿名对象传参:

main中
    methodParam(new Scanner(System.in));
methodParam中
    public static void methodParam(Scanner sc){
        int num = sc.nextInt();
        System.out.println("输入的数字是:" + num);
    }

使用匿名对象返回值:

main中
    Scanner sc = methodReturn();
    int num = sc.nextInt();
    System.out.println("输入的数字是:" + num);
methodParam中
    public static Scanner methodReturn(){
        return new Scanner(System.in);
    }

Random类:生成随机数

import java.util.Random;
    
Random r = new Random();
        
//获取一个随机的int数字(有正负),int num = r.nextInt();
int num1 = r.nextInt();
System.out.println("随机数字是:" + num1);

//获取一个随机的int数字(参数代表范围,左闭右开),int num = r.nextInt(3);  -> [0,3)
int num2 = r.nextInt(5);
System.out.println("随机数字是:" + num2);

对象数组:    

Student[] array = new Student[3];

Student one = new Student("JiaoLiang",23);
Student two = new Student("ZhangXuan",22);
Student three = new Student("Hello",18);
        
array[0] = one;
array[1] = two;
array[2] = three;

System.out.println(array[1].getName());

集合类(ArrayList):长度可变
import java.util.ArrayList;

  • 对于ArrayList后面有一个<E> 表示泛型:装在集合当中的所有元素,全都是统一的什么类型
  • 泛型只能是引用类型,不是基本类型
  • 创建了一个ArrayList集合,集合的名称是list,里面全部装的是String字符串型的数据

ArrayList<String> list = new ArrayList<>();

ArrayList的常用方法    

  • 1、public boolean add(E e);  向集合中添加元素,参数的类型与泛型类似,返回值代表是否添加成功
  • 2、public E get(int index);  从集合中获取元素,参数是索引编号,返回值就是对应位置的元素
  • 3、public E remove(int index);  从集合中删除元素,参数是索引编号,返回值就是被删除的元素
  • 4、public int size();  获取集合的尺寸长度,返回值就是集合中包含的元素个数
//向集合当中添加一些数据,用add方法
list.add("赵丽颖");
list.add("迪丽热巴");
list.add("高圆圆");
list.add("古力娜扎");
System.out.println(list);

//从集合中获取元素,用get方法
String name = list.get(2);
System.out.println("索引值[2]是:" + name);

//从集合中删除元素,用remove方法
String whoRemove = list.remove(1);
System.out.println(whoRemove);
System.out.println(list);

//获取集合的长度(元素的个数),用size方法
int size = list.size();
System.out.println(size);

//遍历
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

如果希望集合ArrayList当中存储基本类型数据,必须使用基本类型对应的 包装类

基本类型    包装类(引用类型,包装类都位于java.long包下)
byte       Byte
short      Short
int        Integer
long       Long
float      Float
double     Double
char       Character
boolean    Boolean

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

字符串:常量,永远不可变。== char[]型字符数组,低层是byte[]字节数组
创建方式:
1、三种构造方法:

  • public String();    创建一个空白字符串,不含有任何内容。
  • public String(char[] array);    根据字符数组的内容,来创建对应的字符串。
  • public String(byte[] array);    根据字节数组的内容,来创建对应的字符串。
//空参构造
String str1 = new String();
System.out.println("str1的字符串是:" + str1);

//字符数组构造
char[] charArray = { 'A', 'B', 'C'};
String str2 = new String(charArray);
System.out.println("str2的字符串是:" + str2);

//字节数组构造
byte[] byteArray = {97 ,98, 99};
String str3 = new String(byteArray);
System.out.println("str3的字符串是:" + str3);

2、一种直接创建:
字符串的常量池:程序中直接写上双引号的字符串,就在字符串常量池中。

  • 基本型 ==比较 数值比较
  • 引用型 ==比较 地址值比较

1、public boolean equals(Object obj);    参数可以是任何对象,只有参数是一个字符串内容相同才会返回true。
        1、任何对象都可以用Object进行接收。
        2、equals方法具有对称性,也就是a.equals(b)与b.equals(a)一样。
        3、如果一个常量一个变量,推荐把常量字符串写在最前面:"abc".equals(str);
2、public boolean equalsIgnoreCase(String str);    忽略大小写,进行内容比较。
字符串的获取相关方法:

  • public int length();    获取字符串中含有字符个数,拿到字符串的长度。
  • public String concat(String str);    将当前字符串和参数字符串拼接成为返回值新的字符串。
  • public char charat(int index);        获取指定索引位置的单个字符。
  • public int indexOf(String str);        查找参数字符串在本字符串中首次出现的索引位置,若没有返回-1值。

字符串的截取方法:

  • public String substring(int index);        截取从参数位置到字符串末尾,返回新字符串。
  • public String substring(int begin, int end);    截取从begin开始到end结束,中间的字符串。[begin, end)

字符串的转换方法:

  • public char[] toCharArray();    将当前字符串拆分为字符数组作为返回值。
  • public byte[] getBytes();        获得当前字符串低层的字节数组。
  • public String[] replace(CharSequence oldString, CharSequence newString);

将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
CharSequence接口:可以接收字符串类型
字符串的分割方法:    

  • public String[] spilt(String regex);    按照参数的规则,将字符串切分成为若干部分。

regex 是 正则表达式 按照"."分割,要写成"\\."    
静态static:
1)一旦用了static关键字,那么这样的内容就不属于对象自己,而是属于类。凡是本类的对象,都共享一份。
    static String room; 
2)一旦使用static修饰成员方法,那么就成了静态方法。

//静态方法
obj.methodStatic();         //不推荐这样做--->javac后会变成“类名称.静态方法名”
MyClass.methodStatic();     //推荐

 如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。

//成员方法
MyClass obj = new MyClass();
obj.method();

无论成员变量,还是成员方法,如果有static,都推荐用类名称调用。
        静态变量:类名称.静态变量
        静态方法:类名称.静态方法()
静态不能直接访问非静态。
        原因:在内存中先有静态内容,后有非静态内容。
静态方法不能使用this关键字。
        原因:this表示当前对象,通过谁调用方法,谁就是当前对象。

静态代码块:
格式:

public class 类名称{
    static {
               静态代码块的内容;
           }
}

当第一次用到本类时,静态代码块执行位唯一一次。
静态的内容优先于非静态的内容。
静态的代码块的用图:用来一次性的对静态成员变量进行赋值。

常用的工具类:
1)Array:java.util.Arrays 与数组相关的工具类,提供大量的静态方法。

  • public static String toString(数组);    将参数数组变成字符串。
  • public static void sort(数组);            默认升序对数组元素进行排序

注意:数值---按照升序
    字符串---字母升序
    自定义类型---它需要有Comparable或Comparator接口支持

2)Math:java.lang.Math 与数学相关的工具类,提供大量的静态方法。

  • public static double abs(double num);         获取绝对值
  • public static double ceil(double num);        向上取整
  • public static double floor(double num);        向下取整
  • public static long    round(double num);        四舍五入

3)Math.PI        近似pai
继承:继承是多态的前提。
继承主要解决的就是:共性抽取。
特点:子类可以拥有父类的 “内容”;子类可以拥有父类的 “新内容”

定义父类格式:
public class 父类名称(){
     ...
}
定义子类格式:
public class 子类名称 extends 父类名称(){
     ...
}

在父子类继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
1)直接:通过子类对象访问成员变量。
            等号左边是谁,就优先用谁,没有则向上找。
2)间接:通过成员方法访问成员变量。
            该方法属于谁,就优先用谁,没有则向上找。

区分子类三种方法重名的三种变量:

  • 局部变量:            直接写成员变量名
  • 本类的成员变量:    this.成员变量名
  • 父类的成员变量:    super.成员变量名

成员方法的访问特点:
在父子类继承关系中,创建子类对象,访问成员方法的规则:
        创建的对象是谁,就优先用谁,如果没有则向上找。
 注意:无论成员方法还是成员变量,如果没有就是向上找,绝对不会向下找子类的。

方法的覆盖重写(Override)-覆盖-复写:方法名称一样,参数列表也一样。
          重载(Overload):方法名称一样,参数列表不一样。
特点:创建的是子类对象,则优先用子类方法。
注意:

1、方法名称与参数列表都相同。
            @override:写在方法前面,用来检测是不是有效的正确覆盖重写。--->没写也可以
2、子类方法的返回值必须小于等于父类方法的返回值范围。
            前提:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String类就是Object的子类。
            (方法void ---> 改为:Object与String)
3、子类方法的权限必须大于等于父类方法的权限修饰符。
            扩展:public > protected > (default) > private
                (default)不是关键字default,而是什么都不写,留空。

继承中构造方法的访问特点:

  • 1、子类构造方法当中有一个默认隐含的“super();”调用,所以一定是先调用的父类构造,后执行的子类构造。
  • 2、子类构造可以通过super关键字来调用父类重载构造。
  • 3、super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。

注意:子类必须调用父类的构造方法,不写则赠送 super(); 
          写了则用写指定的super调用,super只能有一个,还必须是第一个。
super关键字的三种用法总结:

  • 1、在子类的成员方法中,访问父类的成员变量。        super.成员变量
  • 2、在子类的成员方法中,访问父类的成员方法。        super.成员方法
  • 3、在子类的构造方法中,访问父类的构造方法。        super(); 或 super(参数);

this关键字的三种用法总结:

  • 1、在本类的成员方法中,访问本类的成员变量。
  • 2、在本类的成员方法中,访问本类的成员变量。
  • 3、在本类的构造方法中,访问本类的另一个构造方法。    本类无参构造调用本类的有参构造    

必须是构造方法的第一个语句,唯一一个。
super和this两种构造不能同时使用。

java继承的三个特点:
    1、Java语言是单继承的:一个类的直接父类只能有唯一一个。
    2、Java语言可以多级继承:
        class A{}
        class B extends A{}
        class C extends B{}
    3、一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类
        class A{}
        class B extends A{}
        class C extends A{}

抽象:如果父类当中的方法不确定如何进行{}方法体实现,那么就是一个抽象方法。
    抽象方法:加上abstract关键字,然后去掉大括号,直接分号结束。
    抽象类:抽象方法所在的类,必须是抽象类才行,在class之前加上abstract即可。

    使用步骤:
        1、不能直接创建new抽象类对象。
        2、必须用一个子类来继承抽象父类。
        3、子类必须覆盖重写抽象父类当中的所有的抽象方法。
            覆盖重写(实现):去掉抽象方法的abstract关键字,然后补上方法体大括号。
        4、创建子类对象进行使用。
注意事项:
        1、抽象类不能创建对象。
        2、抽象类可以有构造方法,供子类创建对象时,初始化父类成员使用。
        3、抽象类中,不一定包含抽象方法,但是抽象方法的类必须是抽象类。
        4、抽象的类的子类,必须重写抽象父类中所有的抽象方法,不然会报错。
            除非该子类也是抽象类。

接口:就是一种公共的规范标准。是引用数据类型,最重要的就是抽象方法。
定义格式:

public interface 接口名称{
    ...
}

class换成了interface之后,编译生成的字节码文件后还是.java -> .class    

  • java7: 1、常量 2、抽象方法 
  • java8: 3、默认方法 4、静态方法 
  • java9: 5、私有方法

接口的抽象方法:

public abstract 返回值类型 方法名称(参数列表);
public abstract void methodAbs();

注意:1、修饰符必须是两个固定的关键字,public abstract
              2、修饰符可以选择性的省略
              3、方法的三要素可以随意定义
使用:1、接口不能直接使用,必须有一个“实现体”来“实现”该接口。
            public class 实现类名称 implement 接口名称{
                ...
            }
      2、接口的实现类必须覆盖重写 接口中的所有的抽象方法。
            实现:去掉abstract关键字,加上方法体大括号。
      3、创建实现类的对象,进行使用。
        注意:如果实现类并没有覆盖重写接口中的所有的抽象方法,
              那么这个实现类自己就必须是抽象类。
接口的默认方法:
        可以解决接口的升级问题。
        public default 返回值类型 方法名称(参数列表){
            方法体
        }
        1、接口的默认方法,可以通过接口实现类对象,直接调用。
        2、接口的默认方法,可以被接口实现类进行覆盖重写。
接口的静态方法:
        public static 返回值类型 方法名称(参数列表){
            方法体
        }
        提示:就是把abstract或者default换成static即可,带上方法体。
        注意:不能通过接口实现类的对象直接调用接口的静态方法。
        正确用法:通过接口名称直接调用静态方法。

接口的私有方法:
问题:需要抽取一个共有方法,用来解决默认方法之间重复代码的问题
                但是这个共有方法不能在实现类中使用,应该是私有化的。
        1、普通私有方法:解决多个默认方法之间重复代码问题
            格式:private 返回值类型 方法名称(参数列表){
                    方法体
                  }
        2、静态私有方法:解决多个静态方法之间重复代码问题
            格式:private static 返回值类型 方法名称(参数列表){
                    方法体
                  }
接口的常量:
        接口中可以定义“成员变量”,但是必须是public static final三个关键字进行修饰。
        从效果上看,这就是接口的“常量”
        格式:
            public static final 数据类型 常量名称 = 数据值;
        注意:
            一旦是使用final关键字,说明不可修改。
            接口中的常量,必须进行赋值,不能不赋值。
            接口中常量的名称,使用完全大写的字母,用下划线分割。

接口注意事项:
    1、接口是没有静态代码块与构造方法的
    2、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
        格式:
            public class MyInterfaceImpl implement MyInterfaceA,MyInterfaceB{
                //覆盖重写所有抽象方法
            }
    3、如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
    4、如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
    5、如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的
        默认方法进行覆盖重写。
    6、一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。
类与接口:
    1、类与类之间是单继承的,直接父类只有一个。
    2、类与接口之间是多实现的。一个类可以实现多个接口。
    3、接口与接口之间是多继承的。
注意事项:
        1、多个父接口当中的抽象方法如果重复,没关系。
        2、多个父接口当中的默认方法如果重复,有那么子接口必须进行默认方法的覆盖重写,
            而且带着default关键字。

面向对象的多态(polymorphism)
    代码当中体现的多态性,其实就是一句话:父类引用指向子类对象
    格式;
        父类名称 对象名 = new 子类名称();
        接口名称 对象名 = new 实现类名称();
    多态中成员变量的使用特点:
        1、直接通过对象名称访问成员变量,看等号左边是谁,没有则向上找。
        2、间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。
    多态中成员方法的使用特点:
        看new的是谁,就优先用谁,没有则向上找。
        成员变量口诀:编译看左,运行看左。
        成员方法口诀:编译看左,运行看右。
    使用多态的好处:
        无论右边new的时候换的是哪个子类对象,等号左边的调用方法都不会改变。

    对象的向上转型:
        就是多态的写法:
            格式:父类名称 对象名 = new 子类名称();
        右侧创建一个子类对象,把它当做父类来看待使用。
        向上转型一定是安全的。类似于自动转型:double num = 10;  int --> double。

    对象的向下转型:
        调用子类特有方法。
        多态定义后,对象类特有的方法 不能在Main中直接使用
        解决方法:用对象的向下转型“还原”
            格式:子类名称 对象名 = (子类名称)父类对象;
            含义:就是将父类对象,还原为本来的子类对象。

        instanceof关键字:判断父类引用的对象,本来是什么子类。
            格式:对象 instanceof 类型
            这将会得到一个boolean值的结果,也就是判断前面的对象能不能当做后面类型的实例。
    
fina关键字:最终的、不可改变的
    常见四种用法:
        1、可以用来修饰一个类
            格式:
                public final class 类名称{
                    ...
                }
            含义:当前这个类不能有任何的子类。(太监类)
                  不能用一个final类作为父类。
            注意:一个类如果是final的,那么其中的成员方法都无法进行覆盖重写。(没儿子)
                
        2、可以用来修饰一个方法
            当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能覆盖重写。
            格式:
                public final 返回值类型 方法名称(参数列表){
                    ...
                }
            注意事项:
                对于类与方法来说,abstract与fianl不能同时使用,因为矛盾。
                
        3、还可以用来修饰一个局部变量
            一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。(一次赋值,终身不变)
            例如:final int num;
                  num = 10;            //正确写法,只要保证一次赋值即可
                对于基本类型来说,不可改变就是变量的数据不可改变
                对于引用类型来说,不可改变就是变量中的地址值不可改变
                  
        4、还可以用来修饰一个成员变量
            对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变的。
            A、对于成员变量具有默认值(0,Null),所以用了final之后必须手动赋值,不在给默认值了。
            B、对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值,二者选其一。
            C、必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

四种权限修饰符:
                    public > protected > (default) > private
    同一个类        YES            YES            YES            YES
    同一个包        YES            YES            YES            NO        new 另一个类名称.成员变量
    不同包子类        YES            YES            NO            NO
    不同包非子类    YES            NO            NO            NO

内部类:
    如果一个事物的内部包含另外一个事物,那么这就是一个类内部包含另一个类。
    分类:
        1、成员内部类 
            格式:
                修饰符 class 外部类名称{
                    修饰符 class 内部类名称{
                        ...
                    }
                    ...
                }
            注意:内用外,随意访问;外用内,需要借助内部类对象。
            使用:
                A、间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
                B、直接方式:
                    类名称 对象名 = new 类名称();
                    外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
            如果出现重名现象,那么格式是:
                外部类名称.this.外部类成员变;
                
        2、局部内部类(包含匿名内部类)
            如果一个类定义在一个方法的内部,那么这就是一个局部内部类。
            “局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
            定义格式:
                修饰符 class 外部类名称{
                    修饰符 返回值类型 外部类方法名称(参数列表){
                        class 局部内部类名称{
                            ...
                        }
                    }
                    ...
                }
            注意:局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效的final】
            
    定义一个类的权限修饰符:
        1、外部类:public / (default)
        2、成员内部类:public / protected /(default)/ private
        3、局部内部类:什么都不写

匿名内部类:(重要)
    如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
    那么这种情况下就可以省略掉该类的定义,而改为使用【匿名局部类】
    定义格式:
        接口名称 对象名 = new 接口名称{
            //覆盖重写所有的抽象方法
        };
    注意:
        1、匿名内部类,在【创建对象】的时候,只能使用一次。
            如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类。
        2、匿名对象,在【调用方法】的时候,只能调用唯一一次。
            如果希望给匿名对象,调用多次方法,那么必须给对象起名字。
        3、匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】。
            匿名内部类与匿名对象不是一回事。

类作为成员变量类型:
接口作为成员变量类型:
接口作为方法的参数或返回值:
(平均、随机)红包案例
Object类:
    java.lang.Object;
    类Object是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
    1、toString方法--------快捷键:Alt+Insert  toString()
        String toString():返回该对象的字符串表示。 
            toString方法、Random 默认打印地址值,需要覆盖重写
            ArrayList、Scanner 默认不是打印地址值
    2、equals方法--------快捷键:Alt+Insert  equals and hashCode()
         boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。 
            默认对比两个人对象的地址值,没有意义
        重写equals方法:比较两个对象的属性值(对象的参数,name,age )
            隐含一个多态:Object obj = new Person("焦玉良, 23);
                弊端:无法使用子类的特有内容(属性和方法)
                解决:向下转型(强转)把Object类转化成Person类
                    if(this == obj){
                        return true;
                    }
                    if(obj == null){
                        return false;
                    }
                    if(obj instanceof Person){
                        Person p = (Person) obj;
                        //比较两个对象的属性,一个调用方法的this(P1),一个是p(obj = p2)
                        boolean b = this.name.equals(p.name) && this.age == p.age;
                        return b;
                    }
                    return false;
    String类型防止比较有"null":
        boolean b = Objects.equals(str1, str2);

常用类

表示日期和时间的类:
 一、Date类:java.util.Date  类Date表示特定的瞬间,精确到毫秒。
        2020-07-26
        把日期转化成毫秒:
            时间原点(0毫秒):1970年1月1日 00:00:00
                System.currentTimeMillis()    //时间原点到当前系统时间的毫秒数
        把毫秒转化成日期:
            1天 = 24 * 60 * 60 * 1000 = 86400,000毫秒
        构造方法摘要 
            1、Date():分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。 
                in        System.out.println(new Date());
                out        Sun Jul 26 09:54:53 CST 2020
            2、Date(long date):传递毫秒值,再转化为Date日期                     
                in         System.out.println(new Date(0L));
                out     Thu Jan 01 08:00:00 CST 1970
        成员方法摘要
            3、long getTime():把当前系统日期转化为毫秒
                返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 
二、DateFormat类:java.text.DateFormat  
        日期/时间格式化子类的抽象类 格式化(也就是日期 -> 文本)、解析(文本-> 日期)
        成员方法摘要
            1、String format(Date date):将一个 Date 格式化为日期/时间字符串。 
            2、Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。 
        Abstract抽象类,不能直接创建对象使用,可以使用它的子类SimpleDateFormat java.text.SimpleDateFormat
         构造方法摘要: 
            SimpleDateFormat(String pattern):用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat。
                y 年    M 月    d 日    H 时    m 分    s 秒
                "yyyy-MM-dd HH:mm:ss"   "yyyy年MM月dd日 HH时mm分ss秒"

        1、使用DateFormat类中的format,把日期格式化为文本
        String format(Date date);
            1)创建SimpleDateFormat对象,构造方法中传递指定的格式
            2)调用SimpleDateFormat对象的方法format,按照构造方法中的指定的格式,把Date格式化为字符串(文本)

        2、使用DateFormat类中的format,把文本格式化为日期
        Date parse(String source);
            1)创建SimpleDateFormat对象,构造方法中传递指定的格式
            2)调用SimpleDateFormat对象的方法parse,按照构造方法中的指定的格式,把字符串(文本)格式化为Date
            注意:parse抛出一个ParseException异常
            解决:throws继续申明抛出这个异常,或者try...catch自己处理这个异常

三、Calender类:java.util.Calendar  日历类
        抽象类,不能创建对象。里面有一个静态方法叫getInstance(),该方法返回了一个Calender类的子类对象
            static Calendar getInstance():使用默认时区和语言环境获得一个日历。     
                Calendar c = Calendar.getInstance();
        public static final int
        YEAR年    MONTH月  DATE月中的某一天    DAY_OF_MONTH月中的某一天    HOUR时 MINUTE分    SECOND秒    
        常用方法:
            1、int get(int field):返回给定日历字段的值。 
                int year = c.get(Calendar.YEAR); 
            2、void set(int field, int value):将给定的日历字段设置为给定值。
                c.set(Calendar.YEAR,9999);      //两个参数
               void set(int year, int month, int date)      
                c.set(9999,9,9);    //三个参数
            3、abstract void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
                c.add(Calendar.YEAR,-23);     //2020-23=1997
            4、Date getTime():返回一个表示此 Calendar 时间值(从历元至现在的毫秒偏移量)的 Date 对象。 
                Date date = c.getTime();    //Sun Jul 26 15:31:33 CST 2020

四、System类:
        1、static long currentTimeMillis():返回以毫秒为单位的当前时间。 [测试程序执行效率]
            long time = System.currentTimeMillis();
        2、static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):
              从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
            参数:
                src - 源数组。
                srcPos - 源数组中的起始位置。
                dest - 目标数组。
                destPos - 目标数据中的起始位置。
                length - 要复制的数组元素的数量。

int[] src = {1, 2, 3, 4, 5};
int[] dest = {6, 7, 8, 9, 10};
System.out.println(Arrays.toString(dest));      //复制前dest:[6, 7, 8, 9, 10]
System.arraycopy(src,0, dest, 0,3);
System.out.println(Arrays.toString(dest));      //复制后dest:[1, 2, 3, 9, 10]

五、StringBuilder类:字符串缓冲区,提高字符串的操作效率(看成一个长度可变的字符串,未被final修饰)
        构造方法:
            1、StringBuilder():构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。
                StringBuilder bu1 = new StringBuilder();
                System.out.println(bu1);    //打印:空的
            2、StringBuilder(String str):构造一个字符串生成器,并初始化为指定的字符串内容。
                StringBuilder bu2 = new StringBuilder("abc");
                System.out.println(bu2);    //打印:abc

        成员方法:
            1、StringBuilder append(某参数):某参数的字符串表示形式追加到序列。
                某参数:任意的数据类型

StringBuilder bu1 = new StringBuilder();
StringBuilder bu2 = bu1.append("abc");
System.out.println(bu2);    //打印:abc
                
StringBuilder bu1 = new StringBuilder();
bu1.append("abc");
bu1.append(12);
System.out.println(bu1);    //打印:abc12
                
StringBuilder bu1 = new StringBuilder();
bu1.append("abc").append(12);    //打印:abc12

链式编程:方法的返回值是一个对象,可以根据对象继续调用方法。
            
            2、StringBuilder reverse():将此字符序列用其反转形式取代。 
            3、String toString():返回此序列中数据的字符串表示形式。 
                StringBuilder与String可以相互转化
                    String->StringBuilder:
                        StringBuilder(String str)构造一个字符串生成器,并初始化为指定的字符串内容。
                    StringBuilder->String:
                        StringBuilder中的toString方法。
                    '''    String str1 = sb.toString();

六、包装类:
        使用一个类,把基本类型的数据包装起来,这个类就是包装类。
        在包装类中可以定义一些方法,用来操作基本类型的数据。
        装箱与拆箱:基本类型与对应的包装类对象之间的来回转换。
        装箱:(Integer举例)    
            构造方法:
                1、Integer(int value):构造一个新分配的 Integer 对象,它表示指定的 int 值。 
                    ''' Integer i = new Integer(1);
                        System.out.println(i);        //打印:1
                2、Integer(String s):构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。
            静态方法:
                1、static Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例。 
                    ''' Integer i = Integer.valueOf("1");
                        System.out.println(i);        //打印:1
                2、static Integer valueOf(String s):返回保存指定的 String 的值的 Integer 对象。 
        拆箱:(Integer举例)    
            成员方法:
                int intValue():以 int 类型返回该 Integer 的值。 
                ''' Integer i = new Integer(1);
                    int j = i.intValue();
                    System.out.println(j);        //打印:1
        自动装箱与自动拆箱:

基本类型的数据和包装类之间可以自动的互相转换

Integer in = 1;     //等价于 Integer in = new Integer(1);
//in是包装类,无法直接参与运算,可以自动转化为基本类型的数据,再参与计算
in = in + 2;    //in + 2 等价于 in.intValue() + 2 = 3;
//in = in + 2;等价于 in = new Integer(3);
System.out.println(in);        //打印:3
        

基本类型与字符串之间的转化:(基本类型为int举例)
            基本类型->字符串:
                1、基本类型的数据值 + ""        //*推荐
                    ''' String str1 = 12 + "";
                        System.out.println(str1 + 200);        //打印:12200
                        
                2、使用包装类的静态方法。
                    static String toString(int i):返回一个表示指定整数的 String 对象。
                    ''' String str2 = Integer.toString(12);
                        System.out.println(str2 + 300);        //打印:12300
                        
                3、使用String类中的静态方法。
                    static String valueOf(int i):返回 int 参数的字符串表示形式。 
                    ''' String str3 = String.valueOf(12);
                        System.out.println(str3 + 400);        打印:12400
                        
            字符串->基本类型:
                使用包装类中的静态方法。
                    static int parseInt(String s):将字符串参数作为有符号的十进制整数进行解析。 
                    ''' int num = Integer.parseInt("12");
                        System.out.println(num + 500);        //打印:512
        
Collection集合:    java.util.Collection;        [无索引]

    框架:                         Collection                     接口
                         List                     Set             接口
            ArrayList LinkedList Vector     HashSet TreeSet       类
                                          LinkHashSet             类

    方法介绍: 
        '''创建集合对象(多态) 
            Collection<String> coll = new ArrayList<>();
        1、boolean add(E e):确保此 collection 包含指定的元素(可选操作)。
        2、boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。     
        3、boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true。 
        4、boolean isEmpty():如果此 collection 不包含元素,则返回 true。 
        5、void clear():移除此 collection 中的所有元素(可选操作)。 
        6、int size():返回此 collection 中的元素数。 
        7、object[] toArray():返回包含此 collection 中所有元素的数组。 
            '''    object[] arr = coll.toArray();

Iterator接口(迭代器):
    迭代:Collection集合元素的通用获取元素。先判断集合有没有元素,有取出,继续判断,有再取出,直到全部取出。
    
  **该接口无法直接使用,需要Iterator接口实现类对象,获取实现类比较特殊,Collection接口有一个方法叫iterator(),
    这个方法返回就是迭代器的实现类对象。
        Iterator<E> iterator():返回在此 collection 的元素上进行迭代的迭代器。 
        
    迭代器的使用步骤:
    1、先使用Collection集合中的方法iterator()获取迭代器的实现对象,使用Iterator接口接收(多态)
    2、使用Iterator接口中的hasNext()方法判断有没有下一个元素
    3、用Iterator接口中的next()方法取出下一个元素
    方法介绍;
        1、boolean hasNext():如果仍有元素可以迭代,则返回 true。 
        2、E next():返回迭代的下一个元素。

Collection<String> coll = new ArrayList<>();
coll.add("迪丽热巴");
Iterator<String> it = coll.iterator();
while (it.hasNext()){
   String str = it.next();
    System.out.println(str);
}
        

使用:for(Iterator<String> it = coll.iterator();it.hasNext();){...}
增强for循环:专门用来遍历集合和数组的。低层是Iterator迭代器,遍历过程不能对其中的元素增删操作。
        public interface Collection<E> extends Iterable<E>    所有单列集合都可以用增强for
        public interface Iterable<T> 实现这个接口允许对象成为 "foreach" 语句的目标。 
格式:
            for(集合/数组的数据类型 : 集合名/数组名){
                sout(变量名);
            }

int[] arr = {1, 2, 3, 4, 5};
for(int i : arr){
      System.out.println(i);
}

ArrayList<String> arr = new ArrayList<>();
arr.add("abc");
arr.add("def");
arr.add("ghi");
for(String str : arr){
     System.out.println(str);
}

泛型:一种未知的数据类型,不知道使用什么数据类型的时候,可以使用泛型。也可以看成一个变量,接收数据类型。
    E e:Element 元素
    T t:Type 类型
    比如:ArrayList<E>     创建集合对象的时候,就会确定泛型的数据类型。

    创建集合对象不使用泛型:默认类型为Object类型,可以存储任意类型的数据。但是不安全,会引发异常。
    创建集合对象使用泛型:避免了类型转化的麻烦,存储什么类型,取出就是什么类型。
                          但是泛型什么类型,只能存储什么类型。
    
定义和使用含有泛型的类:

//定义和使用含有泛型的类 模拟ArrayList
public class GenericClass<E> {
   private E name;
   public E getName() {
       return name;
   }
   public void setName(E name) {
       this.name = name;
   }
}    

定义和使用含有泛型的方法:
        定义在修饰符和返回值类型之间。
        格式:    
            修饰符 <泛型> 返回值类型(参数列表(使用泛型)){
                方法体;
            }

public class GenericMethod {
    public <M> void method1(M m){
        System.out.println(m);
    }
    public static <S> void method2(S s){
        System.out.println(s);
    }
} 

定义和使用含有泛型的接口:

//GenericInterface接口
            public interface GenericInterface<I> {
                public abstract void method(I i);
            }
//GenericInterfaceImpl接口实现的对象1    //第一种方式:定义接口的实现类,实现接口,指定接口的泛型
            public class GenericInterfaceImpl implements GenericInterface<String>{
                @Override
                public void method(String s) {
                    System.out.println("这是重写接口的第一种方法" + s);
                }  
            }         
//GenericInterfaceImpl_2接口实现的对象2  
            //第二种方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。
            //就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
            public class GenericInterfaceImpl_2<I> implements GenericInterface<I> {
                @Override
                public void method(I i) {
                    System.out.println("这是重写接口的第二种方法" + i);
                }
            }
//demo06GenericInterface主函数main中调用
            //第一种
            GenericInterfaceImpl gi = new GenericInterfaceImpl();
            gi.method("abc");
            //第二种
            GenericInterfaceImpl_2<String> gi2 = new GenericInterfaceImpl_2<>();
            gi2.method("6662jd");
        

    泛型通配符:
        不知道使用什么类型来接收的时候,此时可以使用?,表示未知通配符。
        此时只能接收数据,不能往该集合中存储数据。
        使用方式:
            不能创建对象使用,只能作为方法的参数使用。        

//main外面的方法
           private static void demo01(ArrayList<?> arr) {
                Iterator<?> it = arr.iterator();
                while(it.hasNext()){
                    Object o = it.next();
                    System.out.println(o);
                }
            }

        通配符高级使用---受限泛型    [看的懂就可以]
            泛型的上限限定:? extends E        代表使用的泛型只能是E类型的子类/本身
            泛型的下限限定:? super E        代表使用的泛型只能是E类型的父类/本身

public class demo08Generic {
                    public static void main(String[] args) {
                        Collection<Integer> list1 = new ArrayList<>();
                        Collection<String> list2 = new ArrayList<>();
                        Collection<Number> list3 = new ArrayList<>();
                        Collection<Object> list4 = new ArrayList<>();

                        getElement1(list1);
                        /*getElement1(list2);*/        X
                        getElement1(list3);
                        /*getElement1(list4);*/        X

                        /*getElement2(list1);*/        X
                        /*getElement2(list2);*/        X
                        getElement2(list3);
                        getElement2(list4);
                    }
                    //Integer extends Number extends Object
                    //String extends Object
                    
                    //泛型上限,此时?必须是Number或Number的子类
                    public static void getElement1(Collection<? extends Number> coll){}

                    //泛型下限,此时的?必须是Number或者Number的父类
                    public  static void getElement2(Collection<? super Number> coll){}
                }

数据结构:
    栈(stack):先进后出
    队列(queue):先进先出
    数组(array):查询快-地址是连续的。增删慢-长度是固定的。
    链表(Linked List):查询慢-地址不连续。增删快-元素增删后对整体结构没影响。
        每一个元素称为一个节点,一个节点包含一个数据源(存储数据),两个指针域(存储地址)。
        单向链表:不能保证元素的顺序(存储元素和取出元素的顺序有可能不一致)
        双向链表:有一条链子是专门记录元素的顺序,是一个有序集合
    红黑树(binary tree):趋近于平衡树,查询的速度非常快,查询叶子节点最大次数和最小次数不能超过2倍。

List集合:public interface List<E> extends Collection<E>
    有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。
    用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
    特点:
        1、有序的集合,存取元素和取出元素的顺序使一致的
        2、有索引,包含了一些带索引的方法
        3、允许存储重复的元素
    带索引的(特有)方法:
        1、void add(int index, E element):在列表的指定位置插入指定元素(可选操作)。 
        2、E get(int index):返回列表中指定位置的元素。
        3、E remove(int index):移除列表中指定位置的元素(可选操作)。
        4、E set(int index, E element):用指定元素替换列表中指定位置的元素(可选操作)。 
        '''    //创建一个List集合对象,多态
            List<String> list = new ArrayList<>();

    ArrayList集合:多线程,查询快,增删慢
    LinkedList集合:多线程,低层是一个链表结构,大量对首尾操作的方法,查询慢,增删快
        注意:使用特有方法的时候,不能使用多态
        1、void addFirst(E e):将指定元素插入此列表的开头。 
        2、void addLast(E e):将指定元素添加到此列表的结尾。 
        3、void push(E e):将元素推入此列表所表示的堆栈。((0号元素增加,相当于addFirst) 
        
        4、E getFirst():返回此列表的第一个元素。 
        5、E getLast():返回此列表的最后一个元素。 (增加一个isEmpty判断安全些)
        
        6、E removeFirst():移除并返回此列表的第一个元素。 
        7、E removeLast():移除并返回此列表的最后一个元素。 
        8、E pop():从此列表所表示的堆栈处弹出一个元素。 (0号元素删除,相当于removeFirst)
        ''' //创建LinkedList集合的对象
            LinkedList<String> link = new LinkedList<>();
    Vector集合:可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。单线程。      
          
Set接口:public interface Set<E> extends Collection<E>
    特点:
        1、不允许存储重复元素
        2、没有索引,没有带索引的方法,也没有普通的for循环

    HashSet集合:
        特点:无重复元素、没索引、无序集合(存取元素顺序可能不一致)、低层是哈希表结构(查询快)
        ''' Set<Integer> set = new HashSet<>();
        遍历用:迭代器、增强for
        
        哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,
                是模拟出来的地址,不是数据存储的队伍里地址)
            在Object类中有一个方法,可以获取对象的哈希值:
                int hashCode():返回该对象的哈希码值。 

        哈希表:
            哈希表=数组+链表
                  =数组+红黑树(提高查询速度)        
            
Set集合存储元素不重复的原理:
        Set集合在调用add方法的时候,add方法先会调用元素的hashCode方法和equals方法,判断元素是否重复。

        HashSet存储自定义类型元素:
            重写hashCode方法和equals方法。

    LinkedHashSet集合:具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
        低层是一个哈希表(数组+链表/红黑树)+链表;多了一个链表(记录元素的存储顺序),保证元素有序。

可变参数:
    使用前提:当方法参数列表数据类型已经确定,但是参数的个数不确定,就可以用可变参数。
    使用格式:(定义方法时使用) 
        修饰符 返回值类型 方法名(参数类型...形参名){}
        修饰符 返回值类型 方法名(参数类型[] 形参名){}
    可变参数的原理:
        可变参数低层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
        传递参数的个数可以是0个(不传参),1,2...多个。
    注意:
        1、一个方法的参数列表只能有一个可变参数
        2、如果方法参数有多个,那么可变参数必须写在参数列表的末尾
    可变参数的终极写法:
        public static void method(Object...obj){}

public class demo05VarArgs {
            public static void main(String[] args) {
                System.out.println(add(3,3));       //6
                System.out.println(add(3,3,6));     //12
                System.out.println(add(3,3,2,5,3,8));   //24
            }
            private static int add(int...arr) {
                int sum = 0;
                for (int i : arr) {
                    sum += i;
                }
                return sum;
            }
        }

Collections集合工具类:
    1、static <T> boolean addAll(Collection<? super T> c, T... elements):将所有指定元素添加到指定collection中。
    2、static void shuffle(List<?> list):使用默认随机源对指定列表进行置换。 

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a", "b", "c", "d");
Collections.shuffle(list);

    3、static <T> void sort(List<T> list):根据元素的自然顺序 对指定列表按升序进行排序。
        使用前提:被排序的集合里面存储的元素,必须实现Comparable,重写接口的方法compareTo定义排序规则。
        comparable接口排序规则:自己(this)- 参数 就是升序排序    

public class Person implements Comparable<Person>{
                ...
                //重写排序的规则
                @Override
                public int compareTo(Person o) {
                    //自定义规则,比较两个人的年龄(this,参数Person)
                    return this.getAge() - o.getAge();  //年龄升序排序
                }
            }

    4、static <T> void sort(List<T> list, Comparator<? super T> c):根据指定比较器产生的顺序对指定列表进行排序。         Comparable与Comparator的区别:
            Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较的规则compareTo
            Comparator:相当于找一个第三方的裁判,比较两个人

ArrayList<Integer> list = new ArrayList<>();
            Collections.addAll(list,2,5,3,4);
            System.out.println(list);        //[2, 5, 3, 4]
            Collections.sort(list, new Comparator<Integer>() {
                //重写比较规则
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 - o2; //升序
                }
            });
  System.out.println(list);        //[2, 3, 4, 5]

Map集合:
    Map<K,V>类型参数:
        K - 此映射所维护的键的类型
        V - 映射值的类型
    特点:
        1、Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
        2、Map集合中的元素,key和value的数据类型可以相同,也可以不同
        3、Map集合中的元素,key是不允许重复的,但是value是可以重复的
        4、Map集合中的元素,key和value是一一对应的

Map的常用子类:
    HashMap<K,V>集合:
        1、低层是哈希表:查询快。
        2、无序的集合,存取元素顺序可能不同。
    LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
        1、低层是哈希表+链表(保证迭代的顺序)
        2、有序的集合,存取元素的顺序一致的
        
Map接口中常用方法:
    1、V put(K key, V value):将指定的值与此映射中的指定键关联(可选操作)。[可以不接收返回] 
        返回值V:存储键值对的时候,key不重复,返回值V是null;key重复,会使用新的value替换已有的值,返回被替换的value
        ''' //创建Map集合对象,多态
            Map<String,String> map = new HashMap<>();
            String v1 = map.put("liChen", "fanBing1");
            System.out.println(v1); //null
            String v2 = map.put("liChen", "fanBing2");
            System.out.println(v2); //fanBing1
            System.out.println(map); //{liChen=fanBing2}
            
    2、V remove(Object key):如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
        返回值V:key存在,v返回被删除的值;key不存在,返回值是null
        
    3、V get(Object key):返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
        返回值V:key存在,返回value的值;key不存在,返回值是null
        
    4、boolean containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true。 
    
Map集合遍历键找值方式:
    5、Set<K> keySet():返回此映射中包含的键的 Set 视图。 
        步骤:
            1、使用Map集合的方法keyset(),把Map集合所有的key取出来,存储到set中
            2、遍历set集合,获取Map集合中的每一个key。
            3、通过Map集合中的方法get(key),通过Key找value。
        ''' Map<String, Integer> map = new HashMap<>();
            map.put("ZhangSan",18);
            map.put("LiSi",17);
            map.put("WangWu",28);
            Set<String> strs = map.keySet();
            //增强for
            for (String str : strs) {
                Integer value = map.get(str);
                System.out.println("key:" + str + ";Value:" + value);
            }
            
    6、Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射关系的 Set 视图。 
        Entry键值对对象:
            作用:当Map集合一创建,那么就会在Map集合中一个Entry对象,用来记录键与值(键值对对象、键与值的映射关系)
        把Map集合内部的多个Entry对象取出来存储到一个set集合中。    
        Entry的方法:
            K getKey():返回与此项对应的键。 
            V getValue():返回与此项对应的值。 

Map集合遍历键值对方式:
    '''    Map<String, Integer> map = new HashMap<>();
        map.put("ZhangSan",18);
        map.put("LiSi",17);
        map.put("WangWu",28);
        Set<Map.Entry<String, Integer>> set = map.entrySet();
        //迭代器
        Iterator<Map.Entry<String, Integer>> it = set.iterator();
        while(it.hasNext()){
            Map.Entry<String, Integer> entry = it.next();
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + "--->" + value);
        }

HashMap存储自定义类型键值:
    Map集合保证key是唯一的:作为key元素,必须重写hashCode和equals方法,以保证key唯一。

LinkedHashMap集合:public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 有序的集合

HashTable集合:public class Hashtable<K,V> implements Map<K,V>
    特点:
        单线程安全的,速度慢。(与HashMap相反)
        key、value都不能为空。(与HashMap相反)
        子类Properties集合是一个唯一的与IO流相结合的集合。

JDK9的of方法:
    List接口、Set接口、Map接口,静态方法of,可以给集合一次性添加多个元素
    使用前提:当集合中的元素的个数已经确定了,不再改变时使用。
    注意:of方法只用于List、Set、Map接口,不适用于接口的实现类
          of的方法返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素
          Set、Map调用不能有重复的元素
          
        ''' List<String> list = List.of("a","b","c","d","e");

DeBug追踪:
    可以让代码逐行执行,查看代码执行全过程,调试程序中的BUG

异常:    Throwable->Error、Exception
    Exception:编译期异常,进行编译(写代码)java程序出现的问题
        RuntimeException:运行期异常,java运行过程出现的异常
   
throw关键字:在指定的方法中抛出指定的异常-参数校验
    格式:throw new xxxException("异常产生的原因");
    注意:必须写在方法内部、new的对象是Exception或它的子类对象
          throw关键字后创建的是编译异常,必须处理,用throws或者try...catch
            文件找不到异常:FileNotFoundException
          throw关键字后创建的是RuntimeException及其子类可以不处理,默认交给JVM打印,中断
            空指针异常:NullPointerException
            数组索引越界异常:ArrayIndexOutOfBoundsException

Objects非空判断:(静态方法)
    public static <T> T requireNonNull(T object);查看指定索引对象是不是空。
    ''' public static void main(String[] args) {
            method(null);
        }
        public static void method(Object obj){
            /*if(obj == null){
                throw new NullPointerException("传递对象是null");
            }*/
            Objects.requireNonNull(obj, "传递对象是null");
        }

throws关键字:异常处理第一种方式-交给别人处理
    格式:修饰符 返回值类型 方法名(参数列表) throws xxxException...{
               throw new xxxException("异常原因:xxxException");
               ...
          }
    注意:必须写在方法声明处、声明的异常是Exception或它的子类对象(多个异常:直接写父类异常)
          必须处理-继续使用throws,交给方法调用者处理,再给JVM
                  -try...catch自己处理
        '''    public static void main(String[] args) throws FileNotFoundException,IOException {
                readFile("C:\\b.txt");
            }
            public static void readFile(String fileName) throws FileNotFoundException,IOException {
                if(!fileName.equals("C:\\a.txt")){
                    throw new FileNotFoundException("文件路径错误");
                }
                if(!fileName.endsWith(".txt")){
                    throw new IOException("文件后缀错误");
                }
                System.out.println("文件没问题,读取文件");
            }

try...catch:异常处理第一种方式-自己处理异常
    格式:
        try{
            可能产生异常的代码;
        }
        catch(定义一个异常变量,接收try抛出的异常对象){
            异常处理逻辑,异常之后怎么处理异常对象
            工作中:异常信息记录在日志里
        }
        ...
        catch(异常类名 变量名){
            ...
        }

Throwable异常处理的3个方法:
    1、String getMessage():返回此 throwable 的简短描述。 
    2、String toString(): 返回此 throwable 的详细消息字符串。
    3、void printStackTrace():将此 throwable 及其追踪输出至标准错误流。
    ''' try {
            readFile("C:\\a.tct");
        } catch (IOException e) {
            System.out.println(e.getMessage());//文件后缀错误
            System.out.println(e.toString());//java.io.IOException: 文件后缀错误
            e.printStackTrace();//java.io.IOException: 文件后缀错误
                                //at Demo0802.demo5Throwable.readFile(demo5Throwable.java:24)
                                //at Demo0802.demo5Throwable.main(demo5Throwable.java:14)
        }

finally代码块:一些特定的代码无论是否异常都要执行
    格式:    
        try{
            ...
        }catch(){
            ...
        }finally{
            无论是否异常都会执行
        }
    注意:与try一起使用,资源释放IO流
    如果finally有return语句,那么返回的就是finally的结果(避免finally中写return)

多个异常的捕获处理:
    1、多个异常分别处理
        多个try...catch
    2、多个异常一次捕获,多次处理
        一个try,多个catch
        [异常变量有子父类关系,子类写在前,否则会报错]
    3、多个异常一次捕获,一次处理
        catch(Exception e){
            ...
        }
        [可以不处理]
        
    子类重写父类方法时,抛出和父类一样的异常
                        抛出父类异常的子类
                        不抛出异常
    父类方法没有抛出异常,子类重写父类方法也不可能抛出异常
                          此时子类产生该异常,只能捕获处理,不能声明抛出

自定义异常类:
    格式:
        public class XXXException extends Exception | RuntimeException {
            添加一个空参数的构造方法
            添加一个带异常信息的构造方法
        }

并发:指两个或者多个事件在同一个时间段内发生。---交替执行
并行:指两个或者多个事件在同一个时刻发生(同时发生)。---同时执行
进程:进入到内存中的程序
线程:CPU执行程序的路径
    线程属于进程,是进程的一个执行单元,负责程序的执行
线程调度:分时调度,抢占式调度

主线程:main<=>cpu

创建多线程程序:(第一种方式)
    1、创建一个Thread子类
    2、在Thread子类中重写run方法,设置线程任务
    3、创建Thread类的子类对象
    4、调用Thread类中的方法start方法,开启新的线程,执行run方法。

    void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 

    Thread类的常用方法:
        获取线程的名字:
            1、使用Thread类中的getName()
                String getName():返回该线程的名称。
            2、先获取到当前正在执行的线程,使用线程中的方法getName()获取线程名称
                static Thread currentThread():返回对当前正在执行的线程对象的引用。 
            '''    Thread.currentThread().getName();
            主线程:main
            新线程:Thread-0...
        设置线程的名称:
            1、使用Thread类中的setName()
                void setName(String name):改变线程名称,使之与参数 name 相同。
            2、创建一个带参数的构造方法,重写MyThread类->把线程名称传递给父类,让父类给子线程起一个名字。 
                Thread(String name):分配新的 Thread 对象。
            MyThread里重写构造方法:
                public MyThread(String name) {
                    super(name);
                }
        
    static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),
                                    此操作受到系统计时器和调度程序精度和准确性的影响。 
        '''    Thread.sleep(1000);

创建多线程程序:(第二种方式)实现Runnable接口
    ''' public class RunnableImpl implements Runnable{
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "->" + i);
                }
            }
        }    
    ''' public class demo10Runnable {
            public static void main(String[] args) {
                RunnableImpl run = new RunnableImpl();
                new Thread(run).start();
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "->" + i);
                }
            }
        }
        
匿名内部类创建线程:        
    '''    public static void main(String[] args) {

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

                Runnable run = new Runnable(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 20; i++) {
                            System.out.println(Thread.currentThread().getName() + "->" + i);
                        }
                    }
                };
                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() + "->" + i);
                        }
                    }
                }).start();

        }

解决线程安全问题:
    线程同步:同步代码块、同步方法、锁机制。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值