以下为本人的学习笔记
1.为什么需要泛型
public class GenericDeom{
@Test
public void test1(){
List list = new ArrayList();
list.add("tste");
list.add(10);
list.add(new Object());
//List中可以添加任意类型,因为参数是Object,这样一个我们在遍历这个集合时:
for(int i = 0;i<list.size();i++){
//如果我们不能确定集合中的元素类型,那么我们需要在处理元素时
//要判断元素的类型,才能做相应的操作
}
}
}
以上操作主要存在两个问题:
1.当我们将一个对象放入集合中,集合不会记住对象的类型,当再次从集合中取出此对象时,改变对象的编译类型变成了Object类型,但其运行时类型仍然为其本身类型。
2.因此,//1处取出集合元素时需要认为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常
那么有没有办法可以是集合能够记住集合中元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型
泛型三种写法:
-
List<String> list = new ArrayList<String>();
-
List<String> list = new ArrayList<>();//JDK1.7以上
-
List<String> list = new ArrayList();
2.什么是泛型
JDK1.5之后出现了新的技术——泛型(Generic),此技术的最大特点是类中的属性的类型可以由外部决定。
泛型又称为参数化类型,是一种编译时类型安全检测机制,类型参数的魅力在于,使得程序具有更好的可读性和安全性。
参数化类型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称为类型形参),然后再使用/调用时传入具体的类型(类型实参)
<E>:不确定参数化类型
3.自定义泛型接口、泛型类
//泛型类
//T,E,K,V:参数化类型,也叫泛型形参,在实际使用时才会指定具体类型
//泛型只是作用于代码编译阶段,编译后会被擦除
public class Node<T>{
private T date;
public Node(){}
public Node(T data){
this.data=data;
}
...//getter和setter
}
//测试方法
public void testNode(){
Node<Number> numberNode = new Node<>();
Node<Integer> intNode = new Node<>();
}
泛型只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段
4.通配符
public void test2(){
Node<Number> n1 = new Node<>(10);
Node<Integer> n2 = new Node<>(20);
getData(n1);
//getData(n2);//尽管两者有继承关系,编译报错,因为方法指定了具体的泛型类型
//n1 = n2 ;//不支持
getData2(n2);//不报错
}
public static void getDate(Node<Number> node){
System.out.println(node.getData());
}
//改进
public static void getDate2(Node<?> node){
// node.setData(20);//会报错,不能修改值。“?”表示可以接收任意的泛型类型,但是只是接收输出,并不能修改
System.out.println(node.getData());
}
“?”表示可以接收任意的泛型类型,但是只是接收输出,并不能修改
所以,使用通配符可以引用其他各种参数化类型,通配符定义的变量主要用作引用,可以调用与参数无关的方法,不能调用与参数有关的方法
泛型上限就指一个的操作泛型最大的操作父类,例如,现在最大的上限设置为“Number”类型,那么此时,所能够接收到的类型只能是Number及其子类(Integer)。
-
语法:?extends类 如:(Node<?extends Number> data)只能是Number类以及其子类
泛型下限就指只能设置其具体的类或者父类。
-
语法: ?super类
注意:?extends类和?super类跟?一样只是接收输出,并不能修改
5.泛型方法
泛型除了在类中定义之外,还可以在方法上定义,而且在方法上使用泛型,此方法所在的类不一定是泛型的操作类
//泛型方法
//例子:交换位置方法
//static 后,返回值类型前,加上泛型
public static <T> T[] func(T[] array,int i,int t){//定义一个返回类型T[]是泛型<T>
T temp = array[i];
array[i] = array[t];
array[t] = temp;
return array;
}
6.泛型的嵌套使用
在使用集合Map的时候,我们可以这样遍历
public void test5(){
Map<Integer,String> map = new HashMap<>();
map.put(1,"ss");
map.put(2."tt");
Set<Map.Entry<Integer,Strig>> entrySet = map.entrySet();
for(Map.Entry entry:entrySet){
System.out.println(entry.getKey()+"-"+entry.getValue());
}
}
7.正则表达式
正则表达式(Regular Expression)使用单个字符串描述、匹配一系列符合某个句法规则的字符串。
正则表达式通常被用来检索、替换那些符合某个模式 的文本
java.util.regex包中提供以下两个类对正则表达式的支持:
Matcher(匹配)类:通过解释Pattern对character sequence执行匹配操作的引擎
Pattern(模式)类:正则表达式的编译表示形式
//eg.如何直到一串字符串是由数字组成
//没有使用正则表达式
public void test1(){
String s = "7894562";
char[] chars = s.toCharArray();
boolean flag = true;
for(int i = 0;i<chars.length;i++){
if(chars[i]<'0' || chars[i]>9){
flag = false;
break;
}
}
if(flag){
System.out.println("是由数字组成");
}else{
System.out.println("不是由数字组成");
}
}
//使用正则表达式
public void test3(){
String s = "7894562";
boolean b = s.matches("[0-9]+");
boolean b1 = s.matches("\\d+");
System.out.println(b+"-"+b1);
}
8.Pattern类
public final class Pattern extends Objectimplements Serializable
正则表达式的编译表示形式。指定为字符串的正则表达式必须首先被编译为此类的实例
典型的调用顺序是
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
public void test2(){
//创建一个匹配模式(模板)
Pattern p = Pattern.compile("a*b");//*代表0到多个a
Matcher matcher = p.matcher("aaaaab");
boolean b = m.matches();//匹配
System.out.println(b);
}
9.Matcher类
public final class Matcherextends Objectimplements MatchResult
Matcher类的主要功能是用于正则的匹配,通过Pattern类中定义完的正则,再使用Matcher类进行验证或者替换
常用方法:
Method | 说明 |
---|---|
boolean matches() | 尝试将整个区域与模式匹配 |
String replaceAll(String replacement) | 替换模式与给定替换字符串相匹配的输入序列的每个子序列 |
String replaceFirst(String replacement) | 替换模式与给定替换字符串相匹配的输入序列的第一个子序列 |
regex参数表示正则表达式的模板
10.String类对正则的支持
JDK1.4加入了正则
Method | 说明 |
---|---|
boolean matches(String regex) | 告知此字符串是否匹配给定的正则表达式 |
String replaceAll(String regex,String replacement) | 使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串 |
String replaceFirst(String regex,String replacement) | 使用给定的replacement替换此字符串所有匹配给定的正则表达式的第一个子字符串 |
String[] split(String regex) | 根据给定正则表达式的匹配拆分此字符串 |
11.正则表达式示例
-
验证电话号码(如:066-98563256)
-
验证手机号码
-
验证用户名,只能是字母开头的数字、字母或下划线的组合
-
验证IP地址(如:192.168.0.1)
-
验证网址(如:http://www.baidu.com)
-
验证年龄(100以内)
-
验证金额(可以有小数位)
public void test(){
//匹配电话号码
String phoneNumber = "010-38389438";
boolean b = phoneNumber.matches("\\d{3,4}-\\d{7,8}");// //d 是数字,{}表示位数,-原意输出
System.out.println(b);
//匹配手机号码
String phone = "17239947985";
System.out.println(phone。matches("[1][3-9]\\d{9}"));//[3-9]表示3到9都可以
//匹配用户名,只能是字母开头的数字、字母或下划线的组合
String username= "abk123";
System.out.println(username.matches("[a-zA-Z]+[\\w|_]*"));//+表示一次或多次,|表示或,\\w表示单词字符
//匹配IP地址
String ip = "20.10.20.123";
System.out.println(ip.matches("\\d{1,3}.d{1,3}.d{1,3}.d{1,3}."));//{1,3}表示1到3位
//匹配网址
String addr = "http://www.baidu.com";
System.out.println(username.matches("[http://\\w+.\\w+.\\S*"));// \\S表示非空白字符
//匹配年龄(100以内)
String age = "19";
System.out.println(username.matches("\\d{1,3}"));
//匹配金额(可以有小数位)
String price = "23.3";
System.out.println(username.matches("\\d+.\\d+"));
}
■免责申明
⒈ 本站是纯粹个人学习网站,与朋友交流共赏,不存在任何商业目的。
⒉ 本站利用了部分网络资源,版权归原作者及网站所有,如果您对本站所载文章及作品版权的归属存有异议,请立即通知我们,我们将在第一时间予以删除,同时向你表示歉意!