目录:
1、day01-OOP部分知识点、JDK API、文档注释、String。
2、day02-String、StringBuilder、构造方法、日期操作
3、day03-Calendar、Object类、包装类、Number、正则表达式
4、day04-正则表达式、集合Collection、迭代器
5、day05- List集合、队列:Queue、双端队列:Deque、栈:Stack
6、day06-List、Set、Map
day01
1.OOP部分知识点
类和对象
对象的创建和使用
java内存管理
继承
- 重写
- 对象的造型
访问控制修饰符
封装
static final
引用类型数组
- 二维数组
抽象
接口
内部类
普通内部类
局部内部类
匿名内部类
多态
对象造型
向上造型
强制转型
u 向下造型
u 造型成相关的接口类型
关键字:instanceof
用来在强制转型前进行类型判断
注意点:
一个类中的非static成员变量和方法属于对象的
实例变量
实例方法
2.JDK API
JDK中包含大量的API类库,所谓API(Application Programming Interface,应用程序编程接口)就是一些已写好、可供直接调用的功能(在Java语言中,这些功能以类的形式封装)。
JDK API 包含的类库功能强大,经常使用的有:字符串操作、集合操作、文件操作、输入输出操作、网络操作、多线程等等。
JDK包结构:
JDK中经常使用的包有:
3.文档注释
以/**开头,以*/结尾
通常加在类和方法的上方,用于说明作者,时间,版本,要实现功能的详细描述等信息;
作用:描述类或方法的详细信息
用法:
1. 通过javadoc视图查看
2. 将整个项目的api文档导出
4.String
4.1 String是不可变的对象,本质是字符数组
4.2 String对象的创建 – 2种方式
1.new String("aa")
2.String str = "目标字符串";
通过给出字符串字面量的方式创建对象
字符串直接量保存在字符串常量池中
注意点:
java中为了提高对象的使用率,字符串常量池,用于保存字符串字面量,特点:如果要使用某个字符串字面量,先去字符串常量池中去找是否出现,如果出现,让引用直接指向此字面量对象
字符串常量池:从JDK1.7开始保存在堆中,在JDK1.7之前,是存在于方法区
字符串常量池中保存的是对象的引用
String str = new String("a");
String str1 = "a";
str==str1 ? false
String str = new String("a"),这句话中创建了几个String对象?// 2
String str = new String("a"),这句话中创建了几个对象?
//此问题有误,因为字符串也可以看做数组对象所以总共有几个对象就不确定了!
/*
* String对象是不可变对象
*/
// String str = "a";
// str = "b";
// String str = new String("a");
// String str1 = new String("a");
// boolean flag = str == str1;
// System.out.println(flag);
// String str = "a";
// String str1 = "a";
// System.out.println(str==str1);
String str = "hello";
String str1 = "World";
String str2 = "helloWorld";
//字符串字面量间的拼接会在编译期优化
String str3 = "hello"+"World";
String str4 = str+str1;
System.out.println(str3==str2);//true
System.out.println(str4==str2);//flase
练习:
class A{
public static void main(String[] args){
char[] chs = {'a','b','c'};
String str = "good";
A a = new A();
a.change(chs,str);
System.out.println(Arrays.toString(chs);
System.out.println(str);
}
public void change(char[] ch,String str){
ch[0] = 'g';
str = "ok";
}
}
4.3 常用方法:
---构造方法
---方法:
length()
indexOf()系列方法
indexOf(int ch) - int
indexOf(int ch,int fromIndex) - int
indexOf(String str) - int
indexOf(String str,int fromIndex) - int
lastIndexOf(String str) - int
u 找到子字符串在目标字符串中最后一次出现的位置
lastIndexOf(String str,int fromIndex)-int
从指定位置开始反向搜索指定子字符串第一次出现的位置
lastIndexOf(int ch) - int
lastIndexOf(int ch,int fromIndex) - int
public class StringIndexOfd {
public static void main(String[] args) {
String str = "helloworld";
/*
* indexOf(String subStr) - int
* 得到wo子字符串在str中第一次出现的位置
*/
// int index = str.indexOf("wo");
// System.out.println(index);
str = "hewollwollwoll";
/*
* 得到wo第二次出现的位置
* indexOf(String sub,int fromIndex) - int
* fromIndex:从此位置开始搜索
* 从指定位置开始搜索执行子串第一次出现的位置
*/
// int index = str.indexOf("wo",4);
// System.out.println(index);
/*
* lastIndexOf(String str) - int
* 找到子字符串在目标字符串中最后一次出现的位置
*/
// int index = str.lastIndexOf("wo");
// System.out.println(index);
/*
* lastIndexOf(String str,int fromIndex)- int
* 从指定位置开始反向搜索指定子字符串第一次出现的位置
*/
int index = str.lastIndexOf("wo", 5);
System.out.println(index);
}
}
如果在一个目标字符串中找一个并不存在的字符/字符串,调用indexOf系列方法返回-1
练习:统计一个子串在父串中出现的次数
String str = "headheadheadwo";统计子串"ad"出现的次数
/**
* 统计出目标字符串中子串出现的次数
* @author adminitartor
*
*/
public class IndexOfCountDemo {
public static void main(String[] args) {
String str = "headheadheheadwo";
// 统计 ad出现的次数
int count = 0; //计数
int fromIndex = 0;
String subStr = "ad";
int index; //子串出现的下标
while((index = str.indexOf(subStr, fromIndex))!=-1){
count++;
fromIndex = index + subStr.length();
}
System.out.println(count);
}
}
DAY02
1、内容回顾:
文档注释
常用类:
String:
1. String对象是不可变对象,本质是字符数组
2. 创建对象的2种方式
3. String的常用方法:
a) length()
b) indexOf()系列的方法
<1>indexOf(int ch) - int
<2>indexOf(int ch,int fromIndex) - int
<3>indexOf(String str) - int
<4>indexOf(String str,int fromIndex)-int
c) lastIndexOf系列方法
<1>lastIndexOf(int ch) - int
<2>lastIndexOf(int ch,int fromIndex) int
<3>lastIndexOf(String str) - int
<4>lastIndexOf(String str,int fromIndex) - int
2、String
substring:截取子串
-substring(int beginIndex) - String
-substring(int beginIndex,int endIndex) - String
public class SubstringDemo {
public static void main(String[] args) {
/*
* substring(int beginIndex) - String
* :从指定位置开始截取到字符串结尾的子串
*/
String str = "helloWorld";
String subStr = str.substring(2);
System.out.println(subStr);
/*
* substring(int beginIndex,int endIndex) - String
* :从指定位置开始截取,截取到指定位置结束
* 注意点:包头不包尾
*
*/
subStr = str.substring(2, 6);
System.out.println(subStr);
}
}
练习:
截取网址中的域名部分并打印
public class SubStringDemo01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入网址:");
String address = sc.nextLine();
/*
* 截取域名:
* 1.获取网址中的第一个.和第二个.的位置
*/
int beginIndex = address.indexOf(".")+1;
int endIndex = address.indexOf(".",beginIndex);
String str = address.substring(beginIndex, endIndex);
System.out.println(str);
sc.close();
}
}
trim()
charAt(int index) - char
练习:回文(对称字符串)判断
上海自来水来自海上
startsWith(String prefix) - boolean
endsWith(String suffix) - boolean
toUpperCase()
toLowerCase()
valueOf()
toCharArray()
equals()
两个String对象间用==
trim()
public class TrimDemo {
public static void main(String[] args) {
String str = " hello world ";
/*
*trim() - String
*得到字符串去掉首尾 空格后的新字符串
*/
System.out.println(str);
String subStr = str.trim();
System.out.println(subStr);
}
}
回文判断
/*
* 判断用户输入的字符串是否是回文
*/
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String dest = sc.nextLine();
check(dest);
sc.close();
}
public static void check(String dest){
int len = dest.length();
for(int i=0;i<len/2;i++){
char pre = dest.charAt(i);
char suf = dest.charAt(len-1-i);
if(pre!=suf){
System.out.println("不是回文!");
return;
}
}
System.out.println("是回文!");
}
startsWith-endsWith
/*
* startsWith(String prefix): - boolean
* 判断字符串是否以指定内容开头
*/
String str = "hello_world";
boolean flag = str.startsWith("el");
System.out.println(flag);
flag = str.endsWith("hello_world");
System.out.println(flag);
toUpperCase-toLowerCase
/*
* toUpperCase() - String
* 将字符串中的所有字符都转换为大写
*/
String str = "hello_World";
str = str.toUpperCase();
System.out.println(str);
/*
* toLowerCase() - String
* :将字符串中的所有字符都转换为小写
*/
str = str.toLowerCase();
System.out.println(str);
equals(String) - boolean
/*
* equals(Object) - boolean
* 判断两个String对象的内容值是否相等
*
*/
String str = new String("a");
String str1 = new String("a");
// str==str1 ? false
boolean flag = str.equals(str1);
System.out.println(flag);
static valueOf(int/float/double..) - String
public static void main(String[] args) {
/*
* static valueOf(基本数据类型/引用类型) - String
* :得到指定参数的字符串表示
*/
double d = 2.3;
//想将d变量的值作为字符串表示
String dStr = String.valueOf(d);
System.out.println(dStr);
}
思考:String s1 = "a",s2="b",s3="c"...
String dest = s1+s2+s3+s4+...;内存中会创建多少对象?
String str =s1+s2; //底层采用的就是StrinBuilder
String s4 = "ab"
String de = "a"+"b";
String de1 = s1 + s2;
3、StringBuilder
StringBuilder提供了一个可变的字符数组,所以字符串内容的修改都是在这个数组中进行,而不会每次修改都创建一个新对象.
使用:
1. 构造方法
2. 方法:
a) append(String str)
b) toString()
c) insert(int destOffSet,String str)
d) delete(int start,int end)
e) replace(int strat,int end,String str)
f) reverse()
练习:回文判断
append(String)
toString()
public class StringBuilderDemo01 {
public static void main(String[] args) {
/*
* StringBuilder(String str)
* 创建一个字符串生成器,初始值为给定的字符串内容
*/
String str = "abc",s1="a",s2="b",s3="c";
StringBuilder builder =
new StringBuilder(str);
System.out.println(builder);
//对生成器中的内容进行修改操作
/*
* 多个字符串的拼接
*append(String str) 的返回值其实返回的是this,
*即原来的StringBuilder对象
*/
StringBuilder builder1 = builder.append(s1).append(s2).append(s3);
System.out.println(builder);
System.out.println(builder==builder1);
String dest = builder.toString();
System.out.println(dest);
}
}
insert(int offset,String str)
/*
* insert(int offset,String str) - StringBuilder
* 向指定的位置插入指定的字符串,最近将修饰之后的当前对象
* 返回 - return this
* abcabc
* abchelloabc
*/
builder1 = builder1.insert(3,"hello");
System.out.println(builder1);
delete(int start,int end)
/*
* delete(int start,int end) - StringBuilder
* 边界值:包头不包尾
*/
builder1 = builder1.delete(3, 8);
System.out.println(builder1);
repalce(int start,int end,String str)
/*
* replace(int start,int end,String str) - StringBuilder
* :用指定的字符串替换掉原对象中从指定位置开始,到
* 指定位置结束之间的内容
*/
builder1 = builder1.replace(2, 5, "hello");
System.out.println(builder1);
reverse() - StringBuilder
/*
* reverse() - StringBuilder
* 对StringBuilder对象中的内容进行倒置
*/
builder1 = builder1.reverse();
System.out.println(builder1);
回文判断
/*
* 回文判断
*/
String destStr = "上海自来水来自海";
StringBuilder builder2 = new
StringBuilder(destStr);
String destStr1 = builder2.reverse().toString();
//比较destStr和destStr1的内容
if(destStr.equals(destStr1)){
System.out.println("是回文!");
}else{
System.out.println("不是回文!");
}
注意点:
<1>StringBuilder的很多方法的返回值均为StringBuilder类型。
这些方法的返回语句均为:return this。
<2>java的字符串连接的过程是利用StringBuilder实现的
<3>StringBuffer和StringBuilder,StringBuffer的使用API和StringBuilderde API是一样的。
<4>StringBuffer线程安全的,效率偏低,StringBuilder是非线程安全的,效率偏高
4、日期操作
4.1 Date:java.util
构造方法:
Date():创建一个Date对象,指向创建此对象的时间
Date(long mills):创建一个Date对象,指向给定long值表示的时间点
方法:
getTime() - long:
返回Date对象指向的时间距离历元的时间差的毫秒表示
setTime(long ) - void:
让Date对象指向给定毫秒数的时间点
getTime() - setTime(long mills)
public static void main(String[] args) {
/*
* Date():创建Date对象,指向创建此对象
* 的时间
*/
Date date = new Date();
System.out.println(date);
long mills = date.getTime();
System.out.println(mills);
/*
* 让Date对象指向昨天的此时此刻
*/
long yestoday = mills - 24*60*60*1000;
date.setTime(yestoday);
System.out.println(date);
4.2 SimpleDateFormat
用户在浏览器端注册操作:
出生日期:2018-01-29 12:12:12
服务器端接受到浏览器传递的数据:
java程序:String(格式)
将指定格式的String转换为Date
SimpleDateFormat(String pattern):
pattern:要和Date类型进行转换的String的格式
parse(String) - Date
format(Date) - String
String-->Date
/*
*用户从控制台输入一个指定格式的日期,程序
* 完成String - >Date的转换
*/
Scanner sc = new Scanner(System.in);
System.out.println("请输入出生日期:");
String birth = sc.nextLine();
//String -- >Date
SimpleDateFormat sdf = new
SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//String -->Date
Date birthDate = sdf.parse(birth);
System.out.println(birthDate);
sc.close();
}
format(Date) - String
/*
* 将Date对象的值转换得到String表示
* format(Date) - String
*/
String dest = sdf.format(birthDate);
System.out.println(dest);
sc.close();
练习:
从控制台输入你的出生日期,程序计算出你到今天为止活了多少天并打印输出。
-关键字:求时间差
/**
* 用户输入出生日期,计算存活天数
* @author adminitartor
*
*/
public class LifeDaysDemo {
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入出生日期:");
String birth = sc.nextLine();
SimpleDateFormat sdf = new
SimpleDateFormat("yyyy-MM-dd");
Date birthDate = sdf.parse(birth);
//Date指向当前日期
Date currentDate = new Date();
//求两个Date对象距离历元的时间char
long minus = currentDate.getTime() -
birthDate.getTime();
//将存活的时间值转换为天单位
long days = minus/1000/60/60/24;
System.out.println("恭喜你,已经活了"+days+"天");
sc.close();
}
}
作业:
1.有一个字符串:“abcdef我爱java”,需求:将字符串逆序输出。
2.用StringBuilder判断字符串是否是回文(对称字符串)
3.
String s = " abc abc Abc ";
System.out.println(s);
System.out.println(s.charAt(1));
System.out.println(s.charAt(2));
System.out.println(s.indexOf("bc"));
System.out.println(s.indexOf("bc",3));
System.out.println(s.lastIndexOf("bc"));
System.out.println(s.indexOf("xxx"));
System.out.println(s.substring(5));
System.out.println(s.substring(5, 10));
System.out.println(s.trim());
DAY03
1.内容回顾
1.String
2.StringBuilder
-构造方法
-方法:
3.日期操作
Date:
构造方法
Date()
Date(long mills)
方法:
getTime() - long
setTime(long mills)
SimpleDateFormat:
SimpleDateFormat(String pattern)
String -- >Date
parse(String) - Date
Date -->String
format(Date) - String
需求:创建一个日期对象指向当前时间,从此日期对象中获取时间的具体值(年,月份,日期,小时,分钟,秒数)
2.Calendar
Calendar对象的创建:
Calendar是一个抽象类,不能实例化的,创建的对象一定是其子类对象
子类:GregorianCalendar //阳历
创建对象方式一:
new GregorianCalendar();
创建对象方式二:
Calendar.getInstance() - Calendar
方法:
GET方法:
get(int Field) - int
- 获取到给定日历字段的值
日历字段:
MONTH:0-11
DAY_OF_WEEK:周几
日 一 二 三。。。。六
1 2 3 7
public static void main(String[] args) {
/*
* 创建Calendar对象,获取此对象表示的日期的
* 年的值,月,日,时,分,秒各个日历字段的值
* get(int field) - int
*/
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH)+1;
int date = calendar.get(Calendar.DATE);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
int week = calendar.get(Calendar.DAY_OF_WEEK);
System.out.println(year+"-"+month+"-"+date);
System.out.println(hour+":"+minute+":"+second);
System.out.println(week);
getTime() - Date:
得到Date对象表示此calendar对象指向的时间点。
getTimeInMills() - long:
获取此calendar对象表示的时间距离历元的时间差毫秒表示,等同于Date类中的getTime()。
getActualMaximum(int field):
通常是用来获取一个月中的最大天数
SET方法:set(int Field,int value)
练习:
获取任意一年的二月有多少天
public static void main(String[] args) {
System.out.println("请输入年份:");
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, 1);
calendar.set(Calendar.DATE, 1);
//获取二月中的最大天数
int max = calendar.getActualMaximum(Calendar.DATE);
System.out.println(max);
sc.close();
}
setTime(Date date)
public static void main(String[] args) throws ParseException {
/*
* 用户从控制台输入一个日期,在程序中获取
* 此日期对象的日历信息(年,月,日,周几...)
*/
System.out.println("请输入日期:");
Scanner sc = new Scanner(System.in);
String birth = sc.nextLine();
//2018-01-01
//将String表示的日期-->java中识别的日期对象
SimpleDateFormat sdf = new
SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(birth);
//获取此日期对象表示的周几
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int week = calendar.get(Calendar.DAY_OF_WEEK)-1;
System.out.println(week);
sc.close();
}
add(int field,int amount)
练习:
查看3年2个月零5天以后的那周的周一的日期
/*
* 查看3年2个月零5天以后的那周的周一的日期
*/
Calendar calendar = Calendar.
getInstance();
calendar.add(Calendar.YEAR, 3);
calendar.add(Calendar.MONTH, 2);
calendar.add(Calendar.DATE, 5);
Date date =calendar.getTime();
System.out.println(date);
calendar.set(Calendar.DAY_OF_WEEK, 2);
date =calendar.getTime();
System.out.println(date);
Calendar:
1. 创建对象
2. 方法
a) get系列方法
b) set系列方法
c) add方法
3.Object类
• 在Java类继承结构中,java.lang.Object类位于顶端;
• 如果定义一个Java类时没有使用extends关键字声明其父类,则其父类默认为 java.lang.Object 类;
• Object类型的引用变量可以指向任何类型对象。
方法:
1) toString():
System.out.print(任意对象),输出内容是? 为什么?
Object类中的重要方法,用于返回对象值的字符串表示: 类名@散列码
如果不重写toString方法,将使用Object的toString方法
强烈建议为自定义的每一个类增加toString方法,toString方法是非常有用的调试工具;
格式大多数遵循 “ 类的名字[ 值 ]“
Java 提供的API几乎都重写了 toString()
包括: String StringBuilder Date …..
public class Person {
private String name; //null
private int age;
private char gender;
public Person(String name, int age, char gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
public class ObjectDemo {
public static void main(String[] args) {
Person person = new Person("aa", 12, '男');
System.out.println(person);
}
}
2) equals()
在Object类中,这个方法判断两个对象是否具有相同的引用,即是否为相同的对象;
在实际应用中,一般需要重写该方法,通过比较对象的成员属性,使该方法更有意义 -- 建议重写
案例:Point类中重写此方法,当X,Y坐标相等时,说明两个点对象相等(是同一个点)
String类中的equals()方法
hashCode():
返回一个和地址相关的整数(十进制)
Object类中的toString()返回的字符串是:
类型@散列码(哈希码值)
4 基本数据类型的包装类
问题: int i = 4; 如何得到一个String类型的i的表示?
int -- >String
String str = 23; 是否可以将此字符转换为int类型得到int类型的表示?
JAVA 中8种基本类型都有一个与之对应的类,即包装类(wrapper)。
包装类是不可变类,在构造了包装类对象后,不允许更改包装在其中的值;
包装类是final的,不能定义他们的子类。
Number类
抽象类 Number 是 Byte、Double、Float、Integer、Long 和 Short 类的父类;
Number类中抽象方法在子类中的实现以及使用:
Integer类的常用方法:
1. static parseInt(String) – int
2. static toString(int a) – String
3. static valueOf(int i) – Integer
a) 得到一个Integer对象初始值为给定的变量i
4. intValue() - int
static parseInt(String)-int
static toString(int a) - String
public static void main(String[] args) {
/*
* 将一个字符串表示的数值转换为int类型并进行运算
*/
String str = "23";
int i = Integer.parseInt(str);
System.out.println(i+10);
/*
* 得到一个String对象表示一个int变量中的值
*/
int a = 3;
// Integer integer = new Integer(a);
// str = integer.toString();
// System.out.println(str);
str = Integer.toString(a);
System.out.println(str);
}
static valueOf(int) - Integer
intValue() - int
/*
* valueOf(int) - Integer
* 得到一个Integer对象初始值为给定的int
*/
int x = 34;
Integer inte = Integer.valueOf(x);
System.out.println(inte);
/*
* 返回一个int类型的值表示Integer对象中的数值
*/
Integer integer = new Integer(12);
Integer integer2 = new Integer(34);
int a1 = integer.intValue();
int a2 = integer2.intValue();
装箱:valueOf(int) - Integer完成装箱功能
拆箱:intValue() - int 完成拆箱功能
自动装箱和拆箱
从Java 5.0版本以后加入到了 autoboxing功能
自动“拆箱”和“装箱”是依靠编译器在编译期的“预处理”(优化)工作
public static void main(String[] args) {
int a=3,b=4;
/*
* jdk1.5开始,java新增自动装箱和自动拆箱功能
* 装箱:valueOf(int) - Integer
* 底层默认取调用valueOf(int) - Integer
*/
Integer i = a+b; //int 自动装箱
System.out.println(i);
/*
* 自动拆箱
*/
Integer m = 4,n=5;
Integer total = m+n; //先拆箱后装箱
}
}
5.正则表达式
<1>正则表达式是一串特定字符,组成一个“规则字符串”,这个“规则字符串”是描述文本规则的工具。正则表达式就是记录文本规则的代码。
<2>正则表达式就是一个字符串用于定义一个规则
字符集:
预定义字符集:
正则表达式中如果预定义字符中带有\
\转义字符 \\d
数量词:
可以利用数量词约定字符出现的次数
正则表达式
练习:
1. 手机号码的验证(1,3,4,5,7,8)
a) 13/5/7/8 9位
public class RegexDemo {
public static void main(String[] args) {
/*
* 验证用户输入的手机号是否格式正确
*/
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String phone = sc.nextLine();
//定义正则表达式
String regex = "1[3578]\\d{9}";
//匹配操作
if(phone.matches(regex)){
System.out.println("手机号码正确");
}else{
System.out.println("手机号码错误");
}
sc.close();
}
}
作业:
1. 校验QQ邮箱(5-11位数字@qq.com)
2. 验证用户输入的用户名(6-10位的字符和数字的组合,不能是纯字母,不能是纯数字)
DAY04
1.内容回顾
1. Calendar
2. Object类
a) toString()
b) equals()
c) hashCode()
3. 8种基本数据类型对应的包装类
4. Number
5. 正则表达式
2.正则表达式(下)
QQ邮箱的验证:5-11位数字@qq.com
public static void main(String[] args) {
System.out.println("请输入QQ邮箱:");
Scanner sc = new Scanner(System.in);
String mail = sc.nextLine();
//定义正则表达式
String regex = "[1-9]\\d{4,10}@qq\\.com";
if(mail.matches(regex)){
System.out.println("邮箱输入正确!");
}else{
System.out.println("邮箱输入错误!");
}
sc.close();
}
2.1 分组:():
() 圆括号表示分组,可以将一系列正则表达式看做一个 整体,
练习:
• 检索手机号码: +86/0086 13838389438
– +86/0086 可有可无
– +86/0086 与后面的号码之间空格可以没有或者有多个
– 电话号码为11位数字
public static void main(String[] args) {
System.out.println("请输入手机号码:");
Scanner sc = new Scanner(System.in);
String phone = sc.nextLine();
//定义正则表达式
String regex = "(\\+86|0086)?\\s*1[3578]\\d{9}";
if(phone.matches(regex)){
System.out.println("输入正确");
}else{
System.out.println("输入错误");
}
sc.close();
}
练习:
验证用户输入的日期是否正确
2018-01-31
yyyy - (()|()|())
月份:
大月:1 3 5 7 8 10 12 - 31
小月: 4 6 9 11 - 30
二月:29
/**
* 验证用户输入的日期是否正确
* @author adminitartor
*
*/
public class DateRegexDemo {
public static void main(String[] args) {
System.out.println("请输入日期:");
Scanner sc = new Scanner(System.in);
String date = sc.nextLine();
//定义日期的正则表达式
String regex = "[1-9]\\d{3}-"
+ "(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))"
+ "|((0[469]|11)-(0[1-9]|[12][0-9]|30))"
+ "|(02-(0[1-9]|[12][0-9])))";
/*
* 大月:(|)-( | | )
* (0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])
* 小月:(|)-( | |)
* (0[469]|11)-(0[1-9]|[12][0-9]|30)
* 二月:
* 02-(0[1-9]|[12][0-9])
*
*/
if(date.matches(regex)){
System.out.println("输入正确");
}else{
System.out.println("输入错误");
}
sc.close();
}
}
正则表达式中,有一些字符是具有特殊意义的字符,比如:?,*,+,.,() \ |,
如果想使用这些特殊字符的本意,需在前+ \\
2.2 边界匹配:
^ 匹配开始,$ 匹配结束
案例:匹配8-10个\w 两种写法的区别
String regex = \\w{8,10};
String regex1 = "^\\w{8,10}$"
//目标字符串中出现8-10位的单词字符,那么匹配
String str = "helloworld";
str和regex 匹配的
String str1 = "hello_world";
str1和regex是匹配的
str1和regex1是不匹配的
String中的matches方法自带边界匹配功能,所以如果是通过matches方法来匹配,那么正则表达式中可以不写边界匹配符
2.3.String正则API:
matches(String regex)
split(String regex)
案例:对一个字符串进行分割,分割符为,
String str = "tom,amy,linda,lily";
public static void main(String[] args) {
String str = "tom,amy,linda,lily";
/*
* 将各个人名分隔开并分别取出
*/
String[] strs = str.split(",");
System.out.println(Arrays.toString(strs));
}
练习:
对一个字符串进行分割,分割符为,加上多个空格
String str = "tom, amy, linda,lily ";
/*
* 对一个字符串进行分割,分割符为,+多个空格
*/
String str = "tom, amy, linda,lily";
String[] strs = str.split(",\\s*");
for(int i=0;i<strs.length;i++){
System.out.println(strs[i]);
}
replaceAll(String regex,String replacement)
regex:\\d+
案例:
1. 对一个字符串中的所有数字进行替换
a) String str = "hello12world345 98"
要求:将str中的所有出现的数字替换成"数字"
public static void main(String[] args) {
/*
* 将字符串中的所有数字替换成“数字”中文
*/
String str = "hello12world345 09";
str = str.replaceAll("\\d+", "数字");
System.out.println(str);
}
2. 敏感字符过滤
a) String str = "我去,这道题好难啊,我去去就来";
b) 将"我去" 用***替换
String str = "我去,这道题好难啊,我去去就来";
str = str.replaceAll("我去", "***");
System.out.println(str);
校验用户输入的用户名,由6-10位的字母和数字混合组成,不能是纯字母,也不能是纯数字。
public static void main(String[] args) {
System.out.println("请输入用户名:");
Scanner sc = new Scanner(System.in);
String username = sc.nextLine();
String regex = "\\d{6,10}";
String regex1 = "[a-zA-Z]{6,10}";
if(username.matches(regex)){
System.out.println("用户名不能是纯数字!");
return;
}
if(username.matches(regex1)){
System.out.println("用户名不能是纯字母!");
return;
}
String regex2 = "[a-zA-Z0-9]{6,10}";
if(username.matches(regex2)){
System.out.println("输入正确!");
}else{
System.out.println("输入错误!");
}
sc.close();
}
问题:
正则表达式中中文如何表示?
Unicode编码来表示中文
[\u4e00-\u9fa5]
public static void main(String[] args) {
/*
* 校验用户输入的名字是否是2-4位的中文
* 正则中表示中文:
* [\u4e00-\u9fa5]
*/
System.out.println("请输入姓名:");
Scanner sc = new Scanner(System.in);
String name = sc.nextLine();
String regex = "[\u4e00-\u9fa5]{2,4}";
if(name.matches(regex)){
System.out.println("输入正确");
}else{
System.out.println("输入错误");
}
sc.close();
}
正则表达式:
1. 字符集,数量词,预定义字符集
2. 分组:()
3. 边界匹配符
a) matches(String regex)自带边界匹配功能
4. String类中的正则API
a) split(String regex) - String[]
b) replaceAll(String regex,String replacement) - String
3.集合
需求1:用户注册产生的对象保存起来,用什么来保存?
用户注册(信息) -->创建一个User对象-->user
对象保存到数组中
注册无上限个用户对象,保存起来,此时数组满足不了我们的需求,此时可以使用集合(容器,可以保存数量不定的数据)来保存这些对象
需求2:具有映射关系的数据保存起来
语文 - 90
数学 - 80
英文 – 70
集合也可以保存具有映射关系的数据
3.1.Collection
,定义了集合相关的操作方法,其有两个子接口:
List:可重复集
Set:不可重复集
集合的操作:
add(Object obj): - boolean
Collection定义了一个add方法用于向集合中添加新元素。
该方法会将给定的元素添加进集合,若添加成功则返回true,否则返回false
集合中保存的元素一定是引用类型
注意点:
• 集合中存储的都是引用类型元素,并且集合只保存每个元素对象的引用,而并非将元素对象本身存入集合。
contains(Object obj) – boolean
该方法会用于判断给定的元素是否被包含在集合中。
判断方式:
根据每个元素的equals()方法进行比较后的结果。
通常有必要重写equals()保证contains()方法的合理性。
size():获取集合中的元素个数
clear():清空集合中的所有元素
isEmpty():判断集合是否为空(元素个数是否为0)
addAll(Collection):
将参数中给定的集合中的所有元素添加到本集合中。
containsAll(Collection):
判断参数的集合中的所有元素是否被全部包含在集合中。
注意点:判断元素是否包含采用的是元素所属类的equals()
add(Object) - boolean
public class AddDemo {
public static void main(String[] args) {
//创建集合对象
Collection collection = new ArrayList();
//创建5个User对象
for(int i=1;i<6;i++){
User user = new User(i, "用户"+i, 10+i);
boolean flag = collection.add(user);
System.out.println(flag);
}
/*
* 保存的是Integer类型,此过程存在自动装箱操作
*/
// boolean flag = collection.add(1);
// System.out.println(flag);
}
}
contains(Object) - boolean
public class ContainsDemo {
public static void main(String[] args) {
// Collection collection = new ArrayList();
// collection.add("a");
// collection.add("b");
// collection.add("c");
//
// //判断"a"是否被包含在集合中
// /*
// * contains(Object) - boolean
// * 判断元素是否包含在集合中,
// * 判断依据:调用集中的的元素所属类的equals()
// */
// boolean flag = collection.contains("a");
// System.out.println(flag);
size() - int
//创建集合对象
Collection collection = new ArrayList();
System.out.println(collection.size());
//创建5个User对象
for(int i=1;i<6;i++){
User user = new User(i, "用户"+i, 10+i);
collection.add(user);
}
System.out.println(collection.size());
User user = new User(2,"用户2",12);
//此user对象是否被包含在集合中
/*
*要求:如果集合中存在一个User对象的id和此User
*的id相等,那么视为此user对象被包含在集合中。
*为了保存结果的合理性 ,需要重写equals方法
*/
boolean flag = collection.contains(user);
System.out.println(flag);
clear() - void
/*
* 将集合中的所有元素清空
*/
collection.clear();
System.out.println(collection.size());
}
}
addAll(Collection) - boolean
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("a");
collection.add("b");
collection.add("c");
Collection coll = new ArrayList();
coll.add("d");
coll.add("e");
coll.add("f");
/*
* addAll(Collection) - boolean
* 将coll集合中的所有元素添加到colletion集合中
*/
System.out.println(collection);
collection.addAll(coll);
coll.addAll(collection);
System.out.println(collection);
}
containsAll(Collection) - boolean
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("a");
collection.add("b");
collection.add("c");
collection.add("d");
collection.add("e");
// collection.add("f");
Collection coll = new ArrayList();
coll.add("d");
coll.add("e");
coll.add("f");
/*判断collection集合中是否包含coll集合中的
* 所有元素
* containsAll(Collection) - boolean
* 元素比较采用的是元素所属类的中equals方法
*
*/
boolean flag = collection.containsAll(coll);
System.out.println(flag);
}
3.2.泛型机制:
创建一个集合对象保存User对象(注册),每一个user都有id,name,想实现对集合的同一管理:
对集合中的所有元素进行遍历,打印出遍历到的每一个user对的name和id
• 泛型是Java SE 5.0引入的特性,泛型的本质是参数化类型。在类、接口和方法的定义过程中,所操作的数据类型被传入的参数指定。
3.3.Iterator迭代器
• 迭代器用于遍历集合元素。获取迭代器可以使用Collection定义的方法: iterator()
• 迭代器Iterator是一个接口,集合在重写Collection的iterator()方法时利用内部类提供了迭代器的实现。
遍历方式:
hasNext()
next()
remove()
在使用迭代器遍历集合时,不能通过集合的remove方法删除集合元素,否则会抛出并发更改异常。我们可以通过迭代器自身提供的remove()方法来删除通过next()迭代出的元素。
forEach循环:增强for循环
Java5.0之后推出了一个新的特性,增强for循环,也称为新循环。该循环不通用于传统循环的工作,其只用于遍历集合或数组。
结构:
for(数据类型 引用:Collection/Array){
}
• 在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。
迭代器遍历集合
public static void main(String[] args) {
/*
* 让一个集合中只能保存一种数据类型
*/
Collection<User> collection = new ArrayList<User>();
// Collection collection = new ArrayList();
//创建5个User对象
for(int i=1;i<6;i++){
User user = new User(i, "用户"+i, 10+i);
boolean flag = collection.add(user);
System.out.println(flag);
}
//对集合中的所有元素进行遍历,打印输出每一个user的name和id
/*
* 对集合进行遍历,使用迭代器Iterator接口
* 1.获取此集合的迭代器对象
* 2.使用迭代器步骤:
* 1.先判断下一个位置是否有元素
* 2.如果有,指向下一个位置并获取下一个元素
*/
Iterator<User> it = collection.iterator();
while(it.hasNext()){
User user = it.next();
System.out.println(user.getId()+"-"+user.getName());
}
}
remove()
Iterator<User> it = collection.iterator();
/*
* 对集合进行遍历,从集合中删除id为2的user对象
*/
while(it.hasNext()){
User user = it.next();
if(user.getId()==2){
it.remove();
}
}
作业:
1.在控制台输入n个学生的信息,存放到List中。
学生信息包括:姓名(String),学号(int),分数(double)
2.一个集合存放的是商品对象,将此集合看成是购物车,
现将购物车中数量为0的商品移除掉 - iterator
3.判断指定学号的学生是否已经录入学校网站(集合表示)
contains
DAY05
1 .内容回顾
1. 正则表达式
a) 字符集,数量词,预定义字符集
b) 分组()
c) 边界匹配符
d) String类中的正则API
<1>matches(String regex)
<2>split(String regex) - String[]
<3>replaceAll(String regex,String replacement) - String
2. 集合Collection
a) 方法
<1> add(E) - boolean
<2> contains(Object) - boolean
<3> size() - int
<4> clear() - void
<5> isEmpty() - boolean
<6> addAll(Collection) - boolean
<7> containsAll(Collection) - boolean
b) 泛型机制<类型>
c) 对集合的遍历:
<1> 迭代器-Iterator
1. 使用迭代器对集合进行遍历的步骤:
a) 调用hasNext()先判断集合中是否有下一个元素
b) 如果有,调用next()指向并获取下一个元素
2.迭代器对集合进行遍历过程中不可以通过集合的删除方法来删除集合元素,否则会抛出异常。如果想在迭代过程中删除满足条件的元素,只能通过迭代器的remove()来删除。
3.forEach循环:增强for循环
for(数据类型 引用:遍历的对象){}
2 集合操作 -线性表
Collection接口的子接口:
List:可重复集
Set:不可重复集
2.1 List
• List接口是Collection的子接口,用于定义线性表数据结构。可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或减少。
• List接口的两个常见实现类为ArrayList和LinkedList,分别用动态数组和链表的方式实现了List接口。
• 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别。ArrayList更适合于随机访问而LinkedList更适合于插入和删除。在性能要求不是特别苛刻的情形下可以忽略这个差别。
ArrayList和LinkedList
两者的数据结构
ArrayList:动态数组
优点:查询性能更高
LinkedList:双向循环链表
优点:插入和删除元素性能更高
List集合中的方法
get和set:
get(int index):获取集合中指定下标对应的元素,下标从0开始。
set(int index, E elment):将给定的元素存入给定位置,并将原位置的元素返回。
插入和删除:
void add(int index,E element):
将给定的元素插入到指定位置
remove(int index): - E
删除给定位置的元素,并将被删除的元素返回。
public static void main(String[] args) {
/*
* List集合中的特有的方法
*/
get(int index) - E element
/*
* get(int index) - E
* 获取集合中指定位置的元素
*/
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
System.out.println(list);
String str = list.get(2);
System.out.println(str);
set(int index,E element) - Original
/*
* set(int index,E element) - String
* 给指定位置用给定元素重新赋值,并返回被替换
* 掉的元素
*/
String original = list.set(2, "hello");
System.out.println(list);
System.out.println(original);
add(int index,E element)
/*
* 在元素b后添加新字符串,
* add(int index,E)
*/
list.add(2, "world");
System.out.println(list);
remove(int index) - E element
/*
* 删除集合中第3个位置的值
* remove(int index) - E
* 删除集合中的指定位置的元素并将删除的元素作为
* 参数返回
*/
String remo = list.remove(2);
System.out.println(list);
System.out.println(remo);
List转换为数组:
• List的toArray方法用于将集合转换为数组
• 其有两个方法:
Object[] toArray()
<T>T[] toArray(T[] a)
其中第二个方法是比较常用的,我们可以传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致。返回值则是转换后的数组,该数组会保存集合中所有的元素。
toArray() - Object[]
/*
* toArray() - Object[]
*/
Object[] objects = list.toArray();
for(Object o:objects){
String s = (String)o;
System.out.println(s.length());
}
toArray(T[]) - T[]
/*
* 得到一个String[]数组用于保存list集合中
* 的所有元素
*/
String[] ary = new String[0];
String[] strs = list.toArray(ary);
for(String s:strs){
System.out.println(s.length());
}
数组转换为List:
• Arrays类中提供了一个静态方法asList,使用该方法我们可以将一个数组转换为对应的List集合。
• 注意点:
1.返回的集合我们不能对其增删元素,否则会抛出异常。
2.对集合的元素进行修改会影响数组对应的元素。
asList(T...a) - List<T>
String[] ary = {"a","b","c","d"};
/*
* 得到一个集合对象用于保存数组中的所有元素
* Array -- >list
*/
List<String> list = Arrays.asList(ary);
// for(String str:list){
// System.out.println(str);
// }
list.set(1, "hello");
System.out.println(Arrays.toString(ary));
2.2 List排序
• Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。
• 该方法定义为: void sort(List<T> list)
该方法的作用是对给定的集合元素进行自然排序。
Comparable:
• Collections的sort方法是对集合元素进行自然排序,那么两个元素对象之间就一定要有大小之分。这个大小之分是如何界定的?实际上,在使用Collections的sort排序的集合元素都必须是Comparable接口的实现类,该接口表示其子类是可比较的,因为实现该接口必须重写抽象方法:
– int compareTo(T t);
该方法用于使当前对象与给定对象进行比较。
– 若当前对象大于给定对象,那么返回值应为>0的整数。
– 若小于给定对象,那么返回值应为<0的整数。
– 若两个对象相等,则应返回0。
案例:
一个集合中存放的是学生对象,现对集合进行排序,排序规则按照学生的id排序
public class Student implements Comparable<Student> {
private int id;
private int age;
private String name;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int id, int age, String name) {
super();
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", age=" + age + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
//定义 比较规则
@Override
public int compareTo(Student o) {
return id-o.getId();
}
public class SortDemo {
public static void main(String[] args) {
/*
* 创建一个List集合,向集合中添加一些元素
*/
// List<Integer> list = new ArrayList<>();
// list.add(5);
// list.add(1);
// list.add(3);
// list.add(2);
/*
* 对list集合排序
* Collections
*/
// System.out.println(list);
// Collections.sort(list);
// System.out.println(list);
/*
* 对以下集合内容进行排序
*/
// List<String> list = new ArrayList<>();
// list.add("tom");
// list.add("amy");
// list.add("rose");
// list.add("jack");
// System.out.println(list);
// Collections.sort(list);
// System.out.println(list);
/*
* 对以下集合进行排序,排序规则是按照学生的id排序
*/
List<Student> list = new ArrayList<>();
Student student = new Student(2, 23,"amy");
Student student2 = new Student(1, 25, "tom");
Student student3 = new Student(3, 24, "rose");
list.add(student);
list.add(student2);
list.add(student3);
System.out.println(list);
//排序
Collections.sort(list);
System.out.println(list);
}
}
在以上操作的基础上(对List集合中的元素按照id排序),
要求:对List集合重新排序,排序规则:按照年龄排序
如果集合中的元素所属类已经定义好了比较规则,在此基础上若想按照别的比较规则比较,那么需要自定义比较器,将来在调用Collections.sort()时,让此方法调用新定义的比较规则
Comparator:
• 一旦Java类实现了Comparable接口,其比较逻辑就已经确定;如果希望在排序的操作中临时指定比较规则,可以采用Comparator接口的方式。
• Comparator接口要求实现类必须重写其定义的方法:int compare(T o1,T o2)
public class ComparatorDemo implements Comparator<Student> {
//定义比较规则
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
public class SortDemo {
public static void main(String[] args) {
/*
* 对以下集合进行排序,排序规则是按照学生的id排序
*/
List<Student> list = new ArrayList<>();
Student student = new Student(2, 23,"amy");
Student student2 = new Student(1, 25, "tom");
Student student3 = new Student(3, 24, "rose");
list.add(student);
list.add(student2);
list.add(student3);
System.out.println(list);
/*
* 不按照Student类中已经定义好的比较规则排序
* 而是按照自定义的比较规则排序
* 自定义规则:按照年龄升序排序
*
*/
Collections.sort(list, new ComparatorDemo());
System.out.println(list);
}
}
也可采用匿名内部类的方式实现:
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
List集合:
方法:
get(int index) - E
set(int index,E) - E
add(int index,E) - void
remove(int index) - E
List集合和数组的转换问题:
1. List -->Array
a) toArray() - Object[]
b) toArray(T[]) - T[]
2. Array-->List
a) Arrays.asList(List<T>) - T[]
b) 注意点:
<1> 不能对得到的集合进行增删操作
<2> 可以对集合的元素进行修改,而原数组会随之变化
List集合排序:
Collections.sort(List),调用此方法的前提条件,list集合中的元素所属的类必须实现Comparable接口重写其compareTo(..)方法(定义比较规则)
如果一个集合中的元素所属类的比较逻辑已经确定(此类已经实现Comparable接口并重写其方法),现对此集合进行排序,想采用临时的比较规则/自定义的比较规则,此时需要写一个类实现Comparator接口并重写其中的compare(o1,o2),在此方法中定义新的比较规则,之后调用Collections.sort(List,Comparator)来排序,注意点,Comparator的实现类可以采用内部类的方式定义。
2.3 队列和栈
队列:Queue - 接口
LinkedList实现了Queue接口
Queue:
java.util.Queue
* 队列,可以存储一组元素,但是存取元素必须
* 遵循先进先出原则(FIFO,First Input First Output)
队列(Queue)是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:
只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素。
JDK中提供了Queue接口,同时使得LinkedList实现了该接口(选择LinkedList实现Queue的原因在于Queue经常要进行添加和删除的操作,而LinkedList在这方面效率较高)。
方法:
Offer(E e):将一个对象添加至队尾,如果添加成功则返回true。
poll(): 从队首删除并返回一个元素。
peek():返回队首的元素(但并不删除)。
注意点:poll()和peek()方法获取元素时,如果队列中没有元素,此时返回null
offer(E)
poll() - E
peek() - E
public class QueueDemo {
public static void main(String[] args) {
/*
* 创建队列对象,并向队列中添加元素
* offer(E) - boolean
*/
Queue<String> queue = new LinkedList<>();
queue.offer("a");
queue.offer("b");
queue.offer("c");
// queue.offer("d");
System.out.println(queue);
/*
* 从队列中取出一个元素
* poll() - E
* 获取队首的元素并完成出队操作
*/
String first = queue.poll();
String second = queue.poll();
String third = queue.poll();
String fourth = queue.poll();
System.out.println(first);
System.out.println(second);
System.out.println(third);
System.out.println("第四个元素是:"+fourth);
System.out.println(queue);
/*
* 获取队列中的第一个元素的值
* peek() - E
* 获取队首的元素但不出队
*/
// String first = queue.peek();
// System.out.println(first);
// System.out.println(queue);
}
}
练习题:
完成对一个队列的遍历,将遍历得到的元素打印输出
队列的自行遍历
/*
* 对队列进行自行遍历
*/
while(queue.size()!=0){
String str = queue.poll();
System.out.println(str);
}
Deque:双端队列
• Deque是Queue的子接口,定义了所谓“双端队列”即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口。
• Queue,Deque,LinkedList三者之间的关系
• LinkedList implements Deque
• Deque extends Queue
方法:
Offer(E e)
offerFirst(E e)
offerLast(E e)
poll()
pollFirst()
pollLast()
/*
* Deque:双端队列,可以分别从队列的两端进行
* 入队和出队操作
*/
/*
* 从队尾入队
* -offer(E) - boolean
* -offerLast(E) - boolean
*
* 从队首入队
* -offerFirst(E) - boolean
*/
Deque<String> deque = new LinkedList<>();
deque.offer("a");
deque.offer("b");
deque.offer("c");
System.out.println(deque);
//从队首入队
deque.offerFirst("first");
System.out.println(deque);
//从队尾入队
deque.offerLast("last");
System.out.println(deque);
/*
* peek系列方法:获取队列中的元素但不出队
*/
//peek() - E:默认从队首取元素
String first = deque.peek();
System.out.println(first);
System.out.println(deque);
//peekLast() -E:从队尾取元素
String last = deque.peekLast();
System.out.println(last);
System.out.println(deque);
/*
* poll()
* pollFirst()
* pollLast()
*/
String s1 = deque.poll();
System.out.println(s1);
System.out.println(deque);
String s2 = deque.pollFirst();
System.out.println(s2);
System.out.println(deque);
String s3 = deque.pollLast();
System.out.println(s3);
System.out.println(deque);
• 如果将Deque限制为只能从一端入队和出队,则可实现“栈”(Stack)的数据结构,对于栈而言,入栈称之为push,出栈称之为pop。
• 栈遵循先进后出(FILO First Input Last Output )的原则。
如果对Deque加上限制成为了栈,此时向栈中添加元素(入队),需要使用Deque中定义的一个特殊的方法:push(E)
如果从栈中取出元素,需要调用Deque中定义的方法:pop()
public class StackDemo {
public static void main(String[] args) {
//创建双端队列对象
Deque<String> stack = new LinkedList<>();
//对此队列加限制使其成为栈
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack);
//取出栈中的一个元素
String str = stack.pop();
System.out.println(str);
System.out.println(stack);
}
}
总结:
List集合
队列:Queue
双端队列:Deque
栈:Stack
DAY06
1 .内容回顾
List集合
方法
get(int index) - E
set(int index,E ) - original
add(int index,E) - void
remove(int index) - E
List集合和数组的相互转换
List -->Array
toArray() - Object[]
toArray(T[]) - T[]
Array -->List
Arrays.asList(T...a) - List
注意点:
1. 不可以对得到的集合进行增删操作
2. 可以对得到的集合进行修改操作,但是原数组也随之发生变化
List排序:
Collections.sort(List)
前提:list中的元素的类必须实现Comparable接口,重写其中的compareTo(T)
Collections.sort(List,Comparator)
需求:在集合中的元素类已经确定了比较逻辑的前提下,如果向采用别的比较逻辑,此时就可以写一个类实现Comparator接口,重写其compare(T1,T2)
数据结构:
Queue:队列
- 特点:FIFO
Deque:双端队列
- 特点:可以分别从两端入队和出队
Stack:栈
- 特点:先进后出
2.Set接口:set集合
特点:不可重复集
元素不可重复
添加元素时,先判断元素是否已经存在于集合中,如果存在,那么添加失败,如果不存在,添加成功。
如何判断元素是否已经存在:
调用集合中的元素类中的equals方法
实现类:HashSet()
Set接口下有多个实现类,大部分的set实现类集合都有无序的特点。并不是所有set集合都是无序的,比如LinkedHashSet此集合是有序的
练习:对set集合(User对象)进行遍历,打印输出每个user对象的详细信息
3 查找表:
3.1 Map接口
具有映射关系的数据:
语文 - 90 key - value 键-值
数学 - 80
英语 - 90
• Map接口定义的集合又称查找表,用于存储所谓“Key-Value”映射对。Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。
• 根据内部数据结构的不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序红黑树实现的TreeMap。
Map接口中定义的方法:
put(K key,V value):
向集合中存放元素。
如果存放的key值已经存在,会怎么样?
/*
* 创建Map集合,向集合添加键值对数据
* Map集合中的Key和value都只能是引用类型
*/
Map<String, Double> map =
new HashMap<>();
/*
* 向集合中添加元素
* put(K,V) - V
* :向map集合中添加键值对,将key对应的原来的值返回
* 如果Key已经存在,那么用新的vlaue覆盖掉原来的value值
*/
Double d = map.put("语文",90.0);
Double d1 = map.put("语文", 80.0);
System.out.println(map);
System.out.println(d);
System.out.println(d1);
注意点:HashMap集合是无序的。
get(K key) – V
:根据key值取value值
containsKey(Object key):
判读某个key是否在Map中存在
判断key是否存在map中的方式:调用key的equals方法判断。
为了保证结果的合理性,通常需要重写equals方法的
public static void main(String[] args) {
/*
* 创建Map集合,向集合添加键值对数据
* Map集合中的Key和value都只能是引用类型
*/
Map<String, Double> map =
new HashMap<>();
/*
* 向集合中添加元素
* put(K,V) - V
* :向map集合中添加键值对,将key对应的原来的值返回
* 如果Key已经存在,那么用新的vlaue覆盖掉原来的value值
*/
Double d = map.put("语文",90.0);
Double d1 = map.put("语文", 80.0);
map.put("数学",90.0);
map.put("英语", 80.5);
System.out.println(map);
// System.out.println(d);
// System.out.println(d1);
/*
* 获取数学科目的成绩并打印输出
*/
Double score = map.get("数学");
System.out.println(score);
/*
* containsKey(Object key) - boolean
* 判断给定的key是否包含在map集合中
* 判断方式:调用key所属类的equals方法
*/
boolean flag = map.containsKey("语文");
System.out.println(flag);
}
练习:
map集合保存的数据 ,User - age,此集合中保存了3个user的信息,现要求将用户id为3的用户age改为34
public static void main(String[] args) {
Map<User, Integer> map = new
HashMap<>();
User user = new User(1, 12);
User user2 = new User(2, 13);
User user3 = new User(3, 23);
map.put(user, user.getAge());
map.put(user2, user2.getAge());
map.put(user3, user3.getAge());
System.out.println(map);
//对id为3的user的年龄进行修改
// User destUser = new User(3, 34);
user3.setAge(34);
map.put(user3,user3.getAge());
System.out.println(map);
}
Map的遍历
对map中所有key值进行遍历并输出
-keySet() - Set<K>
public static void main(String[] args) {
/*
* 对Map集合中的所有key值进行遍历并打印输出
*/
Map<String, Double> map =
new HashMap<>();
map.put("语文", 98.5);
map.put("数学", 90.0);
map.put("英语", 89.0);
//取出所有的科目并打印
Set<String> set = map.keySet();
for (String name : set) {
System.out.println(name);
}
}
对Map中的每一组键值对进行遍历
因为每一组键值对是唯一的,所以可以将所有的键值对保存到一个set集合中,对此set集合进行遍历。
此时set集合中的每一个元素是一组键值对,那么泛型应写什么类型
Set<Entry<K,V>> set = map.entrySet();
对此set集合进行遍历取到每一个key-value对
调用entry中的getKey()来获取键值对中的key值
调用entry中的getValue()来获取键值对中的value值
/*
* 对map集合中的每一组键值对进行遍历
* entrySet()
*/
Set<Entry<String, Double>> entrys =
map.entrySet();
for (Entry<String, Double> entry : entrys) {
//entry代表遍历到的一组键值对对象
//将此key-value对中的key和value分别取出并打印
System.out.println(entry.getKey() +"-"+entry.getValue());
}
3.2 HashMap
HashCode():返回的整数有范围
作用:返回一个和地址相关的整数值
注意点:
1. 两个不同对象的hashCode()值可能是相同的
2. 如果两个对象equals结果为true,那么在程序中多次生成的hashcode值一定是相同的
HashMap数据结构的实现:
key—>hashcode()àcode-à散列算法àint(这个值为元素保存在数组中的位置)
1.HashMap内部由数组实现,是当今查询速度最快的数据结构。HashMap根据key元素决定这组键值对应当存放在数组的位置,并且也是根据key元素得到位置来检索数组中的该组键值对以此省去了遍历数组的过程.
2.但是使用HashMap时应当尽量避免出现链表的情况.
HashMap中链表的产生原因:
HashMap是根据key元素的hashcode方法返回的数字经过散列计算得到该组键值对应当存放在数组的哪个位置,而根据key元素equals比较查看当前key是否已经存在于Map中,若存在则直接替换该位置这个key所对应的value,但是若数组该位置已经存在键值对,并且key与当前准备存放的键值对中的key的equals比较不同时,则会在数组当前位置产生链表.这样在将来根据key检索时会出现遍历链表的情况,这样就会降低HashMap查询性能.
总结:当key元素hashcode值相同,但是equals比较不同时就会在HashMap中产生链表,影响查询性能.
如何尽可能的避免出现链表?
重写hashCode和equals方法
保证两个对象equals结果为true,那么此时他们的hashcode值是一样的。
HashSet:HashMap的key的那一列
Map接口的常用实现类:
HashMap
TreeMap:红黑数算法-会自动排序的
Set:TreeSet
3.3 有序的Map -- LinkedHashMap
• 使用Map接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于:
LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。
案例:
HashMap中元素取出顺序和Put的顺序不一定一样
LinkedHashMap中元素取出顺序和put的顺序一致
public static void main(String[] args) {
Map<Integer, String> map =
new LinkedHashMap<>();
map.put(23, "a");
map.put(12, "b");
map.put(45, "c");
System.out.println(map);
}
封装类中的类型定义注意点:
通常在封装类中定义的数据类型是引用类型
方法的递归调用:
在一个方法的内部调用这个方法本身,叫做方法的递归调用
案例:
1. 求阶乘
a) 5! = 5*4*3*2*1
b) 5!=5*4!
c) 4! =4*3!
d) 3! = 3*2!
e) 2!=2*1!
2. 斐波那契数列
数列: 1 1 2 3 5 8 13 21 34...
求Fabonacci数列中第n个位置的值。
Fn = Fn-1 + Fn-2(n>2)
递归是有深度的,如果深度太深,不建议使用递归。
如果要使用递归,必须有一个出口(结束条件)。
作业:
用户从控制台输入要打印出的斐波那契数列的个数
,控制台打印出到这一位位置的所有数列的值。
eg:sc = 5
打印的结果: 1 1 2 3 5
求阶乘
/**
* 求一个数(由用户从控制台输入)的阶乘
* @author adminitartor
*
*/
public class ProductDemo {
public static void main(String[] args) {
System.out.println("请输入要求阶乘的整数:");
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
//求x的阶乘
int product = f(x);
System.out.println(product);
sc.close();
}
//求某个数字的阶乘
public static int f(int n){
if(n==1){
return 1;
}
return n*f(n-1);
}
}
斐波那契数列
/**
* 求Fabonacci数列中某个位置的值
* @author adminitartor
*
*/
public class FabonacciDemo {
public static void main(String[] args) {
System.out.println("请输入要求的位置:");
Scanner sc = new Scanner(System.in);
int pos = sc.nextInt();
int x = f(pos);
System.out.println(x);
sc.close();
}
//求出某个位置的值
public static int f(int n){
if(n==1 || n==2){
return 1;
}
return f(n-1)+f(n-2);
}
}
集合:
Collection接口中的方法
List集合
ArrayList
LinkedList
方法
List和数组的转换
List排序
Set集合:
特点:不可重复集
HashSet,TreeSet,LinkedHashSet
Map集合:保存键值对数据
HashMap:数据结构
方法:
put
get
containsKey
map集合的遍历:
1. 对map中所有key的遍历 - keySet()
2. 对map中的所有元素的遍历 - entrySet()
注意点:
定义封装类中数据的数据类型 - 引用类型
方法的递归调用
4 文件操作 – File
java.io.File用于表示文件(目录),也就是说程序员可以通过File类在程序中操作硬盘上的文件和目录。
4.1 创建File对象
构造方法:
1.File(String pathName)
目录的层级分隔符不要直接写”/”或”\”,应使用File.separator这个常量表示,以避免不同系统带来的差异。
File file = new File("C:\\a.txt");
创建File对象指向给定路径的文件/目录
创建File对象后,此对象指向的文件/目录不一定存在
2.File(File parent,String child):
在指定的父目录下创建子文件/子目录
3.File(String parent,String child):
在指定的父目录下创建子文件/子目录
和第二种构造方法作用完全相同,唯一的区别就是父目录的形式不同
4.2 File表示文件信息操作
方法:
createNewFile()
mkdir()
创建文件或文件夹,如果指向的文件/目录已经存在,那么方法返回false,只有文件/目录不存在,才会创建
public class FileDemo {
public static void main(String[] args) throws IOException {
/*
* 在C盘创建一个文件a.txt
* 通过代码创建文件:
* 1.先创建File对象指向这个文件
* 2.通过调用File类下的一个方法来创建文件的
* file.createNewFile();
*/
// File file = new File("C:"+File.separator+"a.txt");
// boolean flag = file.createNewFile();
// System.out.println(flag);
/*
* 在C盘创建一个hello文件夹
* 在此文件夹下创建一个子文件 - a.txt
*/
File parent = new File("C:"+File.separator+"hello");
//创建目录
boolean flag = parent.mkdir();
System.out.println(flag);
//在此目录下创建子文件a.txt
File child = new File(parent,"a.txt");
flag = child.createNewFile();
System.out.println(flag);
//在hello文件夹下创建子目录 world目录
File child1 = new File(parent, "world");
flag = child1.mkdir();
System.out.println(flag);
//在hello文件夹下创建 week目录
File child2 = new File("C:"+File.separator+"hello","week");
flag = child2.mkdir();
System.out.println(flag);
}
}
练习:
1. 在某个盘符下创建hello目录
2. 在hello目录下创建子目录
3. 在hello目录下创建子文件
思考: File file = new File("a.txt");
file.createNewFile();
文件是否创建成功,如果成功,文件的路径是什么?
可以创建成功,创建在当前项目下。
绝对路径:从盘符开始一级一级往下写
C:\hello\a.txt
相对路径:有参照物
../