以下为本人的学习笔记

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”异常呢?答案就是使用泛型

泛型三种写法:

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类和?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.正则表达式示例

  1. 验证电话号码(如:066-98563256)

  2. 验证手机号码

  3. 验证用户名,只能是字母开头的数字、字母或下划线的组合

  4. 验证IP地址(如:192.168.0.1)

  5. 验证网址(如:http://www.baidu.com

  6. 验证年龄(100以内)

  7. 验证金额(可以有小数位)

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+"));
​
}

■免责申明
⒈ 本站是纯粹个人学习网站,与朋友交流共赏,不存在任何商业目的。
⒉ 本站利用了部分网络资源,版权归原作者及网站所有,如果您对本站所载文章及作品版权的归属存有异议,请立即通知我们,我们将在第一时间予以删除,同时向你表示歉意!

发表回复