------
将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题。让运行时期问题减少、安全。
import java.util.*;
class GenericDemo
{
public static void main(String[] args)
{
//初始化部分
TreeSet ts = new TreeSet(new LenComparator());//使用泛型
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("aaa");
ts.add("z");
ts.add("hahaha");
//遍历输出部分
Iterator it = ts.iterator();//使用泛型
while(it.hasNext())
{
String s = it.next();
System.out.println(s);
}
}
}
class LenComparator implements Comparator//使用泛型
{
public int compare(String o1,String o2)
{
int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));
//对字符串长度进行比较,Integer的compareTo方法,A.compareTo(B),AB返回正数,A=B返回0
//比如此处obj2:"cc" < obj1:"abcd",返回负数,obj1被存到红黑树的小端。输出的时候是先输出红黑树的小端,所以abcd比cc先输出
//如果改变一下位置,变成 new Integer(o1.length()).compareTo(new Integer(o2.length()))
//则此处 obj1:"abcd" > obj2:"cc",返回正数,obj1被存到红黑树的大端。输出的时候是先输出红黑树的小端,所以cc比abcd先输出
if(num==0)
return o2.compareTo(o1);
return num;
}
}
避免了强制转换的麻烦。如实现某接口时,指定传入接口方法的实参的类型,在复写该接口方法时就可以直接使用指定类型,而无需强制转换。
//代码比较
//迭代器
//不使用泛型
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
//使用泛型
Iterator it = ts.iterator();
while(it.hasNext())
{
String s = it.next();
System.out.println(s);
}
//Comparator
//不使用泛型
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2)//类型提升了,向上转型
{
Student s1 = (Student)o1;//所以为了获取到Student类本身的方法,还需要向下转型
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num==0)
{
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
//使用泛型
class LenComparator implements Comparator
{
public int compare(String o1,String o2)//传的时候就是String,没有向上转型的过程,就不需要再向下转型
{
int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));
if(num==0)
return o2.compareTo(o1);
return num;
}
class Worker
{
}
class Students
{
}
//泛型前做法。
class Tool//该作为工具的类可以同时提供给Worker和Students进行操作
{
private Object obj;
public void setObject(Object obj)
{
this.obj = obj;
}
public Object getObject()
{
return obj;
}
}
//泛型类
class Utils//名称都是自己取的,Utils是类的名称,便是带泛型的形式,用来接收类参数
//用户在使用Utils类时,先要告诉Utils,你要把Utils提供的方法使用在什么类上,也就是说,你要把类的类型先传给Utils后才能使用Utils中的方法
//传入类的类型之后,如果你在使用Utils的方法时传入了错误的类,则在编译时期就会报错
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}
class GenericDemo3
{
public static void main(String[] args)
{
Utils u = new Utils();//必须先把类的类型作为参数传递给该自定义的泛型类Utils
//使用Utils
//u.setObject(new Students());此时如果你传的不是Worker
Worker w = u.getObject();;
/* 不使用泛型类时会发生的问题:
Tool t = new Tool();
t.setObject(new Student());
Worker w = (Worker)t.getObject();
//由于Tool类在不用泛型时传入的是上帝类Object,设置的时候设置的是学生,而获取的时候获取是Worker在编译时是不会发生问题的
//但是在运行的时候会发生ClassCastException
*/
}
}
class Demo
{
public void show(T t)//将泛型定义在方法上,这样该方法可以把println构造函数内可以传入的类型都传入,扩展了应用性
{
System.out.println("show:"+t);
}
public void print(Q q)
{
System.out.println("print:"+q);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();
//泛型定义在方法上,该方法可以操作任意类型
//泛型定义在类上,一旦类型确定,那么接下来方法操作的都是那个被确定的类型
d.show("haha");//输出:show:haha
d.show(new Integer(4));//输出:show:4
d.print("heihei");//输出:print:heihei
d.print(3 > 4);//输出:print:false
/*
//对比:泛型定义在类上的情况
* //泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
class Demo
{
public void show(T t)
{
System.out.println("show:"+t);
}
public void print(T t)
{
System.out.println("show:"+t);
}
}
Demo d = new Demo();//对象一建立,要操作的类型就确定了,这里Integer或者String等是必须要指定的
d.show(new Integer(4));//编译通过
d.print("hah");//编译失败,因为已经规定需要操作的是Integer类
*/
}
}
既在类上定义泛型,又在方法上定义泛型的情况:
class Demo
{
public void show(T t)//方法上没有泛型
{
System.out.println("show:"+t);
}
public void print(Q q)
{
System.out.println("print:"+q);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();//如果在这里又同时限定了String类型(不限定时以下都能正常输出)
d.show("haha");//输出:show:haha
d.show(new Integer(4));//编译不通过,因为show已经制定需要操作String类型
d.print("heihei");//输出:print:heihei,print是一个泛型方法,即使Demo d = new Demo();还是可以正常使用
d.print(3 > 4);//输出:print:false
}
}
泛型方法应用在静态方法时的情况:
class Demo//这里的T要在建立对象时才被明确
{
public void print(Q q)
{
System.out.println("print:" + q);
}
public static void method(W w)//静态被先加载,其后才有对象
//静态方法不可以访问类上定义的泛型。
//如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
//如果不在void前加,写成public static void method(W w),编译失败:提示Cannot make a static reference to the non-static type T
{
System.out.println("method:"+ w);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();
d.print("heihei");
d.method(34);
}
}
interface Inter
{
void show(T t);
}
/*
常规的实现泛型接口的方法
class InterImpl implements Inter
{
public void show(String t)
{
System.out.println("show :"+t);
}
}
*/
//实现带泛型的接口时,也不知道需要传入并操作的是什么类型的情况
class InterImpl implements Inter
{
public void show(T t)
{
System.out.println("show :"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl i = new InterImpl();
i.show(4);
//InterImpl i = new InterImpl();
//i.show("haha");
}
}
import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();//ArrayList al 限定了String类型
al.add("abc1");
al.add("abc2");
al.add("abc3");
ArrayList al1 = new ArrayList();//ArrayList al1 限定了Integer类型
al1.add(4);
al1.add(7);
al1.add(1);
printColl(al);
//printColl(al1);如果想要打印al1,Integer类型中的元素,还非得要写两个Iterator,Iterator 和Iterator来实现
//如果使用了泛型限定,就可以避免出现这样繁琐的情况,简化了代码量,同时也提高了扩展性
}
public static void printColl(ArrayList al)
{
Iterator it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();//ArrayList al 限定了String类型
al.add("abc1");
al.add("abc2");
al.add("abc3");
ArrayList al1 = new ArrayList();//ArrayList al1 限定了Integer类型
al1.add(4);
al1.add(7);
al1.add(1);
printColl(al);
printColl(al1);
/*
输出结果:
abc1
abc2
abc3
4
7
1
*/
}
public static void printColl(ArrayList> al)//比较:ArrayList,或者使用public static void printColl(ArrayList al)
{
Iterator> it = al.iterator();//比较:Iterator ,或者使用Iterator,区别是如果是这种方法下的T还可以在while内进行操作
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
只想打印一个类型范围,比如只打印Person类和它的子类import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
printColl(al);
ArrayList al1 = new ArrayList();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al1); //此处将会编译失败,相当于ArrayList al = new ArrayList();error
//Student里面只能存Student,不能存其他Person类的子类实例
}
public static void printColl(ArrayList al)//注意:此处的Iterator中是Person
{
Iterator it = al.iterator();//注意:此处的Iterator中是Person
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
}
public static void printColl(ArrayList extends Person> al)//注意:此处使用了泛型限定
{
Iterator extends Person> it = al.iterator();//注意:此处使用了泛型限定
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
使用了泛型限定后的核心代码示例2:
class Comp implements Comparator//TreeSet构造器已经对此进行了泛型限定 super E>,可以接收Student以及其父类,如Person
//简单点说:在实现比较器的时候,如果类与类之间存在继承关系,那么只要把父类作为泛型参数进行实现,则它的子类都可以调用该比较器进行排序。但是局限性是只能用父类的方法
class Comp implements Comparator
{
public int compare(Student s1,Student s2)//public int compare(Person s1,Person s2)
{
//Person s1 = new Student("abc1");传Student及其父类都可以,因为这两个类型都可以接收Student对象。关键是要能接收进行比较的子类对象
return s1.getName().compareTo(s2.getName());
}
}
TreeSet ts = new TreeSet(new Comp());
ts.add(new Student("abc1"));
ts.add(new Student("abc2"));
ts.add(new Student("abc3"));
for(数据类型 变量名:被遍历的集合(collection)或者数组) {执行语句}
a、对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。可以看作是迭代器的简写形式。b、迭代器除了遍历,还可以进行remove集合中元素的动作。如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的操作。
高级for有一个局限性。必须有被遍历的目标(集合或数组)。传统for遍历数组时有索引。在遍历数组的时候,建议还是使用传统for。因为传统for可以定义角标。
class newChar
{
public static void main(String[] args)
{
//用高级for遍历集合
//ArrayList al的初始化
ArrayList al = new ArrayList();
al.add("abc1");
al.add("abc2");
al.add("abc3");
//增强型for循环
for(String s : al)//前面不加泛型,不能这么用
//for(数据类型 变量名:被遍历的数组或集合)
{
//s = "kk";
System.out.println("s:" + s);
/*
输出结果:
s:abc1
s:abc2
s:abc3
*/
}
System.out.println(al);//输出结果:[abc1, abc2, abc3]
/*使用迭代器时的情况
Iterator it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
*/
//用高级for遍历数组
//数组初始化
int[] arr = {3,5,1};
//传统for循环遍历
for(int x=0; x hm = new HashMap();
hm.put(1,"a");
hm.put(2,"b");
hm.put(3,"c");
//keySet方式取出
Set keySet = hm.keySet();
//因为Map不能直接用Iterator,故还是和Map遍历的方式一样,先要建立一个Set,存Key或者存关系,用for遍历的其实是这个Set
for(Integer i : keySet)
{
System.out.println(i+"::"+hm.get(i));
}
//entrySet方式取出
for(Map.Entry me : hm.entrySet())//简化书写
//Set> entrySet = hm.entrySet();
//for(Map.Entry me : entrySet)
{
System.out.println(me.getKey()+"------"+me.getValue());
}
}
}
class ParamMethodDemo
{
//主函数调用方法
public static void main(String[] args)
{
//改进版老方法调用
int arr[] = {3,4,4,5};//缺点:每次都要新建一个数组
showOld2(arr);//输出:3,4,4,5
int arr2[] = {2,3,4,5,6};//输出2,3,4,5,6
showOld2(arr2);
//新版本方法调用
showNew(3,4,4,5);//输出:3,4,4,5
showNew(2,3,4,5,6); //输出:2,3,4,5,6
}
//老的方法:传入参数不确定时,需要写许多超载的方法
public static void showOld(int a,int b){
System.out.println(a + "," + b);
}
public static void showOld(int a,int b,int c){
System.out.println(a + "," + b + "," + c);
}
//老方法的改进版:传入一个数组
public static void showOld2(int[] arr){
for(int i = 0; i < arr.length; i++){
if(!(i == arr.length - 1)){
System.out.print(arr[i] + ",");//用print就可以实现不换行打印
}else{
System.out.println(arr[i]);
}
}
}
//新的方法:可变参数的方法
public static void showNew(int... arr)//...就表示可变参数
//此时不用再手动每次都new一个Array了,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组.
//在使用时注意:可变参数一定要定义在参数列表最后面,如public static void show(String str,int... arr)
{
for(int i = 0; i < arr.length; i++){
if(!(i == arr.length - 1)){
System.out.print(arr[i] + ",");//用print就可以实现不换行打印
}else{
System.out.println(arr[i]);
}
}
}
}
import java.util.*;
import static java.util.Arrays.*; //导入的是Arrays这个类中的所有静态成员。
import static java.lang.System.*;
class StaticImport //extends Object
{
public static void main(String[] args)
{
//打印输出时就可以直接省略书写System. (import static java.lang.System.*)
out.println("haha");
//使用Arrays工具类的方法sort时就可以省略书写Array. (import static java.util.Arrays.*)
int[] arr = {3,1,5};
sort(arr);
int index = binarySearch(arr,1);//二分查找也是一样可以省略
out.println("Index="+index);
//当没有指定继承时,所以类默认继承了Object
out.println(Arrays.toString(arr)); //但是toString方法所有Object都具备,所以为了区分,必须写上具体调用者
}
}
1,将数组转换成集合,不可使用集合的增删方法,因为数组的长度是固定的。如果进行增删操作,则会发生UnsupportedOperationException的编译异常。2,如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。3,如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
import java.util.*;
class ArraysDemo
{
public static void main(String[] args)
{
//数组初始化
int[] intArr = {2,4,5};
String[] strArr = {"abc","cc","kkkk"};//字符串数组
Integer[] INTArr = {2,4,5}; //整数包装类数组
//转换为字符串形式
System.out.println(Arrays.toString(intArr)); //输出:[2, 4, 5]
//数组转为List
List list = Arrays.asList(strArr);
sop("contains:"+list.contains("cc"));//判断是否存在"cc"这个元素,输出:contains:true
/* 数组变成list集合的好处:可以使用集合的思想和方法来操作数组中的元素
将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定
如果你增删。那么会发生UnsupportedOperationException
可以使用的方法:
contains
get
indexOf()
subList()
*/
//如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在
List li1 = Arrays.asList(intArr);
sop("asList--int[]转集合:" + li1);//输出:asList--int[]转集合:[[I@659e0bfd]
//如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。
List li = Arrays.asList(INTArr);
sop("asList--Integer[]转集合:" + li); //输出:asList--Integer[]转集合:[2, 4, 5]
}
//打印方法
public static void sop(Object obj)
{
System.out.println(obj);
}
}
当指定类型的数组长度小于集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。当指定类型的数组长度大于集合的size,就不会创建新数组,而是使用传递进来的数组。所以创建一个刚刚好的数组最优。
为了限定对元素的操作。不需要进行增删了。
import java.util.*;
class Coll2Arr
{
public static void main(String[] args)
{
//ArrayList初始化
ArrayList al = new ArrayList();
al.add("abc1");
al.add("abc2");
al.add("abc3");
//定义一个String数组,使用toArray方法
String[] arr = al.toArray(new String[al.size()]);//传一个指定类型的数组,数组的长度等于集合的长度al.size()
//打印输出
System.out.println(Arrays.toString(arr));//输出:[abc1, abc2, abc3]
}
}