1、正则表达式
(1)概念:
正则表达式是用来描述字符串内容格式,使用它通常用来匹配一个字符串的内容是否符合要求
补充:
正则的概念:正则就是正则对象(RegExp),核心是正则表达式(规则字符串)。
正则表达式: 对字符串操作的一种逻辑公式,就是用事先定义好的
一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,
这个“规则字符串”用来表达对字符串的一种过滤逻辑。
(2)语法:
正则表达式的语法:-----------了解、不用纠结、不用深入研究
例:在网站上经常用于检测用户输入数据是否符合规范:
- 检测 用户名 是否为8~10数字 英文(大小写)
- 检测 电话号码是否符合规范
- 检测 邮箱地址是否符合规范
- 等
01.正则表达式的特殊字符:
- 1.字符集合:
- 2.预定义字符集:
- 3.量词:约定左侧元素的个数
- 4.特殊字符转义
- 5.分组:将一组规则作为整体进行处理:
1.字符集合:限制字符
[]:表示一个字符,该字符可以是[]中指定的内容
例如:
[abc]:这个字符可以是a或b或c
[^abc]:该字符只要不是a或b或c
[a-z]:表示任意一个小写字母
[a-zA-Z]:表示任意一个字母
[a-zA-Z0-9_]:表示任意一个数字字母下划线
[a-z&&[^bc]]:a~z中除了b和c以外的任意一个字符,其中&&表示“与”的关系
2.预定义字符集:
.:表示任意一个字符,没有范围限制
\d:表示任意一个数字,等同于[0-9]
\w:表示任意一个单词字符,等同于[a-zA-Z0-9_]
\s:表示任意一个空白字符
\D:表示不是数字
\W:不是单词字符
\S:不是空白字符
补充:
在其他语言中,\\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如 Perl),一个反斜杠 \ 就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \\ 代表其他语言中的一个 \,这也就是为什么表示一位数字的正则表达式是 \\d,而表示一个普通的反斜杠是 \\。
例:
System.out.print("\\"); // 输出为 \
System.out.print("\\\\"); // 输出为 \\
3.量词:约定左侧元素的个数
?:表示前面的内容出现0-1次
例如: [abc]? 可以匹配:a 或 b 或 c 或什么也不写
+:表示前面的内容最少出现1次
例如: [abc]+ 可以匹配:b或aaaaaaaaaa...或abcabcbabcbabcbabcbabbabab....
但是不能匹配:什么都不写 或 abcfdfsbbaqbb34bbwer...
*:表示前面的内容出现任意次(0-多次)---匹配内容与+一致,只是可以一次都不写
例如: [abc]* 可以匹配:b或aaaaaaaaaa...或abcabcbabcbabcbabcbabbabab....或什么也不写
但是不能匹配:abcfdfsbbaqbb34bbwer...
{n}:表示前面的内容出现n次
例如: [abc]{3} 可以匹配:aaa 或 bbb 或 aab 或abc 或bbc
但是不能匹配: aaaa 或 aad
{n,m}:表示前面的内容出现最少n次最多m次
例如: [abc]{3,5} 可以匹配:aaa 或 abcab 或者 abcc
但是不能匹配:aaaaaa 或 aabbd
{n,}:表示前面的内容出现n次以上(含n次)
例如: [abc]{3,} 可以匹配:aaa 或 aaaaa.... 或 abcbabbcbabcbabcba....
但是不能匹配:aa 或 abbdaw...
()用于分组,是将括号内的内容看做是一个整体
例如: (abc){3} 表示abc整体出现3次. 可以匹配abcabcabc
但是不能匹配aaa 或abcabc
(abc|def){3}表示abc或def整体出现3次.
可以匹配: abcabcabc 或 defdefdef 或 abcdefabc
但是不能匹配abcdef 或abcdfbdef
量词补充:
x{n} 约定左侧x出现n次
x{n,m} 规定左侧x出现最少n次,最多m次
x{0,n} 规定左侧x出现0到n次
x{n,} 规定左侧x出现最少n次
x? 和x{0,1}等价,x可以没有或者有一个
x+ 和x{1,}等价,x至少有1个,多了随意,简称:一个以上
x* 和x{0}等价,x至少有0个,多了随意,简称:0个以上
4.特殊字符转义:如何匹配字符 【[ ] ? + * .】 ,使用\特殊字符,进行转义!
\. 匹配点 --------重点!
\[] 匹配[
\? 匹配?
\* 匹配*
\+ 匹配+
\\ 匹配\
5.分组:将一组规则作为整体进行
(red|blue|green):匹配red或者blue或者green;
02.如下对应例题:
(1)如上1.字符集合练习题:
例:匹配一个有效字符范围
Hello[1-6]
例:
package apiday02;
/**
* 测试正则
*/
public class RegDemo06 {
public static void main(String[] args) {
String reg = "Hello[123456]";
//被测试的字符串
String s1 = "Hello1";
String s2 = "Hello7";
//测试
System.out.println(s1.matches(reg));//true
System.out.println(s2.matches(reg));//false
}
}
(2)如上2.预定义字符集练习题:
例:
正则规则:\w\w\w\w\w\w
Java String : “\\w\\w\\w\\w\\w\\w”
测试案例:网站上规则 用户名是6个单词字符
package apiday01;
public class RegDome {
public static void main(String[] args) {
/**
* 测试 用户名规则:6个单词字符组成
* - \ 在Java字符串中需要进行转义为\
*/
//正则表达式:可不可以写成:...... 6个点 不可以,范围太大了;逻辑错误
String reg = "\\w\\w\\w\\w\\w\\w";
System.out.println(reg);// \w\w\w\w\w\w
System.out.println(a);
//被检查的字符串
String s1 = "Jerry1";//可以通过检查
String s2 = "Tom-12";//不可以通过检查
String s3 = "Andy";//不可以通过检查
System.out.println(s1.matches(reg));//true
System.out.println(s2.matches(reg));//false
System.out.println(s3.matches(reg));//false
}
}
(3)如上3.量词练习题:
①例1:\w\w\w\w\w\w 等价于 \w{6}
package apiday01;
public class RegDemo08 {
public static void main(String[] args) {
/**
* 测试:网站的密码是单词字符,最少8个,多了不限\w{8}
*/
//定义 网站密码的规则
String reg = "\\w{8,}";// x{n,}:规定左侧x出现最少n次
//定义 被检查的字符串
String s1 = "asdfghjkl";//可以通过检查的字符串
String s2 = "abcde";//不可以通过检查的字符串,太短了 (网站的密码是单词字符,最少8个,多了不限)
String s3 = "asdfghjkl;";//不可以通过检查的字符串,包括“;”
//
System.out.println(s1.matches(reg));//true
System.out.println(s2.matches(reg));//false
System.out.println(s3.matches(reg));//false
}
}
②例2:
- 网站的用户名是8~16个单词字符:\w{8,16}
- 网站的密码是单词字符,最少8个,多了不限\w{8}
- 匹配Hello World,中间至少有一个空白:Hello\s+World \s+ :至少一个,多了不限
---不能匹配:"HelloWorld"
---不能匹配:"Hello World!"
-----能匹配: "Hello World"
package apiday01;
public class RegDemo09 {
public static void main(String[] args) {
/**
* 测试:
* Hello\s+World
*/
//定义正则表达式:
String reg = "Hello\\s+World";//
//定义被检查的字符串:
String s1 = "HelloWorld";//不能通过检查
String s2 = "Hello World";//能通过检查
String s3 = "Hello World";//能通过检查
String s4 = "Hello World";//能通过检查
String s5 = "Hello World!";//不能通过检查
//检查结果:
System.out.println(s1.matches(reg));//false
System.out.println(s2.matches(reg));//true
System.out.println(s3.matches(reg));//true
System.out.println(s4.matches(reg));//true
System.out.println(s5.matches(reg));//false
}
}
(4)如上4.特殊字符转义练习题:
例:如下正则的意义:匹配www.tedu.cn域名
① - - www.tedu.cn 匹配:
- www.tedu.cn 通过
- wwwAteduAcn 通过
- www-tedu-cn 通过
②- - www\\.tedu\\.cn 匹配:
- www.tedu.cn 通过
- wwwAteduAcn 不通过
- www-tedu-cn 不通过
package apiday02;
public class RegDemo10 {
public static void main(String[] args) {
/**
* 测试 如何匹配 域名 www.tedu
* 必须使用正则表达式 www\.tedu\
* . 表示任意字符
* 如果匹配. 就需要\.
*/
//定义正则表达式:
String reg1 = "www.tedu";//错误的!
String reg2 = "www\\.tedu\\";//正确的
//定义被检查的字符串:
String s1 = "www.tedu";
String s2 = "wwwAteduAcn";
String s3 = "www-tedu-cn";
//测试reg1
System.out.println(s1.matches(reg1));//true
System.out.println(s2.matches(reg1));//true
System.out.println(s3.matches(reg1));//true
//测试reg2
System.out.println(s1.matches(reg2));//true
System.out.println(s2.matches(reg2));//false
System.out.println(s3.matches(reg2));//false
}
}
补充练习题:
案例:如何检查一个字符串是否为正确的IPV4地址
正确IP: "192.168.1.25"、 "192.168.199.1"、 "10.0.0.20"、"8.8.8.8"
错误IP: "10-10-10-20" 、"192点168点5点25"
正则:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
- \d{1,3} \. \d{1,3} \. \d{1,3} \. \d{1,3}
注意:写在idea中反斜杠要写两次
(5)如上5.分组练习题
例1:正则
①\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
②(\d{1,3}\.)(\d{1,3}\.)(\d{1,3}\.)(\d{1,3})
③(\d{1,3}\.){3} \d{1,3}
package apiday02;
public class RegDemo11 {
public static void main(String[] args) {
/**
* 检查IP地址是否符合规则
*/
//定义正则规则
//String reg = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";//:\.是匹配点 的
String reg = "(\\d{1,3}\\.){3}\\d{1,3}";//括号里的后边重复了出现三次 用{3}表示
//定义被检查的字符串
String ip1 = "192.168.2.70";
String ip2 = "10.0.0.20";
String ip3 = "8.8.8.8";
//定义错误的被检查字符串
String ip4 = "192点168点2点70";
String ip5 = "192-168-2-70";
//检查
System.out.println(ip1.matches(reg));//true
System.out.println(ip2.matches(reg));//true
System.out.println(ip3.matches(reg));//true
System.out.println(ip4.matches(reg));//false
System.out.println(ip5.matches(reg));//false
}
}
例2:如下①②③:
①`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`
②`\d{1,3}(\.\d{1,3})(\.\d{1,3})(\.\d{1,3})`
③ `\d{1,3}(\.\d{1,3}){3}`
区别是?:
①(\d{1,3}\.){3} \d{1,3} (分组){3} 分组的整体出现3次
②\d{1,3}\.{3}\d{1,3} \.{3}中的. 必须出现2次,可以匹配“192.168...”
2、String支持与正则表达式相关的3个方法:
- 方法1: matches():使用给定的正则表达式验证当前字符串的格式是否符合要求
- !方法2: split():将当前字符串按照满足正则表达式的部分进行拆分
(将一个字符串劈开为几个子字符串) - 方法3: replaceAll():将当前字符串中满足正则表达式的部分替换为给定的字符串
(1)matches():使用给定的正则表达式验证当前字符串的格式是否符合要求
package apiday.day02.regularexpression;
/**
* String字符串有三个比较常用的支持正则表达式的方法:
* boolean matches(String regex)
* 使用给定的正则表达式验证当前字符串的格式是否符合要求,符合则返回true,否则返回false
*/
public class MatchesDemo1 {
public static void main(String[] args) {
/*
邮箱的正则表达式:
[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\.[a-zA-Z]+)+
*/
String email = "wangkj@tedu";
String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";
boolean match = email.matches(regex);
if(match){
System.out.println("是正确的邮箱");
}else{
System.out.println("不是正确的邮箱");
}
/** 例2:测试正则表达式 */
//定义正则表达式
String rule = "HelloWorld";
//定义被检测的字符串
String s1 = "HelloKitty";
String s2 = "HelloWorld";
//检测 s1 是否符合规则
boolean b1 = s1.matches(rule);
//检测 s2 是否符合规则
boolean b2 = s2.matches(rule);
System.out.println(b1);
System.out.println(b2);
}
}
(2)split():将当前字符串按照满足正则表达式的部分进行拆分
-------------(将一个字符串劈开为几个子字符串)
package apiday.day02.regularexpression;
import java.util.Arrays;
/**
* String支持正则表达式的第二个方法:拆分字符串
* String[] split(String regex)
* 将当前字符串按照满足正则表达式的部分进行拆分,并将拆分出的所有部分以String[]形式返回
*/
public class SplitDemo2 {
public static void main(String[] args) {
String line = "abc123def456ghi";
String[] data = line.split("[0-9]+"); //按数字拆分
//将data数组按照字符串的格式输出:
System.out.println(Arrays.toString(data));//[abc, def, ghi]
line = "123,456,789,482";
data = line.split(","); //按逗号拆分
System.out.println(Arrays.toString(data));//[123, 456, 789, 482]
line = "123.456.789.482";
data = line.split("\\."); //按点拆分
System.out.println(Arrays.toString(data));//[123, 456, 789, 482]
//最开始就是可拆分项(.),那么数组中的第1个元素为一个空字符串------""
//如果连续两个(两个以上)可拆分项,它们中间也会拆出一个空字符串-----""
//如果末尾连续多个可拆分项,那么拆出的空字符串被忽略
line = ".123.456..789.482.......";
data = line.split("\\.");
System.out.println(Arrays.toString(data));//[, 123, 456, , 789, 482]
/**
* 例题:
* 根据给定正则表达式的匹配拆分此字符串。该方法的作用就像是
* 使用给定的表达式和限制参数 0 来调用两参数 split 方法。
* 因此,所得数组中不包括结尾空字符串。
*
* 例如,字符串 "boo:and:foo" 使用这些表达式可生成以下结果:
* Regex 结果
* : { "boo", "and", "foo" }
* o { "b", "", ":and:f" }
*/
String str = "boo:and:foo";
String[] arr = str.split(":");
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
//输出:
// boo
//and
//foo
//劈开时候,会自动舍弃后面的空字符串
arr = str.split("o");
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
// "boo:and:foo"
// oo oo
//输出:
//b
//
//:and:f
}
}
(3)replaceAll():将当前字符串中满足正则表达式的部分替换为给定的字符串
package apiday.day02.regularexpression;
import java.util.Scanner;
/**
* 字符串支持正则表达式的第三个方法:替换
* String replaceAll(String regex,String str)
* 将当前字符串中满足正则表达式的部分替换为给定的字符串
*/
public class ReplaceAllDemo3 {
public static void main(String[] args) {
String line = "abc123def456ghi";
line = line.replaceAll("[0-9]+","#NUMBER#"); //将数字部分替换为#NUMBER#
System.out.println(line);
//案例:敏感词替换:
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String str = scanner.nextLine();
String s = str.replaceAll("我[去艹草靠]","***");
System.out.println(s);
}
}
3、Object类--------toString()与equals()
1.Object是所有类的鼻祖(顶级超类),所有类都直接或间接继承了Object,万物皆对象,为了多态
2.Object中有几个经常被派生类重写的方法:toString()和equals()还有hashCode()---这个在散列表才用
(1)调用toString()时默认返回: 类的全称@地址,没有参考意义,所以常常重写toString()返回具体数据
(2)调用equals()时默认比较的还是==(即比较地址),没有参考意义,所以常常重写equals()来比较具体的属性值
需要注意:java的类(String)已经重写equals()了,但我们自己定义的类中必须自己重写equals()后再去调用equals()比较的内容才会相等;
否则即使调用equals()去比较的还是地址
(3)派生类重写equals()的基本规则:
1)两个对象必须是同一个类型,若类型不同则返回false
2)若参数对象为null,则返回false
3)原则上两个对象要比较对象的属性是否是相同
(1)toString():
(2)equals():注意==:作用是判定两个对象的地址是否相同!
补充:
1、equals是object的方法
2、String类型的
equals重写了object的方法,所以此方法比较的是内容,不比较内存地址
==比较内容和地址,因为String也属于引用数据类型
注意:String是特殊的在声明对象时可以写new也可以不写(不写默认就是new)
(总结:==比较内存地址和内容,equals方法被重写只比较内容)
3、基本类型,如int,char,long,boolean。
没有equals方法,只有==只比较值,因为基本数据类型存在栈里也不能new,最关键的一点是只有对象才能调方法
(总结:基本数据类型只有==进行比较,只比较值)
4、引用数据类型,如Integer,Byte,Long,Character,Boolean
引用数据类型是可以new的,而new出来的对象都会在堆中有开辟一个内存地址空间
通常用==比较对象时,比较的就是内存地址和内容
equals是用==判断两个对象是否相等,比较内存地址和内容,当两者都相等时才返回真
(总结:引用数据类型除String特殊外,equals和==都比较内存地址和内容)
1.如果我有一个自定义类对象stu
那么我比较两个对象是否相等,在没重写equals和hashcod方法时,是否用equals和==都可以?(是)
2.如果我比较这个对象中的某个属性是否等于某内容时,这个比较是否就要看我自定义类中的属性类型了?(如果说其中的属性是基本数据类型就只能用==比较值。如果是引用数据类型equals和==都行,比较内存地址和内容。如果是String类型equals比较内容,==比较内存地址和内容)
package apiday.day02.object;
import java.util.Objects;
/** 测试常常被派生类重写的Object中的相关方法 */
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Point{"+"x=" + x +", y=" + y +'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
package apiday.day02.object;
/**
* Object:
* Object是所有类的鼻祖(顶级超类),所有类都直接或间接继承了Object,万物皆对象,为了多态
* Object中有几个经常被派生类重写的方法:toString()和equals()还有hashCode()---这个在散列表才用
*
* 一、演示在什么场合下会用到Object中的什么方法?以及应当如何重写?
* 1.第一个常被子类重新的Object中的方法是:toString()
* (1)输出引用(即:对象p)会默认调用Object中的toString()
* (2)字符串连接时会默认调用toString()
* 为什么重写toString()? 答:调用toString()时默认返回:类的全称@地址,没有参考意义,所以常常重写toString()返回具体数据
* 2.第二个常被子类重新的Object中的方法是:equals()
* 为什么重写equals()? 答:调用equals()时默认比较的还是==(即比较地址),没有参考意义,所以常常重写equals()来比较具体的属性值
* 需要注意:java的类(String)已经重写equals()了,但我们自己定义的类中必须自己重写equals()后再去调用equals()比较的内容才会相等,
* 否则即使调用equals()去比较的还是地址
*
* 二、派生类重写equals()的基本规则:
* ①两个对象必须是同一个类型,若类型不同则返回false
* ②若参数对象为null,则返回false
* ③原则上两个对象要比较对象的属性是否相同
*
* 三、==和equals的区别:
* (1)==:对于基本类型而言,比较的是数值是否相等
* 对于引用类型而言,比较的是内存地址是否相等
* (2)equals:String中重写了equals(),用于比较字符串内容是否相同,
* 若不重写equals()则默认调用Object中的equals()还是比较地址,
* 所以equals()常常被重写来比较对象的数据是否相同
*
*/
public class ObjectDemo {
public static void main(String[] args) {
Point p = new Point(1,2);
//为什么重写toString()?
// 答:Point类若不重写Object类的toString()方法,则使用Object中定义了的toString(),
// 方法的返回字符串格式为:类的全称@地址(如下)
// 例:System.out.println(p);//apiday.day02.gettersetter.Point@28d93b30
// 但通常这个返回结束对我们的开发没有帮助,因此需要在Point类中重写toString()方法
//一、1.第一个常被子类重新的Object中的方法是:toString()
//(1)输出引用(即:对象p)会默认调用Object中的toString(),
//相当于System.out.println(p.toString());
System.out.println(p);//Point{x=1, y=2}
//(2)字符串连接时会默认调用toString()
//相当于 System.out.println(str.toString());
String str = "这是一个Point:" + p;
System.out.println(str);//这是一个Point:Point{x=1, y=2}
/* 一、2.第二个常被子类重新的Object中的方法是equals() */
Point p1 = new Point(1,2);
Point p2 = new Point(1,2);
System.out.println(p1==p2);//false,==比较的是地址
//Object中自己定义的equals()内部还是使用==来比较
//因此派生类在使用时若想比较内容,常常需要重写equals()
//若派生类中重写equals(),则调用重写之后的比较
/*
二、派生类重写equals()的基本规则:
①两个对象必须是同一个类型,若类型不同则返回false
②若参数对象为null,则返回false
③原则上两个对象要比较对象的属性是否相同
*/
System.out.println(p1.equals(p2));//true,因为重写equals()中比较的是x和y
/**
* 需要注意:java的类(String)已经重写equals()了,
* 但我们自己定义的类中必须自己重写equals()后再去调用equals()比较的内容才会相等,
* 否则即使调用equals()去比较的还是地址
*/
//我们自己定义的类在使用时必须自行重写这个方法。
//(1)只有String类的内部已经重写了equals(),重写后可以比较内容
String s1 = new String("?????");
String s2 = new String("?????");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
//(2)除了String类,其余类重写equals()比较的还是地址
StringBuilder str1 = new StringBuilder("?????");
StringBuilder str2 = new StringBuilder("?????");
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2));//false
//(3)......
//(4)......
}
}
4、包装类(自动拆装箱特性、两个常用功能)
- java
定义了8个包装类
,目的是为了解决基本类型不能直接参与面向对象开发
的问题,使得基本类型可以通过包装类的实例以对象的形式存在
----其实就是给8种基本类型套了个壳 - 8个包装类:Integer、Character、Byte、Short、Long、Float、Double、Boolean
注:int的包装类:Integer char的包装类:Character。其余6种基本类型的包装类,首字母大写了 - 其中Character和Boolean是直接继承自Object的,而其余6个数字包装类都继承自java.lang.Number
- Number是一个抽象类,里边定义了一些方法,目的是让包装类可以将其表示的基本类型转换为其他数字类型.
01.JDK5之后--自动拆装箱特性:
装箱:把基本类型加个壳(即首字母大写)转为包装类
拆箱:
(1)JDK5之后推出了一个新的特性:自动拆装箱。该特性是编译器认可以,当编译器编译时若发现有
基本类型与包装类型相互赋值时,将会自动补充代码来完成他们的转换工作,这个过程称为自动拆装箱
02.包装类的常用功能:
(1)可以通过包装类来得到基本类型的取值范围:
(2)包装类提供了一个静态方法【parse(byte/int...)(引用)】,可以将字符串转换为对应的基本类型,
前提是该字符串正确描述了基本类型可以保存得值,否则会抛出数字转换异常:NumberFormatException
package apiday.day02.packagingclass;
/**
* 1、包装类:
* (1)java定义了8个包装类,目的是为了解决基本类型不能直接参与面向对象开发的问题,
* 使得基本类型可以通过包装类的实例以对象的形式存在----其实就是给8种基本类型套了个壳
* (2)8个包装类:Integer、Character、Byte、Short、Long、Float、Double、Boolean
* 注:int的包装类:Integer char的包装类:Character。其余6种基本类型的包装类,首字母大写了
* (3)其中数字类型的包装类都继承自java.lang.Number,而char和boolean的包装类(Character和Boolean)直接继承自Object
* (4)Number是一个抽象类,里边定义了一些方法,目的是让包装类可以将其表示的基本类型转换为其他数字类型.
*
*
* 01.自动拆装箱特性:
* 装箱:把基本类型加个壳(即首字母大写)转为包装类
* 拆箱:
* (1)JDK5之后推出了一个新的特性:自动拆装箱。允许我们在基本类型与包装类型直接赋值,而无需做转换操作
*
* 02.包装类的常用功能:
* (1)可以通过包装类来得到基本类型的取值范围:
* (2)包装类提供了一个静态方法【parse(byte/int...)(引用)】,可以将字符串转换为对应的基本类型,
* 前提是该字符串正确描述了基本类型可以保存得值,否则会抛出数字转换异常:NumberFormatException
*/
public class IntegerDemo {
public static void main(String[] args) {
/** 包装类: */
/* -基本类型转换为包装类:------现在不用了*/
int i = 123;
//java推荐我们使用包装类的静态方法valueOf()将基本类型转换为包装类,而不是直接new
Integer i1 = Integer.valueOf(i);//Integer会重用-128-127之间的整数对象
Integer i2 = Integer.valueOf(i);
System.out.println(i1==i2);//true //new则是false,valueOf在一字节之内是true
System.out.println(i1.equals(i2));//true
/* -包装类转换为基本类型:------现在不用了*/
int in = i1.intValue();//获取包装类对象中表示的基本类型值
double doub = i1.doubleValue();
System.out.println(in);//123
System.out.println(doub);//123.0
/** JDK5之后----自动拆装箱特性: */
//触发编译器自动装箱特性:
Integer it = 5;//会被编译为:Integer i1 = Integer.valueOf(5);
//触发编译器自动拆箱特性:
int ii = it;//会被编译为:int ii = i1.intValue();
//————————>自动装箱时是由编译器默认调用Integer.valueOf()方法!
//————————>对valueOf()方法有一个优化,若数字为-128~127之间的,则复用
Integer aa = 100;//自动装箱,aa是一个对象
Integer bb = 100;//自动装箱,因值在-128~127之间,所以复用了aa对象
System.out.println(aa==bb);//true,因为复用了100那个对象
Integer a = 200;//自动装箱,a是一个对象(因为Integer是一个引用类型)
Integer b = 200;//自动装箱,b是一个对象,但数据不在应用范围内,所以b是另一个对象
int c = 200;//没有装箱
System.out.println(a==b); //false,因为这两个对象的地址不同
System.out.println(a==c); //true,Integer和int对比时,Integer会自动拆箱为int类型
/** 包装类的常用功能: */
//(1)可以通过包装类来得到基本类型的取值范围:
int max = Integer.MAX_VALUE;//获取int最大值
int min = Integer.MIN_VALUE;//获取int最小值
System.out.println(max);//2147483647
System.out.println(min);//-2147483648
Long max1 = Long.MAX_VALUE;
Long min1 = Long.MIN_VALUE;
System.out.println(max1);//9223372036854775807
System.out.println(min1);//-9223372036854775808
//(2)包装类提供了一个静态方法【parse(byte/int...)(引用)】,可以将字符串转换为对应的基本类型
//前提是该字符串正确表达了基本类型的值
//若不能正确表达,则发生NumberFormatException数字转换异常:
/*
String str = "123.456";//--------int不能正确表达【123.456】这个值,所以报数字转换异常
int num = Integer.parseInt(str);
System.out.println(num);//NumberFormatException---报异常了
*/
String str1 = "123";
int num1 = Integer.parseInt(str1);//将字符串str转换为int类型
System.out.println(num1);//123-------由字符串转为了int型的【123】
str1 = "123.456";
double dou = Double.parseDouble(str1);
System.out.println(dou);//123.456
}
}
精华笔记:
1、正则表达式:
正则表达式是用来描述字符串内容格式,使用它通常用来匹配一个字符串的内容是否符合要求
正则表达式的语法:-----------了解、不用纠结、不用深入研究
String支持与正则表达式相关的方法:
matches():使用给定的正则表达式验证当前字符串的格式是否符合要求
split():将当前字符串按照满足正则表达式的部分进行拆分
replaceAll():将当前字符串中满足正则表达式的部分替换为给定的字符串
2、Object:对象/东西
1.是所有类的鼻祖,所有类都直接或间接继承了Object,万物皆对象,为了多态
2.Object中有几个经常被派生类重写的方法: toString()和equals()
调用toString()时默认返回: 类的全称@地址,没有参考意义,所以常常重写toString()返回具体数据
调用equals()时默认比较的还是==(即比较地址),没有参考意义,所以常常重写equals()来比较具体的属性值
需要注意:java提供的类都已经重写equals()了(String、StringBuilder),但我们自己定义的类中必须自己重写equals()后再去调用equals()比较的内容才会相等,
派生类重写equals()的基本规则:
1)两个对象必须是同一个类型,若类型不同则返回false
2)若参数对象为null,则返回false
3)原则上两个对象要比较对象的属性是否是相同
3、包装类:
1.java定义了8个包装类,目的是为了解决基本类型不能直接参与面向对象开发的问题,
使得基本类型可以通过包装类的实例以对象的方式存在
2.包括:Integer、Character、Byte、Short、Long、Float、Double、Boolean。
其中Character和Boolean是直接继承自Object的,而其余6个包装类都继承自java.lang.Number
3.JDK1.5推出了一个新的特性:自动拆装箱,该特性是编译器认可以,当编译器编译时若发现有基本类型与
包装类型相互赋值时,将会自动补充代码来完成他们的转换工作,这个过程称为自动拆装箱
||
- 1、File类 :
01.创建一个新文件----------createNewFile()方法,可以创建一个新文件
02.删除一个文件---------------delete()方法可以将File表示的文件删除
03.创建目录
04.删除目录-------------delete()方法可以删除一个目录,但是只能删除空目录。
05.访问一个目录中的所有子项
06.获取目录中符合特定条件的子项 - 2、使用递归操作删除一个目录
- 3、Lambda表达式
1、File类:——>java.io.(File):(io:input输入 output:输出)
File类:——————>java.io.(File):(io:input输入 output:输出)
(1)File表示的是硬盘上的:文件/目录/抽象路径_.
(2)File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径)
1、使用File可以做到:
01.访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等
(1)获取文件名:getName()
(2)获取长度(单位是字节):long length()
注:Java中(1个字母2个字节);写在文件中(1个字母1个字节;1个文字3个字节:1个原始字节信息+2个长度信息)
(3)是否可读/写:boolean canRead/canWrite() 注:返回boolean型
(4)是否隐藏:boolean isHidden()
02.创建和删除文件
(1)创建一个新文件:createNewFile()———>先判断是否存在:boolean exists(),若不存在则创建
(2)删除一个文件:delete()————————————>先判断是否存在:boolean exists(),若存在则删除
03.创建和删除目录———————————>注:mkdir是Linux中的一条命令
(1)①创建一个目录:mkdir() 注:前提是创建目录的上一级必须存在;否则只会显示创建成功实际却没有创建-----所以不常用
②创建一个目录:mkdirs() 注:创建目录时会将路径上所有不存在的目录一同创建
(2)①删除一个目录:delete() 注:删除目录时为空目录才可以被删除;但可以逐级删除
04.访问一个目录中的子项:———————>注:要想访问首先要获取当前目录(".")
(1)列出当前目录的所有子项:File[] listFiles() 注:返回的数组中每个File元素表示其中的一个子项
注:首先要判断该File是一个文件【boolean isFile()】还是目录【boolean isDirectory()】
再用遍历来返回每一个子项
05.获取目录中符合特定条件的子项:File[] listFiles(FileFilter filter)———>匿名内部类的方式————回调模式
说明:该方法是用于抽象路径名的文件过滤器;会将该目录中每一个子项都作为参数先传给
filter的accept()方法,只有accept()返回为true的子项最终才会被包含在返回的File[]数组中进行返回。
注:File重载的方法 listFiles方法,允许我们传入一个文件过滤器从而可以有条件的获取一个目录中的子项。
06.注:!!!File的API——————>不能访问文件中的具体内容
package apiday.day03_chuanqi.file;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
/**
* File类:——————>java.io.(File):(io:input输入 output:输出)
* (1)File表示的是硬盘上的:文件/目录/抽象路径_.
* (2)File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径)
*
* 1、使用File可以做到:
* 01.访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等
* (1)获取文件名:getName()
* (2)获取长度(单位是字节):long length()
* 注:Java中(1个字母2个字节);写在文件中(1个字母1个字节;1个文字3个字节:1个原始字节信息+2个长度信息)
* (3)是否可读/写:boolean canRead/canWrite() 注:返回boolean型
* (4)是否隐藏:boolean isHidden()
*
* 02.创建和删除文件
* (1)创建一个新文件:createNewFile()—————>先判断是否存在:boolean exists(),若不存在则创建
* (2)删除一个文件:delete()————————————>先判断是否存在:boolean exists(),若存在则删除
*
* 03.创建和删除目录————————————>注:mkdir是Linux中的一条命令
* (1)①创建一个目录:mkdir() 注:前提是创建目录的上一级必须存在;否则只会显示创建成功实际却没有创建-----所以不常用
* ②创建一个目录:mkdirs() 注:创建目录时会将路径上所有不存在的目录一同创建
* (2)①删除一个目录:delete() 注:删除目录时为空目录才可以被删除;但可以逐级删除
*
* 04.访问一个目录中的子项:——————>注:要想访问首先要获取当前目录(".")
* (1)列出当前目录的所有子项:File[] listFiles() 注:返回的数组中每个File元素表示其中的一个子项
* 注:首先要判断该File是一个文件【boolean isFile()】还是目录【boolean isDirectory()】
* 再用遍历来返回每一个子项
*
* 05.获取目录中符合特定条件的子项:File[] listFiles(FileFilter filter)———————>匿名内部类的方式————回调模式
* 说明:该方法是用于抽象路径名的文件过滤器;会将该目录中每一个子项都作为参数先传给
* filter的accept()方法,只有accept()返回为true的子项最终才会被包含在返回的File[]数组中进行返回。
* 注:File重载的方法 listFiles方法,允许我们传入一个文件过滤器从而可以有条件的获取一个目录中的子项。
*
* 06.注:!!!File的API——————>不能访问文件中的具体内容
*
*/
public class FileDemo {
public static void main(String[] args) throws IOException {
/** 1、01.使用File访问当前项目目录下的demo.txt文件 */
/*
实际开发中我们不会使用绝对路径。虽然清晰明了,但是不利于跨平台。
"./"是相对路径:表示当前目录;该目录就是【当前程序所在的项目目录】
*/
//(1)获取文件名:getname()
//例:在项目名下创建一个文件test包含demo.txt文件
// File file = new File("F:/danei/softone/Java/CGB2202/test/demo.txt");//绝对路径
File file = new File("./test/demo.txt");//相对路径
String name = file.getName();
System.out.println("文件名:"+name);//文件名:demo.txt
//(2)获取长度(单位是字节):long length()————————————————>注:返回的是long值,因为int最大值无法表示一个文件的最大容量
long length = file.length();
System.out.println("长度是:"+length+"字节");//长度是:18字节
/*
//注:Java中(1个字母2个字节);写在文件中(1个字母1个字节;1个文字3个字节:1个原始字节信息+2个长度信息)
int s = '你';
System.out.println(s);//20320 4 f 6 0
System.out.println(Integer.toBinaryString(s));//100 1111 0110 0000
int a = 0b100111101100000;
System.out.println("转为10进制是:"+a);//转为10进制是:20320
String s1 = "a";
System.out.println("长度是"+s1.length()+"字节");//长度是1字节
*/
//(3)是否可读/写:boolean canRead/canWrite()
boolean cr = file.canRead();
boolean cw = file.canWrite();
System.out.println("可读:"+cr);//可读:true
System.out.println("可写"+cw);//可写true-----如果在demo.txt文件右键属性勾成只读,那么输出:可写:flase
//(4)是否隐藏:boolean isHidden()
boolean hidden = file.isHidden();//hidden:隐藏
System.out.println("是否隐藏:"+hidden);//是否隐藏:false
/** 02.创建和删除文件 */
//①创建一个新文件:createNewFile()————>先判断是否存在:boolean exists(),若不存在则创建
File f = new File("./test/demo2.txt");
if(f.exists()){//exists:存在<——————判断当前File表示的文件或目录是否真实存在,存在则返回true。
System.out.println("已存在");
}else{
f.createNewFile();//会爆红——————>因为createNewFile()底层需要抛出异常,按alt+enter再回车
System.out.println("该文件已创建!");
}
//②删除一个文件:delete()————————————>先判断是否存在:boolean exists(),若存在则删除
if(f.exists()){
f.delete();
System.out.println("该文件已删除!");
}else{
System.out.println("该文件不存在");
}
/** 03.创建和删除目录 */
//(1)①创建一个目录:mkdir() 注:前提是创建目录的上一级必须存在;否则只会显示创建成功实际却没有创建
//例:在当前目录下创建一个目录:demo
// File dir = new File("./test/demo");//———————————————>会创建成功
File dir = new File("./a/test/demo");//——————>只会显示创建成功实际却没有创建
if(dir.exists()){
System.out.println("该目录已存在");
}else{
dir.mkdir();//①
System.out.println("该目录已创建");//此时./(项目名下的路径)已经创建一个demo的目录(文件夹)
}
//(1)②创建一个目录:mkdirs() 注:创建目录时会将路径上所有不存在的目录一同创建
File dir1 = new File("./test/a/demo");//——————>创建目录时会将路径上所有不存在的目录一同创建
if(dir1.exists()){
System.out.println("该目录已存在");
}else{
dir1.mkdirs();//②
System.out.println("该目录已创建");//此时【./a/test/demo】下创建一个demo的目录(文件夹)
}
//(2)①删除一个目录:delete() 注:删除目录时为空目录才可以被删除;但可以逐级删除
// File dir2 = new File("./test");//————————————————>注:删除目录时为空目录才可以被删除
File dir2 = new File("./test/a/demo");//——>注:但可以逐级删除,此时 a目录下的demo已经被删除
if(dir2.exists()){
//删除目录时只有空目录可以被删除
dir2.delete();
System.out.println("该目录已删除");
}else{
System.out.println("该目录不存在");
}
/** 04.访问一个目录的所有子项 注:要想访问首先要获取当前目录(".") */
//(1)列出当前目录的所有子项:File[] listFiles() 首先要判断是一个文件【boolean isFile()】还是目录【boolean isDirectory()】
File dir3 = new File(".");//列出“.”当前目录(即项目名)下的子项
// File dir3 = new File("./test");//列出“./test”目录下的子项
/*
判断当前File表示的是否为一个文件:boolean isFile()
判断当前File表示的是否为一个目录:boolean isDirectory()
*/
if(dir3.isDirectory()) {
File[] subs = dir3.listFiles();
System.out.println("该“.”目录有"+subs.length+"个子项");//该“.”目录有6个子项
for (int i = 0; i < subs.length; i++) {
File sub = subs[i];
System.out.println("这个目录的子项有:"+sub.getName());//这个目录的子项有:.git .idea......
}
}
/** 05.获取目录中符合特定条件的子项:File[] listFiles(FileFilter filter)————————>回调模式 */
/* 注:File重载的方法 listFiles方法,允许我们传入一个文件过滤器从而可以有条件的获取一个目录中的子项。*/
/*
方法说明:
该方法会将该目录中每一个子项都作为参数先传给filter的accept()方法,
只有accept()返回为true的子项最终才会被包含在返回的File[]数组中进行返回。
*/
//例1:获取当前目录中含有字母“o”的所有子项:
File dir4 = new File(".");
if(dir4.isDirectory()) {
FileFilter filter = new FileFilter() { //FileFilter(文件过滤器)-------只用一次就写成匿名内部类!!!
@Override
public boolean accept(File file) {
System.out.println("正在过滤:"+file.getName());//正则过滤:.git .idea out ......
return file.getName().contains("o");//含有o就返回true contains:包含
}
};
File[] s = dir4.listFiles(filter);
System.out.println("共有子项:" + s.length + "个");//共有子项:1个
for (int i = 0; i < s.length; i++) {
System.out.println("当前目录中含有字母“o”的子项为:"+s[i].getName());//当前目录中含有字母“o”的子项为:out
}
}
//例2:获取【./src/apiday】目录下所有名字“d”开头的子项
File dir5 = new File("./src/apiday");
if(dir5.isDirectory()){
FileFilter filter = new FileFilter() {//第一步:定义一个文件过滤器
@Override
public boolean accept(File file1) {//第三步:定义一个过滤器的规则
System.out.println("正在过滤元素:"+file1.getName());//第四步
return file1.getName().contains("d");
}
};
File[] s1 = dir5.listFiles(filter);//第二步:把这个过滤器传入File数组
System.out.println("共有子项:" + s1.length + "个");//第五步:共有子项:4个
for(int i=0;i<s1.length;i++){
//第六步:当前目录中含有字母“d”的子项为:day01 day02 ...
System.out.println("当前目录中含有字母“d”的子项为:"+s1[i].getName());
}
}
}
}
2、使用递归操作删除一个目录
- 循环是重复执行某个步骤,而递归是重复整个过程。
package IVdayfile;
import java.io.File;
/**
* 编写一个程序,要求实现1+2+3+4+....100并输出结果。
* 代码中不能出现for,while关键字
*
* 编写程序计算:
* 一个人买汽水,1块钱1瓶汽水。3个瓶盖可以换一瓶汽水,2个空瓶可以换一瓶汽水。不考虑赊账问题
* 问20块钱可以最终得到多少瓶汽水。
*
* 删除一个多级目录
*/
public class VdayTest {
public static void main(String[] args) {
File dir = new File("./a");
delete(dir);
}
/**
* 将给定的File对象表示的文件或目录删除:
* @param file
*/
public static void delete(File file){
if(file.isDirectory()){
//清空目录:
File[] subs = file.listFiles();//列出该文件
for(int i=0;i< subs.length;i++){
File sub = subs[i];//从目录中获取一个子项
//将该子项删除:
delete(sub);//递归调用:在一个方法的内部,调用自己的方法(循环整个过程) 而循环是重复步骤
}
}
file.delete();
}
}
3、lambda表达式:———>JDK8之后,java支持了lambda表达式这个特性
lambda表达式:————————————>JDK8之后,java支持了lambda表达式这个特性。
lambda可以使得程序员面向函数式编程
(1)lambda表达式就是一个代码块,以及必须传入代码的变量规范。
(2)lambda可以用更精简的代码创建匿名内部类.但是该匿名内部类实现的接口只能有一个抽象方法,否则无法使用!
(3)lambda表达式是编译器认可的,最终会将其改为内部类编译到.class文件中
1、语法:
(参数列表)->{
//方法体
}
2、lambda表达式精简在哪?
(1)省去了接口名和方法名
(2)参数类型也可以省略,如果方法只有一个参数时,那么参数的"()"也可以忽略
(3)!如果方法体只有一句代码,那么可以将方法体"{}"忽略,如果含有return关键字则要一同忽略
package apiday.day03_chuanqi.lambda;
import java.io.File;
import java.io.FileFilter;
/**
* lambda表达式:————————————>JDK8之后,java支持了lambda表达式这个特性。
* lambda可以使得程序员面向函数式编程
* (1)lambda表达式就是一个代码块,以及必须传入代码的变量规范。
* (1)lambda可以用更精简的代码创建匿名内部类.但是该匿名内部类实现的接口只能有一个抽象方法,否则无法使用!
* (2)lambda表达式是编译器认可的,最终会将其改为内部类编译到.class文件中
*
* 1、语法:
* (参数列表)->{
* //方法体
* }
*
* 2、lambda表达式精简在哪?
* (1)省去了接口名和方法名
* (2)参数类型也可以省略,如果方法只有一个参数时,那么参数的"()"也可以忽略
* (3)!如果方法体只有一句代码,那么可以将方法体"{}"忽略,如果含有return关键字则要一同忽略
*
*/
public class LambdaDemo {
public static void main(String[] args) {
//例1:匿名内部类形式创建FileFilter文件过滤器:
FileFilter filter = new FileFilter() { //FileFilter():为接口名
public boolean accept(File file) {
return file.getName().contains("o");
}
};
/** 如上:用lambda精简上边的代码: */
//(1)省去了接口名和方法名
FileFilter filter1 = (File file) ->{
return file.getName().contains("o");
};
//(2)参数类型也可以省略,如果方法只有一个参数时,那么参数的"()"也可以忽略
FileFilter filter2 = file ->{
return file.getName().contains("o");
};
//(3)!如果方法体只有一句代码,那么可以将方法体"{}"忽略,如果含有return关键字则要一同忽略
FileFilter filter3 = file -> file.getName().contains("o");
//例2:
File dir = new File(".");
FileFilter fileFilter = new FileFilter() {
public boolean accept(File file) {
return file.getName().contains("o");
}
};
File[] sub = dir.listFiles(fileFilter);
//(1)如上进一步精简成:
File dir1 = new File(".");
FileFilter fileFilter1 = file -> file.getName().contains("o");
File[] sub1 = dir1.listFiles(fileFilter);
//(2)如上再进一步精简成:
//lambda表达式也是编译器认可的,最终会被编译器改回成内部类创建的形式:
File dir2 = new File(".");
File[] subs = dir2.listFiles(file->file.getName().contains("o"));
}
}
更多推荐
SE API第三四天:正则、String支持与正则相关3个方法、Object类(toString与equals)、包装类、 || File类、递归(循环)、La
发布评论