1.泛型的引入
[需求]ArrayList集合存储元素并遍历
public static void main(String[] args) {
//创建集合对象
ArrayList<String> array = new ArrayList<String>() ;
//添加元素
array.add("hello") ;
array.add("world") ;
array.add("java") ;
array.add(new Integer(100)) ;
//遍历
//获取迭代器
Iterator<String> it = array.iterator() ;
while(it.hasNext()) {
//java.lang.ClassCastException:类转换异常
String s = (String)it.next() ;
System.out.println(s);
}
}
问题:使用ArrayList集合存储元素遍历的时候,按照正常的操作出现了问题,
当前ArrayList集合中存储了两种类型的元素分别String和Integer类型,在遍历的时候,使用的是String接收的,对于Integer类型就出现了异常!
回想数组:
String[] str = new String[3] ;
str[0] = "hello" ;
str[1] = "world" ;
str[2] = 100 ; 错误的,
数组直接定义了存储的类型,防止出现其他类型的元素,集合能不能也像数组一样,直接规定我们集合的存储类型?
针对这种情况,Java提供了一种技术:泛型
2.泛型的概念
泛型:将明确的集合类型的工作推迟到了创建对象或者调用方法的时候,属于一种参数化类型,可以作为参数传递.
<数据类型> --- 引用数据类型
泛型的好处:
1)将运行时期异常提前到了编译时期
2)优化了设计,解决了黄色警告线问题
3)避免了强制类型转换
4)提高了程序的安全性!
[需求]使用ArrayList集合存储自定义对象并遍历,加入泛型
public static void main(String[] args) {
//创建集合对象
ArrayList<Student> array = new ArrayList<Student>() ; //=号右边的泛型:泛型推断
//创建学生对象
Student s1 = new Student("王昭君",25) ;
Student s2 = new Student("西施",27) ;
Student s3 = new Student("杨贵妃",25) ;
Student s4 = new Student("貂蝉",28) ;
//添加到集合中
array.add(s1) ;
array.add(s2) ;
array.add(s3) ;
array.add(s4) ;
//获取迭代器
Iterator<Student> it = array.iterator() ;
while(it.hasNext()) {
Student s = it.next() ;
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("------------------");
//普通for循环
for(int x = 0 ; x < array.size() ; x ++) {
Student s = array.get(x) ;
System.out.println(s.getName()+"---"+s.getAge());
}
}
3.泛型的应用
1)将泛型定义在类上:解决了向下类型转换出现的问题:ClassCastException
public class ObjectTool<T> {
private T obj ;
public T getObj() {
return obj ;
}
public void setObj(T obj) {
this.obj = obj ;
}
}
//创建ObjectTool对象
ObjectTool<String> ot = new ObjectTool<String>() ;
//赋值
ot.setObj(new String("高圆圆"));
String s = ot.getObj() ;
System.out.println("姓名是:"+s);
2)将泛型定义在方法上
public class ObjectTool{
//泛型是可以在方法上定义的
public <T> void show(T t) {
System.out.println(t);
}
}
//创建ObjectTool类的对象
ObjectTool ot = new ObjectTool() ;
ot.show("hello");
ot.show(true);
ot.show(100);
3)将泛型定义在接口上
//将泛型定义在接口上
public interface Inter<T> {
//接口中变量是常量: public static final int num ;
public abstract void show() ; //抽象方法
}
public static void main(String[] args) {
//第一种情况的测试
//创建接口的子实现类对象
Inter<String> i = new InterImpl() ;
i.show();
System.out.println("---------------------");
//第二种情况
Inter<Integer> i2 = new InterImpl<Integer>();
i2.show() ;
Inter<String> i3 = new InterImpl<String>() ;
i3.show();
}
4.泛型高级(通配符)
-------能看懂就行
<?> :代表任意类型Object类型,或者任意的Java类
<? extends E>:向下限定,E的子类或者E这个类型
<? super E>:向上限定,E及其他的父类
class Animal{
}
class Cat extends Animal {
}
class Dog extends Animal{
}
public static void main(String[] args) {
//创建集合对象,泛型如果明确的情况下,前后必须保持一致
Collection<Object> c1 = new ArrayList<Object>() ;
// Collection<Object> c2 = new ArrayList<Cat>() ;//错误
// Collection<Object> c3 = new ArrayList<Animal>() ;//错误
//<?> :代表任意类型Object类型,或者任意的Java类
Collection<?> c4 = new ArrayList<Object>() ;
Collection<?> c5 = new ArrayList<Animal>() ;
Collection<?> c6 = new ArrayList<Dog>() ;
Collection<?> c7= new ArrayList<Cat>() ;
// <? extends E>:向下限定,E的子类或者E这个类型
Collection<? extends Object> c8 = new ArrayList<Object>() ;
Collection<? extends Object> c9 = new ArrayList<Animal>() ;
Collection<? extends Object> c10 = new ArrayList<Cat>() ;
// Collection<? extends Aninal> c11 = new ArrayList<Object>() ;//错误
// <? super E>:向上限定,E及其他的父类
// Collection<? super Animal> c12 = new ArrayList<Cat>() ;//错误
Collection<? super Animal> c13 = new ArrayList<Animal>() ;
Collection<? super Animal> c14 = new ArrayList<Object>() ;
}
5.Jdk5以后的新特性
增强for,静态导入,可变参数,泛型,自动拆装箱...
(1)增强for
1)增强for循环的格式
for(数据大类型 变量名 : 数组或者集合对象名){
输出变量即可!
}
//定义一个字符串类型的数组
String[] str = {"hello","world","java","javaee"} ;
//直接增强for
for(String s : str) {
System.out.println(s);
}
//创建一个集合
List<String> list = new ArrayList<String>() ;
list.add("hello") ;
list.add("world") ;
list.add("java") ;
//直接增强for
for(String s:list) {
System.out.println(s);
}
[注意]
对上述集合,遍历list集合,判断如果有"world"元素,给集合添加一个元素(javaee)
//遍历list集合,判断如果有"world"元素,给集合添加一个元素(javaee)
for(String s: list) { //使用size()和get(int index)相结合...
//java.util.ConcurrentModificationException :并发修改异常
//增强for的出现就是用来替代迭代器的!
if("world".equals(s)) {
list.add("javaee");
}
}
发现:出现了java.util.ConcurrentModificationException :并发修改异常
增强for的出现时替代迭代器的,所以在遍历集合或者遍历数组就可以使用增强for去完成
解决方法:使用普通for循环遍历,使用size()和get(int index)相结合...
2)增强for循环的弊端
如果集合的对象是null,如果再次对集合操作,就会出现NullPointerException异常
解决方法:对集合进行判断,非空判断解决
if(list !=null) {
for(String s:list) {
System.out.println(s);
}
}
(2)静态导入
1)特点:
1)前提是该方法必须是静态的
2)导入到的一个方法的级别
2)静态导入的格式:
import static 包名.类名.方法名;
import static java.lang.Math.abs; //导入到方法的级别
import static java.lang.Math.pow;
public static void main(String[] args) {
//在测试,直接写方法名,前提静态导入
System.out.println(abs(-100));
System.out.println(pow(2,3));
}
[注意]如果本身当前的某个类中的方法名和需要被静态导入的方法名一样,必须加上前缀
import static java.lang.Math.abs; //导入到方法的级别
import static java.lang.Math.pow;
public class ImportStaticDemo {
public static void main(String[] args) {
System.out.println(java.lang.Math.abs(-100));
//本身当前的某个类中的方法名和需要被静态导入的方法名一样,必须加上前缀
}
public static void abs() {
}
}
(3)可变参数
1)可变参数:当一个方法的参数个数不确定的时候,要使用可变参数
2) 格式:
修饰符 返回值类型 方法名(数据类型...变量名){...}
3)注意:
* 1)变量名:看成一个数组
* 2)使用的时候数据类型后面是3个点...
[需求]求数据之和
public class ArgsDemo {
public static void main(String[] args) {
//当我们的参数不确定的情况下,就可以使用jdk5一个特性:可变参数
System.out.println(sum(10,20,30,40,50));
}
//定义一个参数不确定的方法,通过可变参数操作
public static int sum(int...a) {
//求和:将a是多个参数的,看成数组
//先定义最终结果变量
int result = 0 ;
//增强for遍历可变参数a
for(int n :a) {
result += n ;
}
return result;
}
}
(4)针对数组操作的工具类:Arrays,提供了一个方法:
public static <T> List<T> asList(T... a) :将数组转换成固定大小的集合
public static void main(String[] args) {
//定义数组:
String[] str = {"hello","world","java"} ;
//将数组转换成固定大小的集合
List<String> list = Arrays.asList(str) ;
//增强for
for(String s:list) {
System.out.println(s);
}
}
[注意]如果使用此方法,那么集合的长度不可变!