华清远见-重庆中心-JAVA高级阶段知识点梳理

1.Object类

1.1Object类的介绍

1. java.lang.Object类是所有类的父类

2.万事万物皆可对象

3.一个类没有使用extends继承某个特定父类,那么他的父类就是Object

4.Object类定义了对象的基本行为,可以被子类使用

package seDay1;

import java.util.Date;

public class TestObject {
    public static void main(String[] args) {
        Object obj = new Object();
        System.out.println(obj);

        Student stu = new Student("1001", "tom", 20);
        Class aClass = stu.getClass();//getClass()是object中的一个方法
        System.out.println(aClass);//输出class seDay1.Student
        Object tom = new Student("1001", "tom", 20);
        //类.class的到的是类的全名
        if (tom.getClass()==Student.class){
            //强制类型转换
            Student stu1=(Student) tom;
            System.out.println(stu1.getStuName());
        }

        print("hello");
        print(new Date());
        print(stu);
        print(100);
    }

    //写一个方法,带参数,将参数输出
    public static void print(Object o){
        System.out.println(o);
    }
}

1.2 toString

1.Object类中的toString方法,用于返回对象成员变量的字符串。类名+@+16进制整数

2.通常会重写toString方法,返回更有意义的字符串

1.3equals

1.Object类中的equals方法,用于判断对象是否相等,也就是引用地址是否相等

2.重写equals方法后,比较的是值是否相等

注意:
1.在使用字符串时,如果要比较其值是否相同,不要使用==判断,因为==判断的是内存地址;所以在比较字符串是否相同时,要使用String类重写的equals方法进行判断。

2.equals的原理:将两个字符串用字符数组保存,逐个判断字符数组中的每个字符,全部一致 时返回true;在使用equals方法时,通常将已知的非空字符串作为调用者,避免空指针异常。
 

1.4hashCode

1.Object类中的hashCode方法,根据对象的内容,返回一个整数值

2.一般重写了equals方法就会要求重写hashCode方法

package seDay1;

import java.util.Objects;
//重写父类(Object)中的toString、equals、hashCode方法
public class Student {
    private String stuNo;
    private String stuName;
    private int  stuAge;

    public Student() {
    }

    public Student(String stuNo, String stuName, int stuAge) {
        this.stuNo = stuNo;
        this.stuName = stuName;
        this.stuAge = stuAge;
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(stuNo, stuName, stuAge);
    }

    public String getStuNo() {
        return stuNo;
    }

    public void setStuNo(String stuNo) {
        this.stuNo = stuNo;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public int getStuAge() {
        return stuAge;
    }

    public void setStuAge(int stuAge) {
        this.stuAge = stuAge;
    }

    @Override
    public String toString() {
        return "Student{" +
                "stuNo='" + stuNo + '\'' +
                ", stuName='" + stuName + '\'' +
                ", stuAge=" + stuAge +
                '}';
    }
}

2.String字符串

String是一个类,属于数据类型中的引用类型,Java中一切使用" "引起来的内容,都是这个类的实例,称为字符串对象;字符串在定义后,值不可改变,是一个常量,实际是一个字符数组

package seDay1;

public class StringDemo1 {
    public static void main(String[] args) {
        //字符串不可变,不是通过new创建出来的字符串都是存在常量池中
        String str1="hello";
        String str2="hello1";
        System.out.println(str1==str2); //false

        String str3="hello";
        System.out.println(str1==str3);//true

        String str4="hello"+"1";//编译的时候,先运算,然后到字符串常量池里去找,如果存在,就把值的地址赋值个str4,如果不存在,就创建一个
        System.out.println(str2==str4); //true

        String str5=str1+"1";
        System.out.println(str5==str2);//false 跟变量做拼接,运行的时候才会拼接字符串,和常量池中的地址不等

        String str6 = new String("hello"); //new了一个对象,"hello"存在堆内存中
        System.out.println(str6==str1);//false
    }
}

1.2String类

如果频繁地将一个String类型变量的值进行更改时,会创建很多字符串对象。效率 低,浪费内存空间。所以在频繁更改字符串时,不要使用String类变量。如果要频繁更改字符串,使用StringBuilde类StringBuffer类

1.3 如何创建字符串对象

1.2.1使用" "赋值创建

String str = " abc ";

1.2.2通过构造方法创建 

常用构造方法 说明
String() 创建一个空白字符串对象
String(String str) 创建一个指定字符串的字符串对象
String(char[ ]  list) 创建一个指定字符数组的字符串对象
String(byte[ ]  list,String charsetName) 按指定的编码格式创建一个指定数组的字符串对象

使用 " " 赋值的形式创建

//先判断字符串常量池是否存在" ab ",不存在就创建,将其地址保存到str1变量中 
String str1="ab";

//先判断字符串常量池是否存在" ab ",已经存在就不用创建,将其地址保存到str2变量中
String str2="ab";

//+如果两端都是" "定义的字符串,拼接后再判断字符串常量池是否存在,如果不存在就创建,如果存在就将其地址保存到str3变量中
String str2="a" + "b";

System.out.println(str1==str2);//true
System.out.println(str1==str3);//true

使用构造方法String(String str)创建

//这句话执行时的流程
//1.在字符串常量池中寻找"ab",不存在,创建
//2.在堆中new String(),将字符串常量池中的"ab"保存到new出来的区域
//3.将堆中new出来的地址保存到栈中变量str1中
String str1 = new String("ab");


//这句话执行时的流程
//1.在字符串常量池中寻找"ab",存在,直接引用
//2.在堆中new String(),将字符串常量池中的"ab"保存到new出来的区域
//3.将堆中new出来的地址保存到栈中变量str2中
String str2 = new String("ab");


//由于str1和str2是堆中的两个区域,所以结果为false
System.out.println(str1 == str2);//false

使用+拼接""和new出来的字符串对象创建

//在字符串常量池中创建"ab"
String str1 = "ab";


//1.创建StringBuilder对象
//2.在字符串常量池中创建"a"
//3.在字符串常量池中创建"b"
//4.创建String对象
//5.调用StringBuilder的append方法,将"a"和new String("b")拼接
String str2 = "a" + new String("b");//一共创建了"a","b",String,StringBuilder这四个对
象


//两个不同的地址
System.out.println(str1==str2);//false

注意:

1.在使用字符串时,如果要比较其值是否相同,不要使用==判断,因为==判断的是内存地址;所以在比较字符串是否相同时,要使用String类重写的equals方法进行判断。

2.equals的原理:将两个字符串用字符数组保存,逐个判断字符数组中的每个字符,全部一致 时返回true;在使用equals方法时,通常将已知的非空字符串作为调用者,避免空指针异常。

1.4String类中常用的方法

方法名 返回值 作用
length() int 得到字符串的长度
toLowerCase() String 将字符串转换为小写
toUpperCase() String 将字符串转换为大写
trim() String 去掉字符串首位所有空格
isEmpty() boolean 判断字符串是否为空白字符串
getBytes() byte[ ] 将字符串转换为字节数组
toCharArray() char[ ] 将字符串转换为字符数组
equalsIgnoreCase(String str) boolean 忽略大小写判断两个字符串是否相同
equals(String str boolean 判断两个字符串是否相同
charArt(int index) char 得到字符串指定索引上的字符
indexOf(String str) int

得到指定字符串第一次出现的索引,如果不存在。返回-1

lastIndexOf(String str) int 得到指定字符串最后一次出现的索引,如果不存在。返回-1
contains(字符序列化) boolean 判断某个字符串是否在原字符串中出现
concat(String str) String  将参数字符串拼接到原字符串末尾
starsWith(String str) boolean 判断是否以指定字符串开头
endsWith(String str) boolean 判断是否以指定字符串结尾
substring(int begin) String  从指定索引开始截取字符串至末尾
substring(int begin,int end) String  截取[ begin ,end)区间的字符串
split(String regex) String [ ] 按执行字符串或正则表达式切分原字符串。如果指定内 容不再末尾,n个指定字符能得到n+1个子串;如果指定 内容在末尾,n个指定字符能得到n个子串(不包含末尾 的无效字符)
replace(char oldChar,char newChar ) String 将原字符串中的指定字符替换为新字符
String.valueOf(参数) String 将任意参数转换为字符串。通常用于原始类型转换为字符串
String.formart(String 格 式,Object... obj) String 根据指定格式转换参数。常用于将浮点数保留小数。如 String.format("%4.2f",10.0/3)表示将计算的结果四舍 五入保留2位小数转换为字符串;如果最终数据所占位 置小于4,原样输出,大于4在最前补充空格

3.正则表达式

3.1正则表达式介绍

1.正则表达式是一个特殊的字符串,是由一些特定的字符串组成的“规则字符串”

2.正则表达式,主要用于对字符串进行匹配,查找,替换等操作

3.正则表达式的规则

可以出现的字符

华清远见-重庆中心-JAVA高级阶段知识点梳理_第1张图片

可以出现的字符简写

 华清远见-重庆中心-JAVA高级阶段知识点梳理_第2张图片

字符出现的次数

华清远见-重庆中心-JAVA高级阶段知识点梳理_第3张图片

其他规定

华清远见-重庆中心-JAVA高级阶段知识点梳理_第4张图片

 3.2正则表达式在String中的使用

1.split方法把字符串按照指定的分隔符,分割为字符串数组

2.String提供了用于字符串替换的方法

package seDay2;

import java.util.Arrays;

//正则表达式
public class StringDemo {
    public static void main(String[] args) {
        String str = "aa123bb33cc3333dd1122";
        String regex = "[0-9]{1,}";//正则表达式,最少出现一个0~9的数字
        //根据数字进行切割,把连续的字母取出来,保存在一个数组中
        String[] split = str.split(regex);
        System.out.println(Arrays.toString(split));
        //把字符串转为字符数组,然后用-把元素连成字符串
        String str2 = "123456789";
        String str3 = "";
        char[] chars = str2.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            str3 += chars[i] + "-";
        }
        //去掉最后的-
        str3 = str3.substring(0, str3.length() - 1);
        System.out.println(str3);
        //将2023.1.5输出为2023-1-5
        String year = "2023.1.5";
        //根据正则表达式,把匹配成功的全换成"-"
        System.out.println(year.replaceAll("\\.{1,}", "-"));
        //将tom替换成TOM
        String s1 = "djdtomdddtomxxxeretomxxtom";
        System.out.println(s1.replaceAll("tom", "TOM"));
        //敏感词过滤
        String s3="你最近身体好吗,你妈身体好吗,你妹妹身体好吗";
        System.out.println(s3.replaceAll("你妈|你妹", "****"));
    }
}

4.可变字符串StringBuffer & StringBuilder

4.1StringBuilder类

用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。

4.2StringBuffer类

用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用。

StringBuilder和StringBuffer中的方法都一致,只不过StringBuffer中的方法使用了synchoronized关键字修饰,表示是一个同步方法,在多线程环境下不会出现问题。

4.3构造方法

常用构造方法 作用
StringBuilder 创建一个大小为16的字符串数组,表示一个空白字符。类似于String str=" ";
StringBuilder(String str) 创建一个str长度+16的字符数组后,将str添加到其中。类似于String str="初始值";

4.4普通方法

常用方法 作用
append(Object obj) 将任意类型的参数添加到原可变字符串末尾
delete(int start ,int end) 删除[ start ,end)区间内的字符
deleteCharAt( int index ) 删除index索引上的字符
insert(int index,Object obj) 在索引index上插入obj
replace(int satrt, int end,String str) 将[ start ,end)区间的字符替换为str
reverse() 反转字符串(顺序颠倒)

注意:

1.以上表格中的方法都是在直接操作同一个字符串对象,每次调用方法后,原字符串都会发生变化

2.StringBuffer和StringBuilder并没有重写equals方法,所以可变字符串的值是否相同时,调用的是 equals中原始的==判断。如果要判断两个可变字符串的值是否相同时,需要将其转换为String后调 用equals判断 

5.可变字符串与String之间的转换

5.1String转换为可变字符串

String str="hello";
//通过构造方法将String"包装"为可变字符串对象
StringBuilder sb = new StringBuilder(str);

5.2可变字符串转换为String(任意类型转换为String )

方法一:String.valueOf(Object obj)方法

StringBuilder sb = new StringBuilder("你好");
//调用静态方法
String str =String.valueOf(of);

方法二:对象.toString();

StringBuilder sb = new StringBuilder("你好");
//调用toString()
String str = sb.toString;

 方法三:

StringBuilder sb = new StringBuilder("你好");
//拼接一个空字符串
String str = sb = " ";

5.3String、StringBuilder和StringBuffer的区别

一、相同点:

1.这三个类都可以表示字符串。都提供了一些操作字符串的方法。

2.这三个类中有相同的方法,如charAt()、indexOf()等

3.这三个类都是被final修饰的类,不能被继承

二、不同点:

1.String定义的字符串是一个常量。可变字符串定义的字符串是一个变量

2.String类中的方法,调用后,不会改变原本字符串的值;可变字符串类中的方法,调用后,会改变原本字符串的值

3.StringBuilder是非线程安全的可变字符串类,StringBuffer是线程安全的可变字符串类,其中的方 法被synchronized修饰

注意:

在频繁操作同一个字符串时,一定要使用可变字符串StringBuidler或StringBuffer类的对象,不能使用 String类的对象。


6.Date类

 用于表示日期时间的类,位于java.util包下

6.1构造方法

常用构造方法 说明
Date() 创建当前瞬间对应的日期对象
Date(long l) 创建指定瞬间对应的日期对象
Date(int year,int month,int day) 该方法已经过时,创建指定年月日的日期对象(年是1970年起经过的年数,月用0-11表示表示1到10月)

6.2常用方法

常用方法 作用
getTime() 得到对应Date对象表示的毫秒数
setTime(long l) 设置Date对象的毫秒数
after(Date when) 判断调用日期对象是否在when之后
before(Date when) 判断调用日期对象是否在when之前

7.SimpleDateFormat类

7.1构造方法

常用构造方法 作用
SimpleDateFormat(String pattern) 创建一个指日期模板的格式化日期对象

7.2日期模板

特殊字符 作用
yyyy 年份
MM 月份
dd 日期
HH 24小时
hh 12小时
mm 分钟
ss
E 星期
以上两个字母都可以写成一个 M: 5 , MM: 05
yyyy/MM/dd HH:mm:ss   E 2022年12月3日 20:29:24 星期六

7.3常用方法

常用方法 返回值 作用
format(Date date) String 将Date对象按日期模板转换为字符串
parse(String str) Date 将满足日期模板的字符串转换为Date对象
package seDay2;
//Date类、
// 日期模板类:SimpleDateFormat
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateDemo {
    public static void main(String[] args) throws ParseException {
        Date date = new Date();
        //Date中重写了object中的toString方法,获取的当前系统时间
        System.out.println(date);
        //获取时间毫秒数,从1970,1,1日开始
        System.out.println(date.getTime()/1000/3600/24);
        //设置时间毫秒数
        date.setTime(365l*24*3600*1000);
        //设置指定时间  Date类不方便,需使用Calendar类

        //日期格式化
        SimpleDateFormat sdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
        //format(Date)将Date类型转为String类型
        System.out.println(sdate.format(date));

        //parse(String) ,将满足日期格式化的字符串类型的日期转换为Date类型
        String birth="2000-4-14  12:30:00 星期五" ;
        System.out.println(sdate.parse(birth));

        //计算活了多少天
        Date mybirth=sdate.parse(birth);//出生日期
        Date now = new Date();//当前时间
        System.out.println((now.getTime() - mybirth.getTime()) / 1000 / 3600 / 24);
    }
}

8.Calendar类

1.表示日历的类,包含了很多日历相关的信息。

2.是一个抽象类,无法创建对象,可以通过静态方法getInstance()获取该类的一个实例。

8.1日历字段

在Calendar类中,定义了很多被final和static修饰的常量,称为日历字段,实际一个数字,用于获取指 定信息

作用
Calendar.YEAR 年份
Calendar.MONTH 月份(0-11表示1-12月)
Calendar.DATE 日期
Calendar.DAY_OF_WEEK 星期(1-7表示周天到周六)
Calendar.HOUR 12进制小时
Calendar.HOUR_OF_DAY 24进制小时
Calendar.MINUTE 分钟
Calendar.SECOND
Calendar.DAY_OF_MONTH 本月第几天
Calendar.DAY_OF_YEAR 本年第几天
Calendar.WEEK_OF_MONTH 本月第几周
Calendar.WEEK_OF_YEAR 本年第几周

8.2常用方法

常用方法 作用
get(int field) 根据日历字段获取对应的值
getTime() 获取对应的Date对象(Calendar对象转换为Date对象)
getMaximum(int field) 获取指定日历字段支持的最大值,如CalendaR.DATE最大为31
getActualMaximum(int field) 获取指定日历字段在当前日期下的实际最大值,如11月, Calendar.DATE最大30
set(int field,int value) 将指定的日历字段设置为指定值
set(int year,int month,int date) 同时设置日历对象的年月日
setTime(Date date) 将Date对象作为参数设置日历对象的信息
package seDay2;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

//Calendar:日历,是一个抽象类
public class CalendarDemo {
    public static void main(String[] args) {
        SimpleDateFormat sdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
        //创建对象
        Calendar c1=Calendar.getInstance();
        GregorianCalendar c2 = new GregorianCalendar();

        //get:获取时间分量(年、月、日、时、分、秒、周几....)
        System.out.println(c1.get(Calendar.YEAR));//获取年份
        System.out.println(c1.get(Calendar.MONTH)+1);//获取月份0~11表示1~12月
        System.out.println(c1.get(Calendar.DATE));//获取天
        System.out.println(c1.get(Calendar.HOUR_OF_DAY));//获取小时
        System.out.println(c1.get(Calendar.MINUTE));//获取分钟
        System.out.println(c1.get(Calendar.SECOND));//获取秒
        System.out.println(c1.get(Calendar.DAY_OF_WEEK));//获取星期 周日~周六是1~7
        //三目运算
        int week= c1.get(Calendar.DAY_OF_WEEK);
        String wk= week==1?"周日":"周"+(week+1);

        //set:设置时间分量 2021-11-11  12:00:00
        c2.set(2021,10,11,12,00,00);
        System.out.println(c2);

    }
}

9.包装类

包装类就是原始类型对应的类的引用类型,包装类通常用于字符串与原始类型之间的转换。

在web应用中,从浏览器页面中获取到后台的数据,全部都是String类型,所以一定要使用转换为原始类型的方法。 

包装类 原始类型
Byte byte
Short short
Integer int
Long long
Float float
Double double
Character char
Boolean boolean

9.1特点

1.八个原始类型中,除了int和char,其余类型的包装类,都是将首字母改为大写。int对应 Integer,char对应Character

2.包装类都是被final修饰的,不能被继承

3.除了Character类,其余包装类都有两个构造方法:参数为原始类型或String的构造方法。 Character的构造方法只有一个,参数为char类型。这些构造方法用于将原始类型或字符串转换为 包装类对象

4.除了Character类,其余类都有静态方法parse原始类型(String str),用于将字符串转换为相应的 原始类型      

5.除了Boolean类,其余包装类都有MAX_VALUEMIN_VALUE这两个静态属性,用于获取对应类 型支持的最大最小值

6.所有包装类都重写了toString()方法,用于将包装类对象转换为String对象 

9.2字符串与原始类型之间的转换 

9.2.1字符串转换为原始类型

使用原始类型对应的包装类,调用parse原始类型(字符串)方法

String num="123";
byte b = Byte.parseByte(num);//123
short s = Short.parseShort(num);//123
int i = Integer.parseInt(num);//123
long l = Long.parseLong(num);//123
float f = Float.parseFloat(num);//123.0
double d = Double.parseDouble(num);//123.0
boolean flag = Boolean.parseBoolean(num);//false

9.2.2原始类型转为字符串

1.使用+拼接一个空白字符串

int num = 123;
String str = num + "";

2.将原始类型转换为包装类后,调用toString()方法

int num = 123;
Integer integer = new Integer(num);
String str = integer.toString();

3.String.valueOf(原始类型数据)

int num = 123;
String str = String.valueOf(num);

9.3装箱和拆箱

9.3.1装箱boxing

所有包装类都有一个静态方法valueOf(原始类型),将某个原始类型的数据转换为相应的包装类对 象。

//手动装箱
int i = 123;
//定义原始类型数据

Integer integer = Interger.valueOf(i);
//调用包装类Integer的静态方法valueOf()将原始类型转换为包装类对象

9.3.2拆箱unboxing 

所有包装类都有一个原始类型Value()方法,用于将包装类对象转换为原始类型。这个过程称为拆 箱unboxing。

//手动拆箱
Integer integer = new Integer(123);
//创建一个包装类对象

int i = integer.intValue();
//调用包装类对象的intValue()方法将包装类对象转换为原始类型

 9.3.3自动装箱和拆箱

在jdk1.5之后,为了方便原始类型和包装类之间做转换,加入了自动装箱拆箱的概念,可以直接将原始类型和包装类对象之间互相赋值

 
        Integer i4=100;//自动装箱
        int i=new Integer(100);//自动拆箱
        System.out.println(i4==i);//true 自动拆箱,转为int类型
        System.out.println(i4.equals(i));//true 自动装箱
        //System.out.println(i.equals(i4));//编译错误,基本数据类型没有equals方法

9.4包装类的使用

package seDay3;

//8中基本数据类型,jdk都提供了对应的引用类型(包装类)
//平时使用的时候,包装类和基本数据类型会自动转换(自动装箱、自动拆箱)
//包装类的默认值是null,基本数据类型有自己的默认值
public class IntegerDemo {
    public static void main(String[] args) {
        //创建对象
        Integer i1 = new Integer(100);//没有无参构造函数
        System.out.println(i1);//100
//        Integer i2=new Integer("100a");//异常,数字格式化异常
//        System.out.println(i2);
        Integer i3 = new Integer("200");
        System.out.println(i3);

        //调用方法
        float f1 = i3.floatValue();//将Integer转为float
        Integer i2 = new Integer(100);
        int b = i3.compareTo(i2);
        //i3大于i2,输出为正数;i3等于i2输出0;i3小于i2,输出负数
        if (b > 0) {
            System.out.println("i3大");
        } else if (b < 0) {
            System.out.println("i2大");
        } else {
            System.out.println("相等");
        }
        System.out.println(i1.equals(i2));//true,重写了equals方法

        //类型转换
        Integer i4=100;//自动装箱
        int i=new Integer(100);//自动拆箱
        System.out.println(i4==i);//true 自动拆箱,转为int类型
        System.out.println(i4.equals(i));//true 自动装箱
        //System.out.println(i.equals(i4));//编译错误,基本数据类型没有equals方法

        //Integer的其他方法
        System.out.println("最大值:"+Integer.MAX_VALUE);
        System.out.println("最小值:"+Integer.MAX_VALUE);
        String str="100";
        int a =Integer.parseInt(str);//将字符串解析为整数
        System.out.println(a);
        String str1="1000.2345";
        //int a1 =Integer.parseInt(str1);//数字格式化异常
        //System.out.println(a1);

        System.out.println(Integer.toBinaryString(100));//转为2进制的字符串
        System.out.println(Integer.toHexString(100));//转为16进制的字符串
    }
}

总结:

1.如果通过构造方法创建的包装类对象,会有不同的内存地址,使用==判断结果为false

2.自动装箱方式创建包装类对象,赋值范围在byte范围[-128,127]内,将这个值保存在缓冲区 中,如果多个对象使用同一个数值,共享这个数据,使用同一个地址,使用==判断结果为 true;如果不在byte范围内,就会创建新的包装类对象,会有不同的内存地址,使用==判断结果为false

3.引用类型对象比较值是否相同时,不要使用==,而是要使用重写的equals方法

9.5BigDecimal & BigInteger

9.5.1BigDecimal

1.java中的浮点数类型(float , double)在运算时会有舍入误差,如果希望得到精确的运算结果,可以 使用java.math.BigDecimal类

9.5.2BigInteger

1.dk中提供的整数类型(int ,long )的储值范围有限,当需要进行很大的整数运算时,可以使用 java.math.BigInteger,理论上BigInteger数据范围只受内存容量的限定。

package seDay3;
//BigDecimal得到精确运算结果
//BigInteger需要进行很大的整数运算时使用
import java.math.BigDecimal;
import java.math.BigInteger;

public class BigDecimalDemo {
    public static void main(String[] args) {
        BigDecimal bd = new BigDecimal("3.5");
        BigDecimal bd1 = new BigDecimal("5.2");
        //加法
        BigDecimal add=bd.add(bd1);
        System.out.println(add);
        //减法
        add=bd.subtract(bd1);
        System.out.println(add);
        //乘法
        System.out.println(bd.multiply(bd1));
        //除法  divide(数据,精度,舍入方式)
        System.out.println(bd.divide(bd1,2,BigDecimal.ROUND_HALF_UP));
        System.out.println(bd.divide(bd1,2,BigDecimal.ROUND_FLOOR));
        System.out.println(bd.divide(bd1,2,BigDecimal.ROUND_HALF_DOWN));

        //BigInteger
        BigInteger b = new BigInteger("1000");
        BigInteger b1 = new BigInteger("202020");
        System.out.println(b.add(b1));
        System.out.println(b.subtract(b1));
        System.out.println(b.multiply(b1));
        System.out.println(b1.divide(b));
    }
}

10.异常

当程序没有按开发人员的意愿正常执行,中途出现错误导致程序中断,出现这种情况,就称为异常

10.1异常的产生

异常在程序中以对象的形式存在。当代码执行过程中出现异常,虚拟机会自动创建一个异常对象,如果没有对象该异常对象进行处理,就会导致程序中断,不再执行后续代码。

10.2异常的分类

华清远见-重庆中心-JAVA高级阶段知识点梳理_第5张图片

10.2.1Error错误

如果出现xxxxError,如StactOverFlowError,栈空间溢出,无法通过额外的代码解决,只能修改源码。

10.2.2Exception异常

如果出现xxxxException,如NullPointerException,空指针异常,可以通过额外的代码去解决。

10.2.2.1运行时异常RuntimeException

如果一个异常类属于RuntimeExcption异常类的子类,称为运行时异常,可以通过编译,可以不 用处理,运行时可能抛出异常对象。

常见运行时异常 说明 出现的情景
NullPointerException 空指针异常 用空对象null调用属性或方法
ArrayIndexOutOfBoundsException 数组下标越界异常 使用数组时,下标超出范围
NumberFormatException 数字格式异常 使用包装类调用parse方法做转换时,无法 将参数转换。如String str="123abc";int i=Integer.parseInt(str)
InputMismatchException 输入不匹 配异常 使用Scanner接收控制台输入时,如果不 满足接收的类型。如int i = sc.nextInt(), 实际输入a
ClassCastException 对象 转型 异常 Person p = (Person)Object obj;
ArithmeticException 算术 运算 异常 0当分母

10.2.2.2编译时异常

 如果一个异常类属于Exception异常类的子类,称为编译时异常,无法通过编译,必须处理异常后 才能编译运行。

常见编译时异常 说明 出现的场景
SQLException 数据库SQL相关异常 操作数据库时
IOException 输入输出流异常 使用流对象时
FileNotFoundException 文件未找到异常 方法的参数为文件时

10.3处理异常

通常所说的处理异常,是指处理Exception类的子类异常。

处理异常的目的,就是保证程序正常执行。

10.3.1try-catch-finally语句

这种方式处理异常,无论会不会抛出异常,都能让程序正常执行。

try{
//可能出现异常的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
//无论程序是否会抛出异常,都要执行的代码
}

华清远见-重庆中心-JAVA高级阶段知识点梳理_第6张图片

 try-catch-finally使用时注意:

1.try、catch、finally都不能单独使用,try需要配合catch或finally或catch和finally一起使用

2.执行try中的内容时,当某行代码抛出异常,不再执行try中该行代码后续的内容

3.无论try中的代码是否会抛出异常,finally中的代码一定会执行

4.如果代码会抛出多个异常,可以使用多个catch进行捕获,需要将异常子类放在最前,异常父类放在最后

5.在try中定义的内容,无法在try之外的地方使用

6.try中如果有return,不影响finally的执行,finally优先于return执行

package seDay5;
//try  catch  finally
//finally{代码} :有没有异常最终都要执行的代码
//在finally{代码}之前的return不能阻止finally的运行
//在finally{代码}之前的 System.exit(0);能阻止finally的运行
public class ExceptionDemo4 {
    public static void main(String[] args) {
        try {
            int k=0;
            int m=10/5;
//            System.exit(0);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }finally {
            System.out.println("结束了");
        }
        //笔试题
        int a=data();
        System.out.println(a);//12
    }

    public static int data(){
        int a=10;
        try {
            int k=1;
            int m=a/k;
            a++;
            return a;
        }catch (Exception e){
            a++;
            return a;
        }finally {
            a++;
            return a;
        }
    }
}

10.3.2final、finally、finalize的区别:

1.final是一个修饰符,被final修饰的属性称为常量,方法不能被重写,类不能被继承

2.finally是try-catch-finally结构中的关键字,是异常处理的出口,在无论是否抛出异常,都会执行的代码块

3.finalize是Object类中的方法,finalize()在某个对象被回收前调用的方法

10.3.3throws关键字

1.这种方式,可以让编译时异常通过编译

2.在定义方法的时候,通过该关键字声明可能抛出的异常

3.在调用方法时,如果方法抛出了异常,就需要捕获异常,或者继续抛出异常

4.用法:方法的参数部分之后,添加"throws 异常类型1,异常类型2..."

public class Test{
      public void fun() throws InterruptException{
      //这时该方法就会有一个声明:该方法可能会抛出异常

      //这句话直接写完后,会报错,因为sleep()方法可能会抛出InterruptException异常,属于编译时异常,必须要处理
         Thread.sleep(500);
     }
}

10.3.4throw和throws

1.throws:

throws表示用于声明方法有可能出现的异常。使用时写在方法的小括号之后

2.throw:

throw用于手动抛出异常对象。使用时,写在方法体中,常用于满足某种情况时,强制中断程序 用法:throw 异常对象;

package seDay5;

//throw:抛,一次只能抛一个异常,用在方法内部  throw new xxException();
//throws:抛,用在方法声明上,支持一个方法抛出多个异常  public void 方法名() throws 异常类型1,异常类型2{}
public class ExceptionDemo3 {
    public static void main(String[] args) throws Exception {
//        try {
//            int k=0;
//            int m=10/k;
//        }catch (ArithmeticException e){
//            throw e;
//        }
        age(-1);
        
    }

    //定义一个方法,判断用户的年龄,如果用户的年龄大于120,小于0,抛出异常
    //方法1:使用try catch
    //方法2:在方法内部使用throw抛出异常,在方法声明上使用throws抛出异常
    //RuntimeException:运行时异常,在调用方法时不会提醒捕获异常,只有在运行时才会捕获
    public static void age(int age) throws Exception {
        if (age > 120 || age < 0) {
            throw new Exception("年龄必须在0~120之间");
        } else {
            System.out.println(age);
        }

        try {
            int k = 0;
            int m = 10 / k;
        } catch (ArithmeticException e) {
            throw e;
        }
    }
}

10.3.5自定义异常

如果需要在某种情况下中断程序, 可以自定义一个异常类,再通过throw关键字手动抛出。

自定义异常步骤:

1.定义一个类,继承某个异常类

     如果继承的是RuntimeException,表示自定义的异常类属于运行时异常,该异常对象可以不用处理

    如果继承的是非RuntimeException,表示自定义的异常类属于编译时异常,该异常对象必须要处理

2.可选操作。定义带参构造方法,参数为异常信息,调用父类中的构造方法


package seDay5;
//类继承了Exception  说明这个类是Exception类型
public class GenderException extends Exception{
    //定义构造函数

    //重写方法
    @Override
    public String getMessage() {
        return "性别错误,只能是男生或者女生";
    }

    @Override
    public void printStackTrace() {
        super.printStackTrace();//调用父类的方法
    }
}

11.集合

11.1集合的特点

1.能保存一组数据,可以有序可以无序

2.集合的容量可变

3.集合中可以保存不同类型的数据

4.可以获取集合中保存的元素实际数量

11.2集合框架(集合家族)

Collection还有父接口Iterable,但Iterable接口不算严格意义上的集合的根接口。它称为迭代器,是用 于遍历集合元素的一个工具接口。

所以集合的根接口为Collection接口和Map接口,位于java.util包中。

华清远见-重庆中心-JAVA高级阶段知识点梳理_第7张图片

12Collection接口

该接口有两个核心子接口:List和Set。

这两个接口都可以保存一组元素,List接口保存元素时,是有序可重复的;Set接口保存元素时,是无序不重复的。

常用方法 返回值 作用
add(Object obj) boolean 将元素添加到集合中
size() int 获取集合中元素的数量
isEmpty() boolean 判断集合是否为空
clear() void 清空集合
contains(Object obj) boolean 判断集合中是否存在指定元素
toArray() Object[ ] 将集合转换为数组
remove(Object obj) boolean 移除集合中指定元素
iterator() Iterator 获取集合的迭代器对象,用于遍历集合
package seDay3;
//Collection:集合,是一个接口,定义了集合操作的通用方法

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

public class CollectionDemo {
    public static void main(String[] args) {
        //创建对象
        Collection c = new ArrayList();//没有限定集合的元素数据类型
        System.out.println(c.size());//长度为0
        System.out.println(c.isEmpty());//true 集合为空
        //添加元素
        c.add(new String("hello"));
        c.add(100);
        c.add(3.5);
        c.add(new Date());
        c.add(new Boolean("true"));
        System.out.println(c.size());//长度为5

        //其他方法
        String str1=new String("hello");
        boolean b=c.contains(str1);
        //true 集合c中包含了str1;集合中判断是否包含,是以equals的结果为准
        c.addAll(c);
        System.out.println(c.size());//10
        c.remove(3.5);//删除集合第一个元值为3.5
        //c.removeAll(c);//批量删除
        //c.clear();//清除集合全部元素
        System.out.println(c.size());//0

        //迭代器Iterator
        System.out.println("===================");
        Iterator iterator = c.iterator();
        while (iterator.hasNext()){//判断有没有下一个元素,有为true
            System.out.println(iterator.next());//获取下一个元素,返回元素的值

        }

    }
}

12.1List接口(有序可重复)

有序集合,元素可以重复,允许保存null,可以通过索引获取对应位置上的元素。

在该接口继承Collection接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删 除、获取指定索引的元素、截取子集合的方法等。

常用方法 返回值 作用
get(int index) Object 根据指定索引获取对应的元素
set(int index,Object obj) Object 使用obj替换index上的元素,返回被替换的元素
add(int index,Object obj) void 将obj添加到index上
remove(int index) Object 移除指定索引的元素
indexOf(Object obj) int 得到某元素第一次出现的索引,没有返回-1
lastIndexOf(Object obj) int 得到某元素最后一次出现的索引,没有返回-1
subList(int from,int to) List 截取[ from ,to)区间内的元素,返回子集合

12.1.1ArrayList实现类(掌握)

一.特点:

1.采用数组实现的集合

2.可以通过索引访问元素,可以改变集合大小。如果要在其中插入或删除元素时,会影响后续元素

3.该集合中保存的都是引用类型,即便保存了数组123,也保存的是Integer类型的123,而不是int类型的123

4.该集合查询效率高,中途增加和删除元素效率低

二、构造方法

常用构造方法 说明
ArrayList() 创建一个Object类型的空数组,在调用添加方法后,才会更改该数组大小为10
ArrayList(int initialCapacity) 创建一个指定容量的Object数组,如果参数为负,会抛IllegalArgumentException异常

三、常用方法

ArrayList中的常用方法,就是Collection接口和List接口中定义的方法,请参照上面。

package seDay3;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        System.out.println(list.size());//Collection中继承的方法
        System.out.println(list.isEmpty());

        //添加元素,是按顺序添加的
        list.add(new Student("1001","alice",20));
        list.add(new Student("1002","tom",30));
        list.add(new Student("1003","jack",19));
        list.add(new Student("1004","rose",25));

        //根据元素的位置找到元素 get(i)
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));//获取索引上的元素
        }

        //set(index,数据)  修改集合的元素
        list.set(1,new Student("1002","lilei",20));
        //add(index,数据)  在指定位置添加一个元素,原本的元素往后移
        list.add(1,new Student("1005","jerry",23));
        System.out.println(list);
        //remove(index)  删除指定位置的元素
        list.remove(0);
        System.out.println(list);
        //1005这个学生和1004交换位置
        Student s = list.get(0);
        list.set(0,list.get(list.size()-1));
        list.set(list.size()-1,s);
        System.out.println("改变之后:"+list);

        //使用迭代器遍历list
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

12.1.2LinkedList实现类

一、特点

1.采用双向链表实现的集合

2.集合中保存的每个元素也称为节点,除首尾节点外,其余节点都保存了自己的信息外,还保存了其 前一个和后一个节点的地址

3.如果在双向链表的数据结构中插入和删除操作节点时,不会影响其他节点的位置。如添加时新节点 时,只需要重写定义新节点的前后节点位置即可

3.如果要查询某个节点时,需要从头结点或尾结点开始一步步得到目标节点的位置

4.双向链表在中间插入和删除的效率高随机读取的效率低

华清远见-重庆中心-JAVA高级阶段知识点梳理_第8张图片

二、构造方法

常用构造方法 说明
LinkedList() 创建一个空链表

三、常用方法

由于LinkedList既实现了List接口,又实现了Deque接口,所以还有Deque接口中的一些方法

实现Deque接口的方法 说明
addFirst(Object obj) 添加头元素
addLast(Object obj) 添加尾元素
removeFirst() 移除头元素
removeLast() 移除尾元素
getFirst() 得到头元素
getLast() 得到尾元素
remove() 移除头元素
pop() 移除头元素
push(Object obj) 添加头元素
peek() 得到头元素
poll() 移除头元素
offer(Object obj) 添加尾元素

12.1.3ArrayList和LinkedList的区别

1.这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null

2.ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询

3.LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合

12.2Set接口(无序不重复)

12.2.1特点

1.无序集合,元素不可以重复,允许保存null,没有索引

2.Set接口中没有自己定义的方法,都是继承于Collection接口中的方法

12.2.2HashSet实现类

一、特点

1.采用哈希表实现

2.元素不能重复,无序保存,允许保存一个null

3.本质是一个HashMap对象

4.使用HashSet集合时,通常要重写实体类中的equals和hashcode方法

二、构造方法

常用构造方法 说明
HashSet() 创建一个空集合,实际是创建一个HashMap对象

三、常用方法

1.HashSet中没有属于自定义的方法,都是重写了父接口Set和Collection中的方法。这里参考Collection中 的方法即可。

2.没有与索引相关的方法

3.如果两个对象的hashCode相同,equals方法的比较结果可能为true也可能为false

package seDay4;

import java.util.HashSet;
/*
 * Set:无序不重复
 * List:有序可重复
 * */
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set set = new HashSet<>();
        //存储爱好
        set.add("吃饭");
        set.add("吃饭");//只会添加一个"吃饭"在集合中
        set.add("睡觉");
        set.add("打豆豆");
        set.add("打麻将");
        System.out.println(set);//[吃饭, 打豆豆, 睡觉, 打麻将]

        //添加20个不重复的100以内的整数
        Set slist = new HashSet<>();
        Random rd = new Random();
        while (slist.size() != 20) {
            slist.add(rd.nextInt(100));
        }
        System.out.println(slist);

        //随机产生1~36的六个整数
        slist.clear();
        while (slist.size()!=6){
            slist.add(rd.nextInt(36)+1);
        }
        Iterator iterator = slist.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+"\t");
        }

    }
}

12.2.3TreeSet实现类

一、特点

1.特殊的Set实现类,数据可以有序保存,可以重复,不能添加null

2.采用红黑树(自平衡二叉树)实现的集合

       2.1二叉树表示某个节点最多有两个子节点

       2.2某个节点右侧节点值都大于左侧节点值

       2.3红黑树会经过不停的"变色"、"旋转"达到二叉树的平衡

3.只能添加同一种类型的对象且该类实现了Comparable接口

      3.1实现Comparable接口后必须要重写compareTo()方法

      3.2每次调用添加add(Object obj)方法时,就会自动调用参数的compareTo()方法

4.compareTo()方法的返回值决定了能否添加新元素和新元素的位置

     4.1如果返回0,视为每次添加的是同一个元素

     4.2不能重复添加 如果返回正数,将新元素添加到现有元素之后

     4.3如果返回负数,将新元素添加到现有元素之前

5.添加的元素可以自动排序

二、构造方法

常用构造方法 说明
TreeSet() 创建一个空集合,实际是创建了一个TreeMap对象

三、常用方法

属于Set的实现类,所以能使用Collection和Set中的方法,除此之外,还有独有的方法

常用方法 作用
fisrt() 得到集合中的第一个元素
last() 得到集合中的最后一个元素
ceil(Object obj) 得到比指定元素obj大的元素中的最小元素
floor(Object obj) 得到比指定元素obj小的元素中的最大元素

13.Map接口

13.1特点

1.Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。

2.键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。

3.键和值都是引用类型。

13.2常用方法

常用方法 作用
size() 得到键值对的数量
clear() 清空所有键值对
put(Object key,Object value) 向集合中添加一组键值对
get(Object key) 在集合中根据键得到对应的值
remove(Object key)/remove(Object key,Object key) 根据键或键值对移除
keyset() 获取键的集合
values() 获取值的集合
containsKey(Object key) 判断是否存在某个键
containsValue(Object value) 判断是否存在某个值

13.3HashMap实现类

13.3.1构造方法

常用构造方法 说明
HashMap() 创建一个空的映射集合,默认大小为16,加载因子为0.75

13.3.2常用方法

常用方法参考Map中的方法

package seDay4;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        //存储数据  语文-80  数学-90  英语 65
        HashMap map = new HashMap<>();
        map.put("语文", 80);
        map.put("数学", 90);
        map.put("英语", 65);
        System.out.println(map);
        //是否包含
        System.out.println(map.containsKey("语文"));
        System.out.println(map.containsValue(80));

        //map.get(key) 根据key的值返回对应value值;找不到返回null
        System.out.println(map.get("语文"));

        //因为key已经存在,再添加同样的key,会把原来的value的值覆盖
        map.put("语文", 100);

        //remove() 删除key-value
        map.remove("语文");
        System.out.println(map.size());//获取键值对的数量

        //keySet() 获取键key的集合
        Set strings = map.keySet();
        System.out.println(strings);

        //values() 获取值value的集合
        Collection values = map.values();
        System.out.println(values);
    }
}

 13.3.3Map的遍历(for循环、迭代器)

package seDay4;

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

public class MapDemo1 {
    public static void main(String[] args) {
        HashMap map = new HashMap<>();
        map.put("语文", 80);
        map.put("数学", 90);
        map.put("英语", 65);

        //遍历
        //将map转为一个集合
        Set> entries = map.entrySet();
        //增强for循环遍历
        for (Map.Entry entry : entries) {
            //entry,一个键值对对应的数据
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        //迭代器遍历
        Iterator> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry entry = iterator.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }

    }
}

14Queue——队列

1.队列是常用的数据结构,可以将队列堪称是特殊的线性表,队列只能从一端添加元素(offer),另 一端取出元素(poll)

2.队列遵循先进先出的原则(FIFO, first in first out)

3.Queue是jdk中的接口, LinkedList是Queue的实现类

                                                Queue接口中的主要方法华清远见-重庆中心-JAVA高级阶段知识点梳理_第9张图片

 14.1Deque——双端队列

1.Deque是Queue的子接口, 被称为双端队列,即可以从队列的两端入队(offer),出队 (poll),LinkedList实现了该接口,可以模拟栈的存储方式

2.栈遵循先进后出的原则FILO(first int last out)

3.将Deque限定为为只能从一段出队和入队,就可以模拟栈的数据结构,栈数据结构,入栈为push, 出栈为pop

package seDay4;
import java.util.Deque;
import java.util.LinkedList;
//Deque  双关队列:可以从前面或者后面 进出
//栈:先进后出
public class DequeDemo {
    public static void main(String[] args) {
        Deque dq = new LinkedList<>();
        //模拟栈内存数据结构
        //入栈
        dq.push("A");
        dq.push("B");
        dq.push("C");
        dq.push("D");
        //查看队首
        System.out.println("最先出栈的:"+dq.peek());//D
        //出栈
        System.out.println(dq.pop());//D
        System.out.println(dq.pop());//C
        System.out.println(dq.pop());//B
        System.out.println("即将要出栈的:"+dq.peek());//A

        //入栈
        dq.push("E");
        dq.push("F");
        System.out.println("最先出栈的:"+dq.peek());//F
        System.out.println(dq.pop());//F
        System.out.println(dq.pop());//E
        System.out.println(dq.pop());//A

    }
}

15.Comparable接口 & 接口排序

15.1Comparable接口

1.针对对象数组或者集合中的元素进行排序的时候,首先需要确定元素的比较逻辑,制定比较的 比较规则

2.jdk中的Comparable接口 , 定义了对象间大小比较的方法, 需要大小比较的类,可以实现该 接口

15.2Comparable接口的实现

1.类 implements Comparable

2.重写Comparable接口中的compareTo方法

15.3Collections工具类

15.3.1介绍

1.Collections中提供了一些对集合操作的方法,其中比较常用的有对List的排序方法

2.如果要使用Collections.sort()方法进行对集合中的元素排序,那么要求集合中的元素是实现类

Comparable接口的

15.3.2常用方法

常用方法 说明
Collections.shuffle(List list) 打乱List集合中元素的顺序
Collections.sort(List list) 对List集合中的元素进行排序,元素必须实现 Comparable接口
Collections.swap(List list,int a,int b) 交换List集合中元素的索引
Collections.replaceAll(List list,Object oldObj,Object newObj) 替换List集合中的旧元素为新元素
Collections.reverse(List list) 将List集合中的元素反转
Collections.fill(List list , Object obj) 使用指定元素填充List集合
Collections.rotate(List list , int n) 将集合中最后n个元素放在最前
Collections.max(Collection col)/min(Collection col) 得到集合中的最大/最小值,集合中的元素必须 实现Comparable接口
package seDay4;

import seDay3.homework.Student;

import java.util.*;

//Collections操作集合的工具类
public class CollectionsDemo {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        Collections.sort(list);
        System.out.println(list);

        //给学生排序,按年龄
        List stuList = new ArrayList<>();
        stuList.add(new Student(1, "tom", 20));
        stuList.add(new Student(2, "jack", 23));
        stuList.add(new Student(3, "herry", 22));
        stuList.add(new Student(4, "rose", 18));
        stuList.add(new Student(5, "jerry", 19));
        Collections.sort(stuList);
        System.out.println(stuList);

        //按字符串的长度排序
        Collections.sort(list, new Comparator() {
            //通过匿名内部类重写compare方法
            @Override
            //指定规则
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        });
        System.out.println(list);
    }
}

16.遍历集合中元素的方式

16.1遍历List集合

16.1.1方式一:普通for循环

16.1.2方式二:增强for循环

16.1.3方式三:迭代器

package seDay3;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

//Iterator迭代器:支持遍历的时候删除集合中的元素
public class IteratorDemo {
    public static void main(String[] args) {
        List str = new ArrayList<>();
        str.add("tom");
        str.add("alice");
        str.add("jack");
        str.add("rose");
        /*迭代器
        Iterator iterator = str.iterator();
        while (iterator.hasNext()){
            if (iterator.next().equals("alice")){
                iterator.remove();//通过迭代器删除
            }
        }
        System.out.println(str);*/
        //增强for循环
        for (String s : str) {
            System.out.println(s);
        }
        //普通for循环 删除alice,将其它元素拼接一个“xx-”
        for (int i = 0; i < str.size(); i++) {
            if (str.get(i).equals("alice")){
                str.remove(i);
            }else {
                str.set(i,"xx-"+str.get(i));
            }
        }
        System.out.println(str);//[xx-tom, jack, xx-rose]
    }
}

16.2遍历Set集合

16.2.1方法一:增强for循环

16.2.2方式二:迭代器

17.泛型

一种规范,常用于限制集合中元素的类型,省去遍历元素时判断是否为对应类型和转型的过程

17.1用法

在定义集合遍历时,在类后面写上<引用数据类型>

集合类或接口  集合变量名  =  new  集合实现类();

List list = new ArrayList();
//当前集合只能保存String类型的元素

list.add("sdfsdf");
//list.add(123);//无法添加


List list2 = new ArrayList();
list2.add(123);


18.集合和数组之间的转换

18.1集合转换为数组

集合转换为数组:使用Collection接口中的toArray()方法

//Object[] obj = 集合对象.toArray();
List list = new ArrayList();
list.add(123);
list.add(63);
list.add(3);

Integer[] nums =(Integer[]) list.toArray();

18.2数组转换为集合

//一个数组对象
int[] nums ={11,2,66,3,6,21};

//定义集合对象
List list = new ArrayList();

//遍历数组的同时添加到集合中
for(int i:nums){
   list.add(i);
}

18.3一组数据转换为集合

一组数据转换为集合:使用Arrays工具类中的asList(一组数据)方法

//通常将数组中的数据直接作为参数
List strings = Arrays.asList("XX", "aa", "qq", "xx");

19.文件类File

1.java.io.File 用于表示文件 ( 目录 ) ,程序员可以通过 File 类在程序中操作硬盘上的文件或目录。
2.File 类只用于表示文件 ( 目录 ) 的信息 ( 大小,名称等 ) ,不能对文件内容进行访问

19.1构造方法

常用构造方法 说明
File(String pathName) 根据文件的完整路径创建File对象
File(String parent,String child) 根据文件的父目录路径和自身路径创建File对象
File(File parent,String child) 根据文件的父目录路径和自身路径创建File对象

19.2常用方法

常用方法 说明
exists() 判断文件是否存在
isFile() 判断是否为文件
isDirectory() 判断是否为目录
getName() 获取文件名
getPath() 获取文件相对路径
getAbsolutePath() 获取文件绝对路径
length() 获取文件所占字节
delete() 删除文件或空目录
mkdir() 创建目录
listFiles() 获取某个目录下的第一层子文件对象的数组
getParent() 获取父目录的名称
getParentFile() 获取父目录对象
lastModified() 获取最后一次修改时间对应的毫秒数
isHidden() 判断文件是否隐藏
renameTo(File newFile) 将原文件重命名且移动到指定目录
list() 获取某个目录下的第一层子文件的名称的数组
package seDay5;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;

// File:jdk提供的用于表示文件或目录的类型
public class FileDemo {
    public static void main(String[] args) throws IOException {
        //创建对象  new File(文件路径)
        File file = new File("C:\\Users\\Administrator\\Desktop\\test.txt");
        //true canExecute()文件可以被执行
        System.out.println(file.canExecute());
        //C:\Users\Administrator\Desktop\test.txt  获取文件的绝对路径
        System.out.println(file.getAbsoluteFile());
        //38 length()文件所占字节数
        System.out.println(file.length());
        //test.txt  getName()输出文件名
        System.out.println(file.getName());
        System.out.println(file.getParent());//C:\Users\Administrator\Desktop
        //获取文件的后缀名
        String[] split = file.getName().split("\\.");
        System.out.println(split[1]); //txt
        //isFile()判断是否为文件
        boolean b = file.isFile();
        if (b) {
            System.out.println("是文件");
        } else {
            System.out.println("是目录");
        }
        //exists()) 判断文件是否存在
        File f1 = new File("C:\\Users\\Administrator\\Desktop\\t.txt");
        if (f1.exists()) {
            System.out.println("存在");
        } else {
            //createNewFile()创建文件
            f1.createNewFile();
        }
        //在桌面创建一个文件夹abc,然后在abc里面创建一个def.txt的文件
        File f2 = new File("C:\\Users\\Administrator\\Desktop\\abc");
        if (!f2.exists()) {
            f2.mkdir();//创建文件夹
        }
        File file1 = new File("C:\\Users\\Administrator\\Desktop\\abc\\def.txt");
        if (!file1.exists()) {
            file1.createNewFile();//创建文件
        }


    }
}

19.3递归遍历文件夹

package seDay6;

import java.io.File;

public class FileDemo {
    public static void main(String[] args) {
        File f = new File("C:\\Users\\Administrator\\Desktop\\aa");
        seeFile(f);
    }
    //递归查看文件夹
    public static void seeFile(File file) {
        if (file.isDirectory()) {//判断是否是文件夹
            System.out.println(file.getAbsolutePath());//输出文件夹的路径
            File[] files = file.listFiles();//将文件夹下的第一层文件存到数组里
            for (File file1 : files) {//遍历文件数组
                seeFile(file1);//调用方法判断是否为文件夹
            }
        } else {
            System.out.println(file.getAbsolutePath());//输出文件的路径
        }
    }
}

20.IO流

流用于表示计算机硬盘与内存之间传输数据的通道。

内存中的数据存入到硬盘中,称为写write,也称为输出Output。

硬盘中的数据存入到内存中,称为读read,也称为输入Input。 

20.1流的分类

1.字节输入流InputStream:FileInpuStream、ObjectInputStream

2.字节输出流OutputStream:FileOutputStream、ObjectOutputStream

3.字符输入流Reader:FileReader、BufferedReader、OutputStreamWriter

4.字符输出流Writer:FileWriter、BufferedWriter、InputStreamReader

20.1.1按方向分

输入流:InputStream、Reader      将硬盘中的数据读取到内存中

输出流:OutputStream、Writer     将内存中的数据写入到硬盘中

20.1.2按类型分

字节流:InputStream、OutputStream    读写非文本类型文件。如图片、音视频、其他文件等

字符流:Reader、Writer                        读写纯文本类型文件。如txt、md等

20.2流的四个父类的特点

1.这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象

2.这四个父类中都定义了close()方法,用于关闭流对象,释放资源

3.输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数 据到硬盘中

4.输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中,在使用输出流对象时,一定要调用flush()或close()方法后,才能真正将数据写入到硬盘中

5.所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字 符流,数据以字符传输

6.读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件 可以不存在,但父目录必须存在

7.读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流

20.3FileInputStream文件字节输入流

按字节读取硬盘中的文件。

20.3.1构造方法

常用构造方法 说明
FileInputStream(String pathName) 根据文件名创建流对象
FileInputStream(File file) 根据文件对象创建流对象

20.3.2常用方法

常用方法 说明
read() 读取一个字节,返回读取到的字节
read(byte[ ] bytes) 按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组 中
close() 关闭流对象
package seDay6;
//FileInput:字节文件输入流,按字节读取
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputSreamDemo {
    public static void main(String[] args) {
        FileInputStream is = null;
        try {
            is = new FileInputStream("C:\\Users\\Administrator\\Desktop\\test.txt");
            int read = is.read();//读取到一个字节
            System.out.println(read);
            read = is.read();//读取到一个字节
            System.out.println(read);
            read = is.read();//读取到一个字节
            System.out.println(read);
            byte[] bs = new byte[3];
            int read1 = is.read(bs);
            System.out.println("read1:"+read1);
            System.out.println(new String(bs));
            byte[] bs1 = new byte[100];
            int read2 = is.read(bs1);
            System.out.println(new String(bs1));//将读取的字节数组转为字符串
            System.out.println(is.read());//-1 说明读取到文件末尾

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();//关闭流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

20.4FileOutputStream文件字节输出流

按字节将内存中的数据写入到硬盘中。

20.4.1构造方法

常用构造方法 说明
FileOutputStream(String pathname) 根据文件名创建输出流对象,写入时覆盖原内容
FileOutputStream(String pathname,boolean append) 根据文件名创建输出流对象,第二个参数为true,写 入时追加在原内容之后
FileOutputStream(File file) 根据文件对象创建输出流对象,写入时覆盖原内容
FileOutputStream(File file,boolean append) 根据文件对象创建输出流对象,第二个参数为true, 写入时追加在原内容之后

20.4.2常用方法

常用方法 作用
write(int i) 写入一个指定字节
write(byte[ ] bytes) 写入一个字节数组
write(byte[] bytes,int off,int len) 写入字节数组中从off开始的len个字节
flush() 将流中的数据冲刷到硬盘中
close() 关闭流对象
package seDay6;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建一个字节输出流,true,从文件的末尾写入
        FileOutputStream out = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test.txt",true);
        String str = "疑是地上霜。";
        out.write(str.getBytes());//将字符串转为字符数组并写到文件中
        out.write(str.getBytes(),0,6);//从字节数组的指定位置找,找指定长度,然后写入文件

        out.close();

        //读取文件中的所有内容
        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\t.txt");
        byte[] bytes = new byte[1024];
        int length = fis.read(bytes);
        while (length!=-1){
            fis.read(bytes,0,length);
            length = fis.read(bytes);

        }
        System.out.println(new String(bytes));
        fis.close();
    }
}

20.5使用FileInputStream和FileOutputStream 实现单文件的复制

import java.io.*;
public class CopyFile {
    public static void main(String[] args) throws IOException {
//定义原文件和目标文件
        File source = new File("F:\\221001\\录屏\\FileInputStream和 FileOutputStream.mp4");
                File target = new File("F:\\221001\\copy.mp4");
//定义文件字节输入流,用于读取原文件
        FileInputStream fis = new FileInputStream(source);
//定义文件字节输出流,用于写入文件
        FileOutputStream fos = new FileOutputStream(target);
/*
//调用无参的read()方法,表示读取一个字节,返回读取到的字节
int read = fis.read();
//如果能读取到内容
while (read > -1) {
//将读取到的内容写入到文件中
fos.write(read);
//继续读取
文件夹的复制
read = fis.read();
}
*/
//定义一个字节数组,大小为8MB
        byte[] bytes = new byte[1024 * 1024 * 8];
//按字节数组读取,返回读取到的字节数量
        int count = fis.read(bytes);
//循环读取写入
        while (count > -1) {
//将读取的字节数组写入到文件中
// fos.write(bytes);//如果调用该方法,最后一次会多写入上一次残留的数据
            fos.write(bytes,0,count);//如果调用该方法,实际读取到了多少字节就写入多少
            count = fis.read(bytes);
        }
        fis.close();
        fos.close();
        if (target.exists()) {
            System.out.println("复制成功");
        }
    }
}

文件夹的复制

import java.io.*;
public class CopyDirectory {
    public static void main(String[] args) {
/*File source = new File("F:\\221001\\录屏\\流的基本概念.mp4");
File target = new File("F:\\221001\\copy.mp4");
copyFile(source, target);*/
        File source = new File("F:\\221001\\笔记");
        File target = new File("F:\\221001\\笔记副本");
/*
* source F:\221001\笔记
* target F:\221001\笔记副本
* 1.调用copyDir方法,判断发现source是一个文件夹,创建目标文件夹
target:“F:\221001\笔记副本”
* 2.遍历source,如其中有xxx.md文件,即child
* 此时的source是F:\221001\笔记\xxx.md,即child
* 此时的target是F:\221001\笔记副本\xxx.md,用File(File parent,String child)
构造方法表示这个目标文件
* 所以创建File newTarget = new File(target,child.getName())
*
* */
        copyDir(source, target);
    }
    /*
     * 定义复制文件夹的方法
     * */
    public static void copyDir(File source, File target) {
        //如果是文件,调用单文件复制的方法
        if (source.isFile()) {
            copyFile(source, target);
        } else {//如果是文件夹
            //创建要复制的目标文件夹
            target.mkdir();
            //展开原文件夹
            for (File child : source.listFiles()) {
                //定义复制后的新目标文件
                //如source为F:\221001\笔记\day1.md时,递归调用的target为F:\221001\笔记副本\day1.md
                File newTarget = new File(target, child.getName());//这里使用File(File parent,String child)构造方法创建target对象
                //递归调用的原文件依然是当前遍历出来的子文件,目标文件就是最终复制的F:\221001\笔记副本\day1.md
                copyDir(child, newTarget);
            }
        }
    }
    /*
     * 定义单文件复制的方法
     * */
    public static void copyFile(File source, File target) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //创建用于输入输出的流对象
            fis = new FileInputStream(source);
            fos = new FileOutputStream(target);
            //定义字节数组
            byte[] bytes = new byte[1024 * 1024 * 8];
            //按数组读取
            int count = fis.read(bytes);
            while (count != -1) {
                fos.write(bytes, 0, count);
                count = fis.read(bytes);
            }
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在" + e);
        } catch (IOException e) {
            System.out.println("读写异常" + e);
        } finally {
            
            //按字符写入文件
            try {
                if (fis != null) {
                    fis.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                System.out.println("关闭流对象异常" + e);
            }
        }
    }
}

20.6BufferedInputStream & BufferedOutputStream

1.使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流进行创建的
2.BufferedInputStream & BufferedOutputStream 是过滤流

20.6.1BufferedInputStream输入流

package seDay6;

import java.io.*;

//BufferedInputStream带缓冲区的输入流,读取效率比FileInputStream效率高
public class BufferedInputStreamDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\Administrator\\Desktop\\java1\\视频\\Reader和Writer.mp4");
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bin = new BufferedInputStream(fis);//BufferedInputStream的参数是InputStream
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\测试.mp4"));
        byte[] bs = new byte[1024 * 1024];
        int len;
        while ((len=bin.read(bs))!=-1){
            fos.write(bs,0,len);
        }
        fis.close();
        fos.close();
    }
}

20.6.2BufferedOutputStream输出流

public class BufferedOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new
                FileOutputStream("C:\\Users\\Administrator\\Desktop\\abc.txt",true);
        BufferedOutputStream bos =new BufferedOutputStream(fos);
        String str = new String("dkldjkldjkldXXXXX");
        bos.write(str.getBytes()); // 写入缓冲区
        bos.flush(); // 刷新,把内容真的写入到文件中
        bos.close(); // ** 关闭的时候,会先把缓冲区的数据,写入到文件中,然后在关闭流。
        fos.close();
    }
}

20.7DataOutputStream & DataInputStream

1.DataOutputStream & DataInputStream 是对流功能的扩展,可以更方便的读取 int ,long ,char
类型的数据
2.DataOutputStream 对基本的输出流功能进行扩展,提供了基本数据类型的输出方法
3.DataInputStream 对基本的输入流功能的扩展,它提供了基本类型的输入方法
package seDay6;

import java.io.*;

public class DataOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\Administrator\\Desktop\\1.txt");
        FileInputStream fis = new FileInputStream(file);
        DataInputStream dis = new DataInputStream(fis);
        int read = dis.read();
        System.out.println("read"+read);
    }
}

16.6FileReader文件字符输入流

按字符读取文件。

16.6.1构造方法

常用构造方法 说明
FileReader(String fileName) 根据文件名创建文件字符输入流对象
FileReader(File file) 根据文件对象创建文件字符输入流对象

16.6.2常用方法

常用方法 作用
ready() 判断是否还有下一个字符
read() 读取下一个字符,返回读取到的字符
read(char[] chars) 按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组 中
close() 关闭流对象

16.7FileWriter文件字符输出流

按字符写入文件。

16.7.1构造方法

常用构造方法 作用
FileWriter(String fileName) 按文件名创建字符输出流对象,覆盖写入
FileWriter(String fileName,boolean append) 按文件名创建字符输出流对象,如果append为true, 表示追加写入
FileWriter(File file) 按文件对象创建字符输出流对象,覆盖写入
FileWriter(File file,boolean append) 按文件对象创建字符输出流对象,如果append为 true,表示追加写入

16.7.2常用方法

常用方法 作用
write(String str) 按字符串写入
flush() 将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真 正写入
close() 关闭流对象

16.8BufferedReader缓冲字符输入流

自带缓冲区(字符数组)的字符输入流。默认字符数组大小为8192,每次最多读取8192个字符。

在读取纯文本文件(txt或md)时,首选该类。

16.8.1构造方法

常用构造方法 作用
BufferedReader(Reader in) 创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象, 参数为Reader类型对象,Reader是抽象类,所以实际参数为 Reader的子类,如FileReader,在FileReader对象中定义要读取的 文件
BufferedReader(Reader in,int size) 创建一个指定缓冲区(字符数组)大小的字符输入流对象

16.8.2常用方法

常用方法 作用
ready() 判断是否还有字符
readLine() 读取整行字符
close() 关闭流对象

16.9BufferedWriter缓冲字符输出流

BufferedWriter缓冲字符输出流

16.9.1构造方法

常用构造方法 说明
BufferedWriter(Writer writer) 创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象, Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在 FileWriter中定义要将输入写入的目标文件
BufferedWriter(Writer writer,int size) 创建一个指定缓冲区大小的字符输出流对象

16.9.2常用方法

常用方法 作用
write(String str) 写入字符串
newLine() 换行
flush() 冲刷流中的数据到硬盘
close() 关闭流对象
package seDay6;

import java.io.*;
public class BufferReaderDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\abc.txt");
        InputStreamReader reader = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(reader);
        FileOutputStream fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\def.txt");
        OutputStreamWriter writer = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(writer);

        while (true){
            String s=br.readLine();//读取一行
            if (s==null){
               break;
            }
            bw.newLine();//换行
            bw.write(s);
            bw.flush();//刷新,写入文件
            System.out.println(s);
        }

    }
}

16.10ObjectOutputStream对象字节输出流(序列化)

16.10.1特点

1.序列化:将对象转换为文件的过程

2.被序列化的对象,必须要实现Serializable接口

3.transient关键字修饰的成员变量,不会被序列化

4.Serializable接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化

16.10.2构造方法

构造方法 说明
ObjectOutputStream(OutputStream os) 创建一个对象字节输出流对象,参数为一个字节输出 流对象,由于OutputStream是抽象类,所以使用其 子类,如FileOutputStream对象,在其中定义要写入 的文件

 16.10.3常用方法

常用方法 作用
writeObject(Object obj) 将一个对象写入到本地文件中
close() 关闭流对象

16.11ObjectInputStream对象字节输入流(反序列化)

反序列化:将文件转换为对象的过程

16.11.1构造方法

常用方法 作用
readObject() 读取序列化后的文件,返回类型为Object
close() 关闭流对象
package seDay6;

import java.io.*;

//把自定义的类型,序列化到文件中
public class ObjectInputStreamDemo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化
        FileOutputStream fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\学生.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Student student = new Student("tom", 20, "男");
        oos.writeObject(student);//写入对象

        oos.close();
        fos.close();

        //反序列化,找到student对象
        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\学生.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        if (o instanceof Student){
            Student stu= (Student)o;
            System.out.println(stu.getName()+stu.getSex()+stu.getAge());
        }
    }
}

16.12转换流

实际属于字符流,作用为将一个字节流对象转换为字符流对象

16.12.1OutputStreamWriter

将字节输出流转换为字符输出流;提供char流到字节,按照编码处理

16.12.2InputStreamReader

将字节输出流转换为字符输出流;完成byte流解析为char流,按照编码解析

16.12.3转换流的使用

如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。 使用字符流读写字符时比字节流更方便。

package seDay6;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

// ** OutputStreamWrite
public class OutputStreamWriteDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("C:\\Users\\Leiweigeng\\Desktop\\3.14.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        osw.write("大江东去,浪淘尽,千古风流人物。\n故垒西边,人道是,三国周郎赤壁。\n乱石穿空,惊涛拍岸,卷起千堆雪。\n江山如画,一时多少豪杰。\n" +
                "遥想公瑾当年,小乔初嫁了,雄姿英发。\n" +
                "羽扇纶巾,谈笑间,樯橹灰飞烟灭。\n" +
                "故国神游,多情应笑我,早生华发。\n" +
                "人生如梦,一尊还酹江月");
        osw.flush();
        osw.close();
        fos.close();
    }
}

17.线程

17.1继承线程

1.Thread类代表线程类型

2.任何线程对象都是 Thread ( 子类 ) 的实例
3.Thread 类是线程的模板(封装了复杂的线程开启等操作,封装了操作系统的差异性等)
4.只要重写 run 方法,就可以实现具体线程。
5.创建线程实例(即子类的对象 通过start 方法,启动线程,线程启动之后,会尽快执行 run 方法

package seDay7;

public class ThreadTest {
    public static void main(String[] args) {
        //一个人负责问1000次你吃了吗
        //另一个人回答1000次我吃了
        AskThread ask = new AskThread();
        ask.start();//启动线程
        AnswerThread answer = new AnswerThread();
        answer.start();


    }
}
class  AskThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            try {
                Thread.sleep(100);//每次循环等待100毫秒
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("你吃了吗");
        }
    }
}
class AnswerThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            try {
                Thread.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("我吃了");
        }
    }
}

17.2重写Runnable接口

1.创建一个类,实现Runnable接口,重写run方法

2.以实现了Runnable接口的类的实例,作为创建Thread类的参数

package seDay7;
//一个类的父类不是Thread,要想使用线程,需要实现Runnable接口,重写run方法
//然后通过new Thread(new 实现了Runnable接口的类)就可使线程
public class RunnableTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new B());
        thread.start();
    }
}
class A{

}
class B extends A implements Runnable{

    @Override
    public void run() {
        System.out.println("你吃了吗");
    }
}

17.3使用匿名内部类创建线程

package seDay7;

public class ThreadTest2 {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    try {
                        Thread.sleep(50);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println("正在选衣服:"+i);
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    try {
                        Thread.sleep(50);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println("正在试衣服:"+i);
                }
            }
        };
        t1.start();
        t2.start();
        t2.setPriority(10);//设置优先级  数值越大优先级越大
        t2.interrupt();//
    }
}

17.4线程的生命周期

华清远见-重庆中心-JAVA高级阶段知识点梳理_第10张图片

 17.5sleep方法

Thread.sleep(times) 使当前线程从 running 放弃处理器,进入 block 状态,休眠 times 毫秒,在进入
runnable 状态

17.6守护线程

守护线程是指,在线程运行前,将线程设置为守护线程,那么当程序中没有其他线程运行时候,
jvm 退出,程序就终止
package seDay7;

import javax.lang.model.element.VariableElement;

public class ThreadTest3 {
    public static void main(String[] args) {
        Thread t1=  new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    try {
                        sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("hello....."+i);
                }

            }
        };
        Thread t2=  new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    try {
                        sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("hi....."+i);
                }

            }
        };
        t1.start();
        t2.setDaemon(true);//设置t为守护线程,其他线程结束,t2也会结束
        t2.start();

    }
}

17.7线程的信息

package seDay7;

public class ThreadTest4 {
    public static void main(String[] args) {
        Thread t = Thread.currentThread();//获取当前线程
        System.out.println(t);//Thread[main,5,main]
        //线程id
        System.out.println(t.getId());//1
        //线程名
        System.out.println(t.getName());//main
        //线程的优先级
        System.out.println(t.getPriority());//5
        //线程状态
        System.out.println(t.getState());//RUNNABLE
        //看线程是否还活着
        System.out.println(t.isAlive());//true
        //是否为守护线程
        System.out.println(t.isDaemon());//false
    }
}

17.8线程同步

1.同步,就是指在调用某个功能的时候,在没有得到结果之前,该调用不返回,同时其他线程无
法使用这个功能。
2.异步: 并发,线程间互不影响,自己干自己的。
3.同步: 步调一致的处理,有序地执行。
4.多个线程并发读写同一个临界资源的时候,会发生 线程并发安全问题 ,使用同步代码块,解决并发安全问题
           synchronized 可以修饰方法,表示整个方法修的全部内容需要同步。
           synchronized (同步监视器) { // .... } ,同步监视器一般是一个对象。
package seDay7;

public class SynchronizedDemo {
    public static void main(String[] args) {
        SynchronizedDemo s = new SynchronizedDemo();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
              s.add("小红");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                s.add("tom");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                s.add("rose");
            }
        });
        t1.start();
        t2.start();
        t3.start();

    }
    public synchronized void add(String name){
        System.out.println("hello:"+name);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void add1(){
        System.out.println("hello");
        synchronized (this){
            for (int i = 0; i < 100; i++) {
                System.out.println(i+"--------------");
            }
        }
    }
}

 17.9单例模式

package seDay7;

public class SynchronizedDemo1 {
    public static void main(String[] args) {
        SingleA a1 = SingleA.getInstance();
        SingleA a2 = SingleA.getInstance();
        System.out.println(a1==a2);

        SingleB sb1 = SingleB.getInstance();
        SingleB sb2 = SingleB.getInstance();
        System.out.println(sb1==sb2);
    }
}
//单例模式:指一个类只能有一个实例
class SingleA{
    private static SingleA sa=null;
    //①私有化构造函数,避免程序员自己创建对象
    private SingleA() {
    }

    //②提供一个公开的方法,只能返回一个实例
    //synchronized:同一时间只能被一个线程调用到
    public static synchronized SingleA getInstance(){
       if (sa==null){
           sa=new SingleA();
       }
       return sa;
    }
}
//单例模式
class SingleB{
    private static SingleB sb=new SingleB();
    private SingleB() {
    }
    public static SingleB getInstance(){
        return sb;
    }
}

18. socket编程

1.在C/S 模式下,客户向服务器端发出请求,服务器端接收到请求之后,提供相应的服务。
2.客户端部分: 每个用户都有自己的客户端,负责发送请求。
3.服务端部分: 多个用户共享一个服务器,处理每个客户端的请求。

服务器端

package seDay7;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/*服务端程序:
        等待客户端来连接
        一定要先启动服务器,然后再启动客户端
*/
public class Server {
    //运行在服务器的socket
    private ServerSocket server;

    //构造方法,初始化server变量
    public Server() {
        System.out.println("开始初始化");
        try {
            server=new ServerSocket(9999);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("初始化成功");
    }

    //启动服务器
    public void  start(){
        while (true){
            System.out.println("等待客户端连接");
            try {
                Socket socket=server.accept();//阻塞方法
                InetAddress inetAddress = socket.getInetAddress();
                String ip=inetAddress.getHostAddress();//客户端的ip
                int port = socket.getPort();//端口号
                System.out.println(ip+":"+port+"连接成功......");

                //流的使用
                InputStream inputStream = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(inputStream);
                BufferedReader br = new BufferedReader(isr);
                String word = br.readLine();
                br.close();
                System.out.println(ip+":"+port+"说:"+word);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
}

客户端

package seDay7;

import sun.misc.OSEnvironment;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    private Socket socket;

    //如果对象创建成功,说明连接到服务器了,服务器会给客户端分配一个端口号
    public Client() {
        System.out.println("开始连接服务器");
        try {
            //localhost:代表的是自己的电脑
            socket = new Socket("localhost", 9999);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("连接成功");
    }

    //启动客户端
    public void start() {
        try {
            OutputStream os = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(os);
            PrintWriter pw = new PrintWriter(osw);
            String s = new Scanner(System.in).nextLine();
            pw.println(s);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        Client c = new Client();
        c.start();
    }
}

19.总结

Java高级阶段我学起来感觉方法太多了,记住的话有点难度,但是我觉着只要认识单词就差不多了,那些方法名跟它的中文意思差不多了多少,就是方法的重载(一个方法有多种参数列表)让记住它的方法更难了;第二个就是文件io流,一开始我学着感觉还好,学几个流之后我就感觉有点晕了,还得好好去理解一下。

你可能感兴趣的:(java-ee)