------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
一、泛型
泛型(Generic):JDK1.5以后出现的新特性,用于解决安全问题,是一个类型安全机制。泛型的出现将运行时期出现的问题如ClassCastException转移到了编译时期,方便于程序员解决问题,让运行时问题减少、安全;还避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。如:ArrayList
public static void main(String[] args)
{
//定义集合,并加入泛型,只能传入字符串
ArrayList al = new ArrayList();
//添加元素
al.add("xiaoming");
al.add("haha");
al.add("nihao");
//迭代器也加入泛型
Iterator it = al.iterator();
while(it.hasNext())
{
String s = it.next();
System.out.println(s);
}
}
泛型类:当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在可以定义泛型来完成拓展。泛型类定义的泛型在整个类中有效,如果被方法使用,当泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。要注意这里的具体类型都是引用类型,不能是基本类型。通过一段小代码进行演示:
class Demo
{
public static void main(String[]args)
{
//创建对象,明确要操作的数据类型为String
Useruser=new User();
//方法操作的参数类型只能是String
user.setObject("你好");
}
}
//定义一个泛型类
class User{
private AA a;
public void setObject(AA a){
this.a=a;
}
public AA getTool(){
return a;
}
}
class Demo
{
public static void main(String[]args)
{
//创建对象,明确要操作的数据类型为String
Tool tool=new Tool();
//get方法操作的参数类型只能是String
tool.get("你好");
//print方法在方法上定义了泛型,可以调用与类泛型不同的参数
tool.print("再见");
tool.print(12);//向上提升为Integer类型。
}
}
//定义一个泛型类
class Tool{
public void get(T t){
System.out.println(t);
}
public void print(S s){
System.out.println(s);
}
}
当一个泛型类中有静态方法时,静态方法不可以访问类上定义的泛型,如果静态方法操作的数据类型不确定,可以将泛型定义在方法上。
通配符:用?表示,又叫占位符,当传入的类型不确定时,使用通配符。使用通配符的好处是可以不用明确传入的类型,在使用泛型类或泛型方法时,提高了扩展性。定义的通配符主要做引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。即不能调用对象特有的方法。下面这个程序就应用了通配符,提高了扩展性。
public static void main(String[] args)
{
//定义一个字符串类型的ArrayList集合
ArrayList a1 = new ArrayList();
a1.add("abc1");
a1.add("abc2");
a1.add("abc3");
//定义一个I整数型的ArrayList集合
ArrayList a2 = new ArrayList();
a2.add(4);
a2.add(7);
a2.add(1);
//调用迭代方法
print(a1);
print(a2);
//使用了通配符,可以传入任意参数类型的ArrayList集合
public static void printColl(ArrayList> al)
{
Iterator> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().toString());
}
}
第一种设定上限:?extends E:可以接收E类型或者E的子类型。如:ArrayList extends Number> al=new ArrayList
第二种设定下限:? super E: 可以接收E类型或者E的父类型。 如:ArrayList super Integer> al=new ArrayList
通过应用泛型限定,可以让具有继承关系或处在同一个继承体系中的对象,能够实现方法的共用,提高代码的复用性。如下面这个程序:
/**
定义学生类、工人类,他们都有年龄属性。
建立他们的具体对象,并放在TreeSet集合中。
按照姓名的自然顺序排序。
*/
class GenericDemo7
{
public static void main(String[] args)
{
//建立存储学生对象的TreeSet集合,按照传入的比较器排序
TreeSet ts = new TreeSet(new Comp());
ts.add(new Student("孙明"));
ts.add(new Student("小新"));
ts.add(new Student("陈光"));
ts.add(new Student("阿亮"));
Iterator it = ts.iterator();
//获取每个学生
while(it.hasNext())
{
System.out.println(it.next().getName());
}
//建立存储工人对象的TreeSet集合,按照传入的比较器排序
TreeSet ts1 = new TreeSet(new Comp());
ts1.add(new Worker("王猛"));
ts1.add(new Worker("李霞"));
ts1.add(new Worker("孙一"));
ts1.add(new Worker("霍东"));
Iterator it1 = ts1.iterator();
while(it1.hasNext())
{
System.out.println(it1.next().getName());
}
}
}
//定义比较器,定义泛型为Person
class Comp implements Comparator
{
public int compare(Person p1,Person p2)
{
return p2.getName().compareTo(p1.getName());
}
}
//定义Person类
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public String toString()
{
return "person :"+name;
}
}
//定义学生类,继承Person
class Student extends Person
{
Student(String name)
{
super(name);
}
}
//定义工人类,继承Person类
class Worker extends Person
{
Worker(String name)
{
super(name);
}
}
Comparator接口传入参数类型是 super T>,当我们传入的是工人和学生共同的子类Person时,存储两者的集合都可以调用这个比较器,提高了代码的复用性,简化了代码。二、枚举
就是让一个类对应的引用型变量的取值为若干个固定的值中的一个。例如星期对应的值只能是星期一到星期日。否则编译无法通过。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。下面就通过一个普通类来实现枚举的功能,如下:
public abstract class WeekDay{
//构造函数私有
private WeekDay(){}
//定义变量,表示周日
public final static WeekDay SUN = new WeekDay(){
public WeekDay nextDay() {
return MON;
}
};
//定义变量。表示周一
public final static WeekDay MON = new WeekDay(){
public WeekDay nextDay() {
return SUN;
}
};
//定义抽象方法,表示下一天
public abstract WeekDay nextDay();
//返回字符串表现形式
public String toString(){
return this==SUN?"SUN":"MON";
}
}
该类的对象的值只能是固定的SUN、MON。 该类创建时,首先将构造函数私有,所以外部无法创建该类的对象。每一个同类型成员变量用公有静态修饰,其实就是该类的一个实例对象。类中可以定义共有方法或抽象方法,成员变量对象中要复写抽象方法。
枚举类:通过enum关键字表示,枚举类中每个元素都是类静态常量,都是该类的一个实例对象。枚举类定义的值就是该类中定义的元素。若不是,编译失败。枚举类的构造函数称为构造器,必须私有,保证外部无法创建枚举类的实例。在构造枚举值时被调用。可以定义多个构造器,调用哪个即初始化对应的值。下面通过一段程序演示枚举类及其特有的方法。
public class Demo {
public static void main(String[] args) {
//获取表示周一的对象
WeekDay weekDay = WeekDay.MON;
//获取表示周五的对象
WeekDay weekDay2 = WeekDay.FRI;
//打印枚举常量名
System.out.println(weekDay2);
//打印枚举常量名
System.out.println(weekDay2.name());
//打印枚举常量的次序
System.out.println(weekDay2.ordinal());
//将字符串转为枚举常量
System.out.println(WeekDay.valueOf("SUN"));
//获取所有枚举常量
System.out.println(WeekDay.values());
}
//定义一个内部枚举类
public enum WeekDay{
//定义枚举常量
SUN(1),MON(),TUE,WED,THI,FRI,SAT;
private WeekDay(){}
//定义有参数的构造方法
private WeekDay(int day){}
}
}
要注意的是枚举中元素必须位于枚举类的最上方,如果后面还有其他成员要用分号隔开。否则编译失败。枚举和普通的类一样,类中也可以有普通成员变量、成员方法等。当枚举类中多个构造方法时,元素需指定构造方法。若选择有参数的构造方法,需要传入参数,否则还是默认的构造方法。枚举也内部类的形式存在比较常见。枚举类中方法返回的类型一般都是本类类型。当枚举类中只有一个成员时,可以看成是一种单例设计模式的体现。下面再通过一个表示交通灯的枚举类,学习内容更丰富的枚举类。如下: //定义表示交通灯的枚举类
public enum WeekDay{
SUN(1),MON(),TUE,WED,THI,FRI,SAT;
private WeekDay(){System.out.println("first");}
private WeekDay(int day){System.out.println("second");}
}
public enum TrafficLamp{
//表示红灯,复写换灯方法
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
//表示绿灯,复写换灯方法
GREEN(45){
public TrafficLamp nextLamp(){
return YELLOW;
}
},
//表示黄灯,复写换灯方法
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
//定义表示换灯的抽象方法
public abstract TrafficLamp nextLamp();
//定义变量,表示亮灯时间
private int time;
//定义构造函数,初始化产生亮灯时间
private TrafficLamp(int time){this.time = time;}
}
}
-------------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------