一、基本概念
概念:泛型就是参数化类型,使用广泛的类型。
起因:数据类型不明确。
装入数据的类型都被当作Object对待,从而”丢失”自己的实际类型。
获取数据时往往需要转型,效率低,容易产生错误。
作用:
安全:在编译的时候检查类型安全。
省心:所有的强制转换都是自动和隐式的,提高代码的重用率。
二、未使用泛型
package Genericity;
public class Student {
private Object englishScore;
private Object mathsScore;
public Object getEnglishScore() {
return englishScore;
}
public void setEnglishScore(Object englishScore) {
this.englishScore = englishScore;
}
public Object getMathsScore() {
return mathsScore;
}
public void setMathsScore(Object mathsScore) {
this.mathsScore = mathsScore;
}
public Student(Object englishScore, Object mathsScore) {
super();
this.englishScore = englishScore;
this.mathsScore = mathsScore;
}
public Student() {
super();
}
}
package Genericity;
/**
* 获取值:
* 1、强制类型转换
* 2、手动类型检查:避免转换错误 java.lang.ClassCaseException
* @author liguodong
*
*/
public class Demo01 {
public static void main(String[] args) {
Object obj=80;
//JDK6以前 Object-->Integer-->自动拆箱
int score01 = (Integer)obj;
//JDK7 以后 Object-->Integer-->自动拆箱
int score02 = (int)obj;
System.out.println("score01:"+score01+",\nscore02:"+score02+"。");
//存入整数:int-->Integer-->Object
Student stu = new Student(80,90);
int engScore = (Integer)stu.getEnglishScore();
String mathsScore = null;
if(stu.getMathsScore() instanceof String){
mathsScore = (String) stu.getMathsScore();
}
System.out.println("English分数为:"+engScore+",\nMaths分数为:"+mathsScore+"。");
}
}
运行结果:
score01:80,
score02:80。
English分数为:80,
Maths分数为:null。
三、自定义泛型
1.泛型类
package Genericity;
/**
*
* 泛型类:声明时使用泛型
* 字母:
* T 表示类型Type。
* K V分别代表键值中的Key Value。
* E 代表Element。
*
* 使用时确定类型
* 注意泛型只能是引用类型,不能使基本类型。
* 泛型声明时 不能使用在静态类型或静态方法上。
*
* @author liguodong
*
* @param <T>
*/
public class Student<T1,T2> {
private T1 id;
private T2 name;
public T1 getId() {
return id;
}
public void setId(T1 id) {
this.id = id;
}
public T2 getName() {
return name;
}
public void setName(T2 name) {
this.name = name;
}
public Student(T1 id, T2 name) {
super();
this.id = id;
this.name = name;
}
public Student() {
}
public static void main(String[] args) {
//使用时指定类型(引用类型)
Student<Integer, String> student01 = new Student<Integer, String>(1001, "德玛西亚");
Student<Integer,String> student02 = new Student<>();
//1、安全:类型检查(编译时)
student02.setId(1003);
student02.setName("堕落天使");
//2、省心:类型转换
int id = student01.getId();//自动拆箱
System.out.println(id);//1001
}
}
2.泛型接口
package Genericity;
/**
* 接口中泛型类型字母只能使用在方法中,不能使用在全局变量中
* @author liguodong
*
* @param <T>
*/
public interface Comparator<T> {
//T a = 2; xxx java接口中属性:final static
void compare(T t);
}
3.泛型方法
package Genericity;
import java.io.Closeable;
/**
* 泛型方法<> 返回类型前面
* 只能访问对象的信息,不能修改信息。
* @author liguodong
*
*/
public class Method {
//泛型方法
public static <T> void test(T t)
{
System.out.println(t);
}
//extends <= T...表示可变参数
public static <T extends Closeable> void test(T... t)
{
System.out.println(t);
for (T temp : t) {
try {
if(null != temp){
temp.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
test("df");//T-->String //df
}
}
4.泛型继承擦除
package Genericity;
/**
* 父类为泛型类
* 1.属性
* 2.方法
* 要么同时擦除,要么子类大于父类的类型
* 不能子类擦除,父类泛型
* 1.属性类型
* 在父类中,随父类而定
* 在子类中,随子类而定
* 2.方法重写
* 全部随父类而定
* */
public abstract class Father<T,T1>
{
T t;
public abstract void test(T t);
}
/**
* 子类声明时指定具体类型
* 属性类型为具体类型
* 方法类型也为具体类型
*/
class Child1 extends Father<String,Integer>
{
Integer t1;
@Override
public void test(String t1){
this.t = t1;//t->String
this.t1 = 100; //t1->int
}
}
/**
* 子类为泛型,类型在使用时确定
* 要么同时擦除,要么子类大于父类的类型(顺序可以交换)
*/
class Child2<T1,T> extends Father<T,T1>
{
T t2;
@Override
public void test(T t2)
{
}
}
/**
* 子类为泛型类,父类不指定类型->泛型的擦除,使用Object替换,此时Father为Object类型
*/
class child3<T1,T2> extends Father
{
T1 abc;
@Override
public void test(Object t) {
}
}
/**
* 子类与父类同时擦除,使用Object替换,此时Father为Object类型
*/
class Child4 extends Father{
String t4;
@Override
public void test(Object t4) {
}
}
/**
*错误: 子类擦除,父类使用泛型
*/
/*class Child5 extends Father<T>
{
@Override
public void test(T t5) {
}
}*/
5.泛型接口擦除
package Genericity;
/**
* 泛型接口:与继承同理
* 重写方法随父类而定
* @author liguodong
*/
public interface Comparable<T> {
void compare(T t);
}
//声明子类指定具体类型
class Comp implements Comparable<Integer>
{
@Override
public void compare(Integer t) {
}
}
//同时擦除
class Comp1 implements Comparable
{
@Override
public void compare(Object t) {
}
}
//父类擦除子类泛型
class Comp2<T> implements Comparable{
@Override
public void compare(Object t) {
}
}
//子类泛型>=父类泛型
class Comp3<T,T1> implements Comparable<T>
{
@Override
public void compare(T t) {
}
}
//父类泛型,子类擦除 错误 同 声明子类具体类型 区别开
/*class Comp4 implements Comparable<T>
{
@Override
public void compare(T t) {
}
}
*/
6.泛型擦除情况
package Genericity;
/**
* 泛型的擦除情况
* 1.继承或实现声明不指定类型
* 2.使用时不指定类型
*
* 统一Object对待
* 1.编译器的警告 消除警告使用Object
* 2.不完全等同于Object 编译时不会自动类型检查
*/
public class Hero<T> {
private T id;
private T name;
public Hero() {
}
public Hero(T id, T name) {
super();
this.id = id;
this.name = name;
}
//泛型声明时不能使用静态属性
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public static void main(String[] args) {
//消除警告使用Object
Hero<Object> stu = new Hero<Object>();//不叫擦除
stu.setName("fds");//以Object对待
Hero stu1 = new Hero();//stu1相当于Object
//test(stu);//不叫擦除,会类型检查,会报错
//擦除 不会类型检查
//stu1相当于Object 但是不完全等同于Object
test(stu1);
test1(stu);
test1(stu1);
}
//不完全等同于Object,编译时不会自动类型检查
public static void test(Hero<Integer> a) {
}
public static void test1(Hero<?> a) {
}
}
7.泛型没有多态
package Genericity;
/**
* 多态的两种形式
* 1.形参使用多态
* 2.返回类型使用多态
*/
class Fruit {
}
public class Apple extends Fruit{
//形参使用多态
public static void test(Fruit f){
}
//返回类型使用多态
public static Fruit test2() {
return new Apple();
}
public static void main(String[] args) {
Apple f = new Apple();
test(f);
test2();
}
}
解决泛型没有多态,使用通配符。
8.通配符
?可以接收泛型的任意类型。只能接收和输出,不能修改。
9.泛型的嵌套
package Genericity;
public class Demo02<T>
{
T hero;
public static void main(String[] args) {
//泛型的嵌套
Demo02<Hero<String>> demo02= new Demo02<Hero<String>>();
//从外到内拆分
demo02.hero = new Hero<String>();
Hero<String> student = demo02.hero;
student.setName("盲僧");
String name = student.getName();
System.out.println(name);
}
}
10.没有泛型数组
package Genericity;
/**
* 没有泛型数组
* 声明可以使用,但是创建失败
*/
public class Array {
public static void main(String[] args) {
Integer[] integer = new Integer[4];
//Hero<String>[] arr01 = new Hero<String>[10];//报错 不能使用泛型数组
//Hero<?>[] arr02 = new Hero<Object>[10];//报错
Hero<?>[] hero = new Hero[10];//声明可以使用,但是没啥意义
MyArrayList<String> strArrayList = new MyArrayList<String>();
strArrayList.add(0, "a");
String string = strArrayList.getElem(0);
System.out.println(string);//a
MyArrayList<Integer> intArrayList = new MyArrayList<Integer>();
intArrayList.add(1, 1001);
int data = intArrayList.getElem(1);
System.out.println(data);//1001
}
}
class MyArrayList<E>
{
Object[] cap = new Object[10];
public void add(int index,E e)
{
cap[index] = e;
}
@SuppressWarnings("unchecked")
public E[] getAll()
{
return (E[]) cap;
}
@SuppressWarnings("unchecked")
public E getElem(int index)
{
return (E) cap[index];
}
}
没有泛型数组,但是可以巧妙的运用类来自己转换。
例如:ArrayList<E>源码
JDK7以前使用泛型
List<String> arrlist = new ArrayList<String>();
JDK7中使用泛型改进
List<String> arrlist = new ArrayList<>();
四、泛型与容器
1、Iterator与List
package Genericity;
import java.util.Iterator;
/**
* 迭代器原理
* @author liguodong
*/
@SuppressWarnings("all")
public class MyArray {
private String[] arr = {"a","b","c","d","d","e","e","f","g"};
private int size = arr.length;
public static void main(String[] args) {
MyArray list = new MyArray();
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
private class MyIt implements Iterator<String>{
private int cursor = -1;
/**
* 判断是否存在下一个元素
* @return
*/
public boolean hasNext(){
return cursor+1<size;
}
/**
* 获取下一个元素
*/
public String next(){
cursor++;//移动一次
return arr[cursor];
}
/**
* 删除元素
*/
public void remove(){
//没有实现
}
}
public Iterator<String> iterator(){
return new MyIt();
}
}
package Genericity;
import java.util.Iterator;
public class MyArrayAnonymous implements java.lang.Iterable<String>{
String[] elem = {"a","b","c","d","e"};
int size = elem.length;
/**
* 匿名内部类实现简单迭代器
* @return
*
* 对比AbstractList类源码
*/
public Iterator<String> iterator()
{
return new Iterator<String>()
{
private int cursor = -1;
public boolean hasNext()
{
return cursor+1<size;
}
public String next()
{
cursor++;
return elem[cursor];
}
public void remove(){
}
};
}
public static void main(String[] args) {
MyArrayAnonymous list = new MyArrayAnonymous();
Iterator<String> it = list.iterator();
while(it.hasNext())
{
System.out.print(it.next()+" ");
}
System.out.println();
//增强for,必须实现java.lang.Iterable接口,重写iterator方法。
for(String temp:list)
{
System.out.print(temp+" ");
}
}
}
2、HashMap+分拣思路
package Genericity.Map;
public class Letter {
private String name;
private int count;
public Letter() {
}
public Letter(String name, int count) {
super();
this.name = name;
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
package Genericity.Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 每个单词存储的次数
* Key:string
* Value:自定义类型
*
* "分拣"思路
* 1. 为所有的key创建容器,之后容器中存放对应value
* 2. 第一次创建容器,并存放值
* 第二次直接使用容器存放值
*/
public class Demo01 {
public static void main(String[] args) {
test1();
}
//思路一
public static void test1()
{
String str= "this is a cat and that is a mice and where is the food";
//分割字符串
String[] strArray = str.split(" ");
Map<String, Letter> letters = new HashMap<>();
/*for(String temp:strArray)
{
//1.为所有的key创建容器,之后容器中存放对应value
if(!letters.containsKey(temp))
{
letters.put(temp,new Letter());
}
}
for(String temp:strArray)
{
Letter col = letters.get(temp);//直接使用容器
col.setCount(col.getCount()+1);
//col.setName(temp);
}*/
//上面合并在一起
for(String temp:strArray)
{
//1.为所有的key创建容器,
if(!letters.containsKey(temp))
{
letters.put(temp,new Letter());
}
//2.之后容器中存放对应value
Letter col = letters.get(temp);//直接使用容器
col.setCount(col.getCount()+1);
}
//输出Map的值
Set<String> keys = letters.keySet();
for (String key:keys) {
Letter col = letters.get(key);
System.out.println("字母"+key+",次数"+col.getCount());
}
}
//思路二
public static void test2()
{
String str= "this is a cat and that is a mice and where is the food";
//分割字符串
String[] strArray = str.split(" ");
Map<String, Letter> letters = new HashMap<>();
for(String temp:strArray)
{
/*
//1.为所有的key创建容器,
if(!letters.containsKey(temp))
{
Letter col = new Letter();
col.setCount(1);//存放第一次的值
letters.put(temp,col);
}
else {
//2第二次直接使用容器中存放对应value
Letter col = letters.get(temp);//直接使用容器
col.setCount(col.getCount()+1);
}*/
Letter col = null;
if(null==(col =letters.get(temp)))
{
col = new Letter();
col.setCount(1);
letters.put(temp,col);
}
else {
col.setCount(col.getCount()+1);
}
}
//输出Map的值
Set<String> keys = letters.keySet();
for (String key:keys) {
Letter col = letters.get(key);
System.out.println("字母"+key+",次数"+col.getCount());
}
}
}
运行结果:
字母mice,次数1
字母that,次数1
字母cat,次数1
字母is,次数3
字母food,次数1
字母a,次数2
字母the,次数1
字母where,次数1
字母this,次数1
字母and,次数2
3、分拣思路+面向对象组合
package Genericity.Map;
/**
* 学生
* @author liguodong
*
*/
public class Student {
private String name;//姓名
private String no;//班号
private double score;//分数
public Student(String name, String no, double score) {
super();
this.name = name;
this.no = no;
this.score = score;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Student [name=" + name + ", no="+ no+", score="+score+"]";
}
}
package Genericity.Map;
import java.util.ArrayList;
import java.util.List;
/**
* 班级
*/
public class ClassRoom
{
private String no;//班号
private List<Student> stus;//学生列表 里面包括班号
private double total;//总分
public ClassRoom() {
stus = new ArrayList<>();
}
public ClassRoom(String no) {
this();
this.no = no;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public List<Student> getStus() {
return stus;
}
public void setStus(List<Student> stus) {
this.stus = stus;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
}
package Genericity.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 定义一个Student类,属性:name 姓名 no班号,score成绩。
* 现将若干Student对象放入List,请统计出每个班级的总分和平均分,分别打印出来.
*/
public class MapDemo {
public static void main(String[] args) {
//学生列表
List<Student> list = new ArrayList<>();
//放入学生对象
exam(list);
//统计
Map<String, ClassRoom> rooms = new HashMap<String, ClassRoom>();
count(rooms,list);
//打印
printScore(rooms);
}
/**
* 打印平均分
* @param rooms
* @param list
*/
public static void printScore(Map<String, ClassRoom> rooms){
Set<Map.Entry<String,ClassRoom>> entrySet = rooms.entrySet();
Iterator<Map.Entry<String, ClassRoom>> it = entrySet.iterator();
while(it.hasNext())
{
Map.Entry<String, ClassRoom> entry = it.next();
ClassRoom room = entry.getValue();
double avg = room.getTotal()/room.getStus().size();
System.out.println("班号"+room.getNo()+",总分"+room.getTotal()+",平均分"+avg);
}
}
//统计分数
public static void count(Map<String,ClassRoom> rooms,List<Student> list) {
for(Student stu:list) {
String no = stu.getNo();//得到学生班号
double score = stu.getScore();//得到分数
//根据班级编号查看Map是否存在该班级 分拣思路 value= get(Key);
ClassRoom room = rooms.get(no);
if(null==room)//第一次
{
room = new ClassRoom(no);
rooms.put(no,room); //Map put(key,value)
}
//存储
room.setTotal(room.getTotal()+score);//加入总分
//stus已经在构造函数中初始化了,这里直接加入即可。
room.getStus().add(stu);//加入学生
}
}
//将student放入对象List
public static void exam(List<Student> list)
{
list.add(new Student("a","001",80));
list.add(new Student("b","002",30));
list.add(new Student("c","001",40));
list.add(new Student("d","004",60));
list.add(new Student("e","005",70));
}
}
运行结果:
班号004,总分60.0,平均分60.0
班号005,总分70.0,平均分70.0
班号001,总分120.0,平均分60.0
班号002,总分30.0,平均分30.0
原文地址:http://blog.csdn.net/scgaliguodong123_/article/details/45716377