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.Object类中的toString方法,用于返回对象成员变量的字符串。类名+@+16进制整数
2.通常会重写toString方法,返回更有意义的字符串
1.Object类中的equals方法,用于判断对象是否相等,也就是引用地址是否相等
2.重写equals方法后,比较的是值是否相等
注意:
1.在使用字符串时,如果要比较其值是否相同,不要使用==判断,因为==判断的是内存地址;所以在比较字符串是否相同时,要使用String类重写的equals方法进行判断。
2.equals的原理:将两个字符串用字符数组保存,逐个判断字符数组中的每个字符,全部一致 时返回true;在使用equals方法时,通常将已知的非空字符串作为调用者,避免空指针异常。
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 +
'}';
}
}
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
}
}
如果频繁地将一个String类型变量的值进行更改时,会创建很多字符串对象。效率 低,浪费内存空间。所以在频繁更改字符串时,不要使用String类变量。如果要频繁更改字符串,使用StringBuilde类或StringBuffer类
String str = " abc ";
常用构造方法 | 说明 |
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方法时,通常将已知的非空字符串作为调用者,避免空指针异常。
方法名 | 返回值 | 作用 |
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在最前补充空格 |
1.正则表达式是一个特殊的字符串,是由一些特定的字符串组成的“规则字符串”
2.正则表达式,主要用于对字符串进行匹配,查找,替换等操作
3.正则表达式的规则
可以出现的字符
可以出现的字符简写
字符出现的次数
其他规定
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("你妈|你妹", "****"));
}
}
用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。
用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用。
StringBuilder和StringBuffer中的方法都一致,只不过StringBuffer中的方法使用了synchoronized关键字修饰,表示是一个同步方法,在多线程环境下不会出现问题。
常用构造方法 | 作用 |
StringBuilder | 创建一个大小为16的字符串数组,表示一个空白字符。类似于String str=" "; |
StringBuilder(String str) | 创建一个str长度+16的字符数组后,将str添加到其中。类似于String str="初始值"; |
常用方法 | 作用 |
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判断
String str="hello";
//通过构造方法将String"包装"为可变字符串对象
StringBuilder sb = new StringBuilder(str);
方法一: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 = " ";
一、相同点:
1.这三个类都可以表示字符串。都提供了一些操作字符串的方法。
2.这三个类中有相同的方法,如charAt()、indexOf()等
3.这三个类都是被final修饰的类,不能被继承
二、不同点:
1.String定义的字符串是一个常量。可变字符串定义的字符串是一个变量
2.String类中的方法,调用后,不会改变原本字符串的值;可变字符串类中的方法,调用后,会改变原本字符串的值
3.StringBuilder是非线程安全的可变字符串类,StringBuffer是线程安全的可变字符串类,其中的方 法被synchronized修饰
注意:
在频繁操作同一个字符串时,一定要使用可变字符串StringBuidler或StringBuffer类的对象,不能使用 String类的对象。
用于表示日期时间的类,位于java.util包下
常用构造方法 | 说明 |
Date() | 创建当前瞬间对应的日期对象 |
Date(long l) | 创建指定瞬间对应的日期对象 |
Date(int year,int month,int day) | 该方法已经过时,创建指定年月日的日期对象(年是1970年起经过的年数,月用0-11表示表示1到10月) |
常用方法 | 作用 |
getTime() | 得到对应Date对象表示的毫秒数 |
setTime(long l) | 设置Date对象的毫秒数 |
after(Date when) | 判断调用日期对象是否在when之后 |
before(Date when) | 判断调用日期对象是否在when之前 |
常用构造方法 | 作用 |
SimpleDateFormat(String pattern) | 创建一个指日期模板的格式化日期对象 |
特殊字符 | 作用 |
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 星期六 |
常用方法 | 返回值 | 作用 |
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);
}
}
1.表示日历的类,包含了很多日历相关的信息。
2.是一个抽象类,无法创建对象,可以通过静态方法getInstance()获取该类的一个实例。
在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 | 本年第几周 |
常用方法 | 作用 |
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);
}
}
包装类就是原始类型对应的类的引用类型,包装类通常用于字符串与原始类型之间的转换。
在web应用中,从浏览器页面中获取到后台的数据,全部都是String类型,所以一定要使用转换为原始类型的方法。
包装类 | 原始类型 |
Byte | byte |
Short | short |
Integer | int |
Long | long |
Float | float |
Double | double |
Character | char |
Boolean | boolean |
1.八个原始类型中,除了int和char,其余类型的包装类,都是将首字母改为大写。int对应 Integer,char对应Character
2.包装类都是被final修饰的,不能被继承
3.除了Character类,其余包装类都有两个构造方法:参数为原始类型或String的构造方法。 Character的构造方法只有一个,参数为char类型。这些构造方法用于将原始类型或字符串转换为 包装类对象
4.除了Character类,其余类都有静态方法parse原始类型(String str),用于将字符串转换为相应的 原始类型
5.除了Boolean类,其余包装类都有MAX_VALUE和MIN_VALUE这两个静态属性,用于获取对应类 型支持的最大最小值
6.所有包装类都重写了toString()方法,用于将包装类对象转换为String对象
使用原始类型对应的包装类,调用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
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);
所有包装类都有一个静态方法valueOf(原始类型),将某个原始类型的数据转换为相应的包装类对 象。
//手动装箱
int i = 123;
//定义原始类型数据
Integer integer = Interger.valueOf(i);
//调用包装类Integer的静态方法valueOf()将原始类型转换为包装类对象
所有包装类都有一个原始类型Value()方法,用于将包装类对象转换为原始类型。这个过程称为拆 箱unboxing。
//手动拆箱
Integer integer = new Integer(123);
//创建一个包装类对象
int i = integer.intValue();
//调用包装类对象的intValue()方法将包装类对象转换为原始类型
在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方法
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方法
1.java中的浮点数类型(float , double)在运算时会有舍入误差,如果希望得到精确的运算结果,可以 使用java.math.BigDecimal类
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));
}
}
当程序没有按开发人员的意愿正常执行,中途出现错误导致程序中断,出现这种情况,就称为异常
异常在程序中以对象的形式存在。当代码执行过程中出现异常,虚拟机会自动创建一个异常对象,如果没有对象该异常对象进行处理,就会导致程序中断,不再执行后续代码。
如果出现xxxxError,如StactOverFlowError,栈空间溢出,无法通过额外的代码解决,只能修改源码。
如果出现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 | 文件未找到异常 | 方法的参数为文件时 |
通常所说的处理异常,是指处理Exception类的子类异常。
处理异常的目的,就是保证程序正常执行。
这种方式处理异常,无论会不会抛出异常,都能让程序正常执行。
try{
//可能出现异常的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
//无论程序是否会抛出异常,都要执行的代码
}
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;
}
}
}
1.final是一个修饰符,被final修饰的属性称为常量,方法不能被重写,类不能被继承
2.finally是try-catch-finally结构中的关键字,是异常处理的出口,在无论是否抛出异常,都会执行的代码块
3.finalize是Object类中的方法,finalize()在某个对象被回收前调用的方法
1.这种方式,可以让编译时异常通过编译
2.在定义方法的时候,通过该关键字声明可能抛出的异常
3.在调用方法时,如果方法抛出了异常,就需要捕获异常,或者继续抛出异常
4.用法:方法的参数部分之后,添加"throws 异常类型1,异常类型2..."
public class Test{
public void fun() throws InterruptException{
//这时该方法就会有一个声明:该方法可能会抛出异常
//这句话直接写完后,会报错,因为sleep()方法可能会抛出InterruptException异常,属于编译时异常,必须要处理
Thread.sleep(500);
}
}
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;
}
}
}
如果需要在某种情况下中断程序, 可以自定义一个异常类,再通过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();//调用父类的方法
}
}
1.能保存一组数据,可以有序可以无序
2.集合的容量可变
3.集合中可以保存不同类型的数据
4.可以获取集合中保存的元素实际数量
Collection还有父接口Iterable,但Iterable接口不算严格意义上的集合的根接口。它称为迭代器,是用 于遍历集合元素的一个工具接口。
所以集合的根接口为Collection接口和Map接口,位于java.util包中。
该接口有两个核心子接口: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());//获取下一个元素,返回元素的值
}
}
}
有序集合,元素可以重复,允许保存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)区间内的元素,返回子集合 |
一.特点:
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());
}
}
}
一、特点
1.采用双向链表实现的集合
2.集合中保存的每个元素也称为节点,除首尾节点外,其余节点都保存了自己的信息外,还保存了其 前一个和后一个节点的地址
3.如果在双向链表的数据结构中插入和删除操作节点时,不会影响其他节点的位置。如添加时新节点 时,只需要重写定义新节点的前后节点位置即可
3.如果要查询某个节点时,需要从头结点或尾结点开始一步步得到目标节点的位置
4.双向链表在中间插入和删除的效率高,随机读取的效率低
二、构造方法
常用构造方法 | 说明 |
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) | 添加尾元素 |
1.这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null
2.ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询
3.LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合
1.无序集合,元素不可以重复,允许保存null,没有索引
2.Set接口中没有自己定义的方法,都是继承于Collection接口中的方法
一、特点
1.采用哈希表实现
2.元素不能重复,无序保存,允许保存一个null
3.本质是一个HashMap对象
4.使用HashSet集合时,通常要重写实体类中的equals和hashcode方法
二、构造方法
常用构造方法 | 说明 |
HashSet() | 创建一个空集合,实际是创建一个HashMap对象 |
三、常用方法
1.HashSet中没有属于自定义的方法,都是重写了父接口Set和Collection中的方法。这里参考Collection中 的方法即可。
2.没有与索引相关的方法。
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");
}
}
}
一、特点
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小的元素中的最大元素 |
1.Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。
2.键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。
3.键和值都是引用类型。
常用方法 | 作用 |
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) | 判断是否存在某个值 |
常用构造方法 | 说明 |
HashMap() | 创建一个空的映射集合,默认大小为16,加载因子为0.75 |
常用方法参考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);
}
}
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());
}
}
}
1.队列是常用的数据结构,可以将队列堪称是特殊的线性表,队列只能从一端添加元素(offer),另 一端取出元素(poll)
2.队列遵循先进先出的原则(FIFO, first in first out)
3.Queue是jdk中的接口, LinkedList是Queue的实现类
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
}
}
1.针对对象数组或者集合中的元素进行排序的时候,首先需要确定元素的比较逻辑,制定比较的 比较规则
2.jdk中的Comparable接口 , 定义了对象间大小比较的方法, 需要大小比较的类,可以实现该 接口
1.类 implements Comparable
2.重写Comparable接口中的compareTo方法
1.Collections中提供了一些对集合操作的方法,其中比较常用的有对List的排序方法
2.如果要使用Collections.sort()方法进行对集合中的元素排序,那么要求集合中的元素是实现类
Comparable接口的
常用方法 | 说明 |
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);
}
}
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]
}
}
一种规范,常用于限制集合中元素的类型,省去遍历元素时判断是否为对应类型和转型的过程
在定义集合遍历时,在类后面写上<引用数据类型>
集合类或接口 集合变量名 = new 集合实现类();
List list = new ArrayList();
//当前集合只能保存String类型的元素
list.add("sdfsdf");
//list.add(123);//无法添加
List list2 = new ArrayList();
list2.add(123);
集合转换为数组:使用Collection接口中的toArray()方法
//Object[] obj = 集合对象.toArray();
List list = new ArrayList();
list.add(123);
list.add(63);
list.add(3);
Integer[] nums =(Integer[]) list.toArray();
//一个数组对象
int[] nums ={11,2,66,3,6,21};
//定义集合对象
List list = new ArrayList();
//遍历数组的同时添加到集合中
for(int i:nums){
list.add(i);
}
一组数据转换为集合:使用Arrays工具类中的asList(一组数据)方法
//通常将数组中的数据直接作为参数
List strings = Arrays.asList("XX", "aa", "qq", "xx");
常用构造方法 | 说明 |
File(String pathName) | 根据文件的完整路径创建File对象 |
File(String parent,String child) | 根据文件的父目录路径和自身路径创建File对象 |
File(File parent,String child) | 根据文件的父目录路径和自身路径创建File对象 |
常用方法 | 说明 |
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();//创建文件
}
}
}
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());//输出文件的路径
}
}
}
流用于表示计算机硬盘与内存之间传输数据的通道。
将内存中的数据存入到硬盘中,称为写write,也称为输出Output。
将硬盘中的数据存入到内存中,称为读read,也称为输入Input。
1.字节输入流InputStream:FileInpuStream、ObjectInputStream
2.字节输出流OutputStream:FileOutputStream、ObjectOutputStream
3.字符输入流Reader:FileReader、BufferedReader、OutputStreamWriter
4.字符输出流Writer:FileWriter、BufferedWriter、InputStreamReader
输入流:InputStream、Reader 将硬盘中的数据读取到内存中
输出流:OutputStream、Writer 将内存中的数据写入到硬盘中
字节流:InputStream、OutputStream 读写非文本类型文件。如图片、音视频、其他文件等
字符流:Reader、Writer 读写纯文本类型文件。如txt、md等
1.这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
2.这四个父类中都定义了close()方法,用于关闭流对象,释放资源
3.输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数 据到硬盘中
4.输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中,在使用输出流对象时,一定要调用flush()或close()方法后,才能真正将数据写入到硬盘中
5.所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字 符流,数据以字符传输
6.读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件 可以不存在,但父目录必须存在
7.读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流
按字节读取硬盘中的文件。
常用构造方法 | 说明 |
FileInputStream(String pathName) | 根据文件名创建流对象 |
FileInputStream(File file) | 根据文件对象创建流对象 |
常用方法 | 说明 |
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();
}
}
}
}
按字节将内存中的数据写入到硬盘中。
常用构造方法 | 说明 |
FileOutputStream(String pathname) | 根据文件名创建输出流对象,写入时覆盖原内容 |
FileOutputStream(String pathname,boolean append) | 根据文件名创建输出流对象,第二个参数为true,写 入时追加在原内容之后 |
FileOutputStream(File file) | 根据文件对象创建输出流对象,写入时覆盖原内容 |
FileOutputStream(File file,boolean append) | 根据文件对象创建输出流对象,第二个参数为true, 写入时追加在原内容之后 |
常用方法 | 作用 |
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();
}
}
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);
}
}
}
}
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();
}
}
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();
}
}
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);
}
}
按字符读取文件。
常用构造方法 | 说明 |
FileReader(String fileName) | 根据文件名创建文件字符输入流对象 |
FileReader(File file) | 根据文件对象创建文件字符输入流对象 |
常用方法 | 作用 |
ready() | 判断是否还有下一个字符 |
read() | 读取下一个字符,返回读取到的字符 |
read(char[] chars) | 按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组 中 |
close() | 关闭流对象 |
按字符写入文件。
常用构造方法 | 作用 |
FileWriter(String fileName) | 按文件名创建字符输出流对象,覆盖写入 |
FileWriter(String fileName,boolean append) | 按文件名创建字符输出流对象,如果append为true, 表示追加写入 |
FileWriter(File file) | 按文件对象创建字符输出流对象,覆盖写入 |
FileWriter(File file,boolean append) | 按文件对象创建字符输出流对象,如果append为 true,表示追加写入 |
常用方法 | 作用 |
write(String str) | 按字符串写入 |
flush() | 将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真 正写入 |
close() | 关闭流对象 |
自带缓冲区(字符数组)的字符输入流。默认字符数组大小为8192,每次最多读取8192个字符。
在读取纯文本文件(txt或md)时,首选该类。
常用构造方法 | 作用 |
BufferedReader(Reader in) | 创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象, 参数为Reader类型对象,Reader是抽象类,所以实际参数为 Reader的子类,如FileReader,在FileReader对象中定义要读取的 文件 |
BufferedReader(Reader in,int size) | 创建一个指定缓冲区(字符数组)大小的字符输入流对象 |
常用方法 | 作用 |
ready() | 判断是否还有字符 |
readLine() | 读取整行字符 |
close() | 关闭流对象 |
BufferedWriter缓冲字符输出流
16.9.1构造方法
常用构造方法 | 说明 |
BufferedWriter(Writer writer) | 创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象, Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在 FileWriter中定义要将输入写入的目标文件 |
BufferedWriter(Writer writer,int size) | 创建一个指定缓冲区大小的字符输出流对象 |
常用方法 | 作用 |
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);
}
}
}
1.序列化:将对象转换为文件的过程
2.被序列化的对象,必须要实现Serializable接口
3.transient关键字修饰的成员变量,不会被序列化
4.Serializable接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化
构造方法 | 说明 |
ObjectOutputStream(OutputStream os) | 创建一个对象字节输出流对象,参数为一个字节输出 流对象,由于OutputStream是抽象类,所以使用其 子类,如FileOutputStream对象,在其中定义要写入 的文件 |
常用方法 | 作用 |
writeObject(Object obj) | 将一个对象写入到本地文件中 |
close() | 关闭流对象 |
反序列化:将文件转换为对象的过程
常用方法 | 作用 |
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());
}
}
}
实际属于字符流,作用为将一个字节流对象转换为字符流对象
将字节输出流转换为字符输出流;提供char流到字节,按照编码处理
将字节输出流转换为字符输出流;完成byte流解析为char流,按照编码解析
如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。 使用字符流读写字符时比字节流更方便。
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();
}
}
1.Thread类代表线程类型
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("我吃了");
}
}
}
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("你吃了吗");
}
}
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();//
}
}
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();
}
}
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
}
}
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+"--------------");
}
}
}
}
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;
}
}
服务器端
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流,一开始我学着感觉还好,学几个流之后我就感觉有点晕了,还得好好去理解一下。