泛型:
定义:将明确的集合类型的工作推迟到了创建对象或者调用方法的时候,属于一种参数化类型,可以作为参数传递;
原因:数组直接定义了存储的类型,防止出现其他的类型的元素,集合也像数组一样,直接规定集合的数据类型,针对这种情况,诞生除了泛型这个概念 ===> 泛型的引出可以提供程序的安全性;
泛型的好处:
1> 将运行时期异常提前到了编译时期;
2> 优化了设计,解决了黄色警告线问题;
3> 避免了强制类型转换;
举例:
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo {
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)) ; //已经定了当前集合时String类型
//遍历
//获取迭代器
Iterator<String> it = array.iterator() ;
while(it.hasNext()) {
//java.lang.ClassCastException:类转换异常
String s = it.next() ; //这里不需要强制类型转换,因为已经定义了集合的类型树String类型
System.out.println(s);
}
}
}
ArrayList集合存储自定义类型的对象,并遍历:
举例:
package org.westos_01;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
/**
* 使用ArrayList集合存储自定义对象并遍历,加入泛型
* @author Administrator
*
*/
class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 class GenericDemo2 {
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());
}
}
}
Object中的泛型:
在早期的时候,使用Object类型代表任意类型,向上转型没有问题,使用向下转型的时候,可能会出现问题(需要的类型有问题),这个时候就需要引入泛型操作;
举例:
class ObjectTool<T> { //T表示可以接受的数据类型为任意类型
private T obj ;
public T getObj() {
return obj ;
}
public void setObj(T obj) {
this.obj = obj ;
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
//创建ObjectTool对象
ObjectTool<String> ot = new ObjectTool<String>() ;
//赋值
ot.setObj(new String("高圆圆"));
String s = ot.getObj() ;
System.out.println("姓名是:"+s);
//ot.setObj(new Integer(27)); 直接隐藏的问题解决了
System.out.println("---------------");
ObjectTool<Integer> ot2 = new ObjectTool<Integer>() ;
ot2.setObj(new Integer(27));
//ot2.setObj(new String("高圆圆"));
Integer i = ot2.getObj() ;
System.out.println("年龄是:"+i);
}
}
方法中也可以定义泛型:
public class ObjectTool{
//泛型是可以在方法上定义的
public <T> void show(T t) { //泛型的参数为任意类型
System.out.println(t);
}
}
泛型在接口中:
两种情况:
//将泛型定义在接口上
public interface Inter<T> {
//接口中变量是常量: public static final int num ;
public abstract void show() ; //抽象方法
}
//接口中泛型,子实现类的第一种情况,就是已经知道是什么类型了
public class InterImpl implements Inter<String> {
@Override
public void show() {
System.out.println("hello");
}
}
//第二种情况,就是不知道具体的类型是什么
public class Inter2Impl<T> implements Inter<T>{
@Override
public void show() {
System.out.println("hello");
}
}
//测试类
public class InterDemo {
public static void main(String[] args) {
//第一种情况的测试
//创建接口的子实现类对象
Inter<String> i = new InterImpl() ; //第一种因为定义了String类型,所以只能用String的类型实现
i.show();
System.out.println("---------------------");
//第二种情况的测试
Inter<Integer> i2 = new Inter2Impl<Integer>(); //第二种可以使用任何累心进行定义
i2.show() ;
Inter<String> i3 = new Inter2Impl<String>() ;
i3.show();
}
}
泛型高级(通配符):
<?>:代表任意类型Object类型,或者任意的Java类;
<? extends E>:向下限定,E的子类或者E这个类型;
<? super E>:向上限定,E及其他的父类;
举例:
import java.util.ArrayList;
import java.util.Collection;
class Animal{
}
class Cat extends Animal {
}
class Dog extends Animal{
}
public class GenericDemo {
public static void main(String[] args) {
//创建集合对象,泛型如果明确的情况下,前后必须保持一致
//Collection<Object> c2 = new ArrayList<Cat>() ; 会报错
//Collection<Object> c3 = new ArrayList<Animal>() ; 会报错
Collection<Object> c1 = new ArrayList<Object>() ;
//<?>:代表任意类型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 Aninal> c11 = new ArrayList<Object>() ; 会报错
Collection<? extends Object> c8 = new ArrayList<Object>() ;
Collection<? extends Object> c9 = new ArrayList<Animal>() ;
Collection<? extends Object> c10 = new ArrayList<Cat>() ;
//<? super E>:向上限定,E及其他的父类
//Collection<? super Animal> c12 = new ArrayList<Cat>() ; 会报错
Collection<? super Animal> c13 = new ArrayList<Animal>() ;
Collection<? super Animal> c14 = new ArrayList<Object>() ;
}
}
JDK5以后的新特性:
增强for循环:格式:
for(数据大类型 变量名 : 数组或者集合对象名){
输出变量即可;
}
作用:
增强for的出现是替代迭代器的,所以在遍历集合或者遍历数组就可以使用增强for去完成;
增强for循环的弊端:
如果集合的对象是null,如果再次对集合操作,就会出现异常;
解决:对集合进行判断,非空判断解决;
举例:
public class ForDemo {
public static void main(String[] args) {
//定义一个数组,静态初始化
int[] arr = {11,22,33,44,55} ;
//正常的方式,普通for循环
for(int x = 0 ; x < arr.length ; x ++) {
System.out.println(arr[x]);
}
System.out.println("---------------------");
//增强for循环
for(int a :arr) {
System.out.println(a);
}
//定义一个字符串类型的数组
String[] str = {"hello","world","java","javaee"} ;
//增强for
for(String s : str) {
System.out.println(s);
}
System.out.println("-------------------------");
//创建一个集合
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 = null ;
//NullPointerException:如果集合为空遍历的话会报异常
//解决方法:给集合进行非空判断
if(list !=null) {
for(String s:list) {
System.out.println(s);
}
}
}
}
静态导入:
特点:
1> 前提是该方法必须是静态的;
2> 导入到的一个方法的级别;
静态导入的格式:
import static 包名 . 类名 . 方法名; ==> 方法必须是静态方法;
之前学习的导包:java.util.Scanner; 导入到类的级别;
举例:
import static java.lang.Math.abs; //导入到方法的级别
import static java.lang.Math.pow;
public class ImportStaticDemo {
public static void main(String[] args) {
System.out.println(Math.abs(-100));
System.out.println(Math.pow(2,3));
//可以使用带前缀的方式
System.out.println(java.lang.Math.abs(-100));
System.out.println("-------------------------");
//在测试,直接写方法名,前提静态导入
//System.out.println(abs(-100));
System.out.println(java.lang.Math.abs(-100));
System.out.println(pow(2,3));
//本身当前的某个类中的方法名和需要被静态导入的方法名一样,必须加上前缀
}
//Date ---->有两个包下 java.util.Date java.sql.Date
}
可变参数:
当一个方法的参数个数不确定的时候,要使用可变参数;
格式:
修饰符 返回值类型 方法名(数据类型 . . . 变量名){...}
注意:
1> 变量名:看成一个数组;
2> 使用的时候数据类型;
举例:
public class ArgsDemo {
public static void main(String[] args) {
int a = 10 ;
int b = 20 ;
int c = 30 ;
int d = 40 ;
//当我们的参数不确定的情况下,就可以使用jdk5一个特性:可变参数
System.out.println(sum(a,b,c,d,50));
}
//定义一个参数不确定的方法,通过可变参数操作
public static int sum(int...a) { //将a看成一个数组的形式
//求和:将a是多个参数的,看成数组
//先定义最终结果变量
int result = 0 ;
//增强for遍历可变参数a
for(int n :a) {
result += n ;
}
return result;
}
}
ArrayList集合存储自定义对象并遍历:
举例:
package org.westos_01;
import java.util.ArrayList;
import java.util.Iterator;
/**
*
* ArrayList集合存储自定义对象并遍历,有几种方式?
* Iterator iterator() ;
* listIterator listiterator();(可以不写)
* 普通for循环:size()/get(int index)
* 增强for循环
*/
public class ArrayListTest {
public static void main(String[] args) {
//创建ArrayList集合
ArrayList<Student> array = new ArrayList<Student>() ;
//创建学生对象
Student s1 = new Student("张三", 20) ;
Student s2 = new Student("李四", 19) ;
Student s3 = new Student("王五", 22) ;
Student s4 = new Student("赵六", 26) ;
//添加元素
array.add(s1) ;
array.add(s2) ;
array.add(s3) ;
array.add(s4) ;
//方式1:迭代器遍历:Iterator
Iterator<Student> it = array.iterator() ;
while(it.hasNext()) {
Student s = it.next() ;
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("-------------------");
//方式2:普通for
for(int x = 0 ; x < array.size() ; x ++) {
Student s = array.get(x) ;
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("-------------------");
//方式3:增强for循环
for(Student s : array) {
System.out.println(s.getName()+"----"+s.getAge());
}
}
}
针对数组操作的工具类:
Arrays提供了一个方法:
public static <T> List<T> asList(T... a):将数组转换成固定大小的集合;
注意:如果使用此方法,那么集合的长度不可变;
举例:
public class ArraysDemo {
public static void main(String[] args) {
//定义数组:
/*String[] str = {"hello","world","java"} ;
//将数组转换成固定大小的集合
List<String> list = Arrays.asList(str) ;*/
//一步完成
List<String> list = Arrays.asList("hello","world","java") ;
//添加元素
//list.add("javaee") ;// java.lang.UnsupportedOperationException :集合固定的,长度是固定的
//list.remove("world") ;
list.set(1, "javaee"); //将指定位置的元素修改为"javaee"
//增强for
for(String s:list) {
System.out.println(s);
}
}
}
综合练习1:
package org.westos_03;
import java.util.ArrayList;
import java.util.Random;
/**
*
* 需求:求10个1~20之间的随机数,要求数据不能重复 set集合
*
*分析:
* 可以使用数组,数组的长度固定,不够好,使用集合去做
*
* 创建一个随机数类对象
* Random
*
* 获取指定的随机数的范围:
* int nextInt() ; 获取的int类型的范围
* int nextInt(int n) ;获取1~n之间的数据 ,[0,n)
*
* 创建一个ArrayList集合对象,元素类型:Integer类型
* 定义统计遍历:count 是从0开始
* 判断如果统计遍历小于10
* 先计算出1-20之间的随机数,还需要判断集合中是否包含这些元素
* 如果不包含,添加,count++
* 包含,重复,不搭理了....
*
* 大于10,不搭理
*
* 遍历即可
*/
public class ArrayListTest {
public static void main(String[] args) {
//创建随机数类对象
Random r = new Random() ;
//创建一个ArrayList集合
ArrayList<Integer> array = new ArrayList<Integer>() ;
//定义统计变量
int count = 0 ;
//判断统计变量的个数
while(count <10) {
//个数符合的情况下,计算出1-20之间的随机数
int number = r.nextInt(20) +1 ;
//需要判断集合总是发包含这个number
if(!array.contains(number)) {
array.add(number) ;
count ++ ;
}
}
//增强for
for(Integer i : array) {
System.out.println(i);
}
}
}
综合练习2:
package org.westos_02;
import java.util.ArrayList;
import java.util.HashSet;
/**
*需求
集合的嵌套遍历
有一个Java基础班,里面有很多学生,把一个班级集合:ArrayList<Student>
不止一个Java基础班,这个时候就定义大集合:ArrayList<ArrayList<Student>>
有三个基础班,分别遍历每一个班里面学生信息:(name,age)
*
*/
class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 class ArrayListTest {
public static void main(String[] args) {
//创建一个大的集合
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>() ;
//创建第一个班的集合对象
ArrayList<Student> firstArray = new ArrayList<Student>() ;
//创建学生对象
Student s1 = new Student("曹操",35) ;//后知后觉
Student s2 = new Student("诸葛亮", 29);//先知先觉
Student s3 = new Student("蒋干", 30) ;//不知不觉
//给第一个班添加元素
firstArray.add(s1) ;
firstArray.add(s2) ;
firstArray.add(s3) ;
//将第一个集合添加到大集合中
bigArrayList.add(firstArray) ;
//创建第二个班集合对象
ArrayList<Student> secondArray = new ArrayList<Student>() ;
Student s11 = new Student("宋江",38) ;
Student s22 = new Student("鲁智深", 29);
Student s33 = new Student("武松", 30) ;
secondArray.add(s11) ;
secondArray.add(s22) ;
secondArray.add(s33) ;
//添加到大集合
bigArrayList.add(secondArray) ;
//创建第三个集合对象
ArrayList<Student> thirdArray = new ArrayList<Student>() ;
Student s111 = new Student("高圆圆",38) ;
Student s222 = new Student("唐嫣", 29);
Student s333 = new Student("刘若英", 30) ;
thirdArray.add(s111) ;
thirdArray.add(s222) ;
thirdArray.add(s333) ;
//添加到集合
bigArrayList.add(thirdArray) ;
//增强for遍历:大集合
for(ArrayList<Student> array: bigArrayList) {
for(Student s:array) {
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
}