黑马程序员---泛型,Collections,Arrays

-----------android培训java培训、java学习型技术博客、期待与您交流!---------


泛型

      

      上一个博客就想介绍泛型的,不过发现泛型实在是有点儿多,因为很重要,加在上一篇博客里内容太多,不方便阅读,所以就在这这篇博客中介绍。


            而且在张老师的高新技术中也有讲到泛型,所以就把泛型整合一下来讲解,不过有点儿纠结,就是高新技术的泛型用到了反射什么的。


            现在看到这篇博客的朋友可能不知道,所以比较纠结要不要一起总结。还是一起总结吧,知识点一分散就该不熟了,所以咱们现在来学习泛型把~

 

      泛型就是在上一篇博客中我说等一下介绍的尖括号<>。

 

      泛型概述


            1.   JDK1.5版本之后出现的新特性,用于解决安全问题,是一个类型安全机制。

 

            2.   JDK1.5的集合类希望在定义集合时,标识你要传入的对象的类型,不是这个类型的不让传入。

 

            3.   泛型是给编译器看的,在编译时不加入泛型指定的类型的元素会发生异常。

      
                  但ArrayList<Integer>和ArrayList<String>的对象的字节码形式一样,说明泛型被转换成字节码之后就消失了,

                 

                  所以可以用反射取得add方法,在ArrayList<Integer>对象中添加String类型的元素,不会发生异常。

 

            4.   没有使用泛型时,不管是什么类型的对象都可以存储进同一个集合中。使用泛型后,可以将一个集合中的元素规定为一个类型,


                  这个集合中只能存储一种类型的对象,更加安全,并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,


                  不需要对对象进行强制类型转换,更加方便。泛型就是把原来的类名进行了延长。


                  在JDK 1.5中,你还可以按原来的方式将各种不同类型的数据装到一个集合中,但编译器会报告unchecked警告。

 

            5.   格式:


                  通过<>来定义要操作的引用数据类型


                  如:ArrayList<String>             //这个集合中只能存入String类型的元素

 

      泛型的好处


            1.   将运行时期出现的问题ClassCastException转移到了编译时期,方便于程序员解决诶问题,让运行时期问题减少,安全


            2.   避免强制转换的麻烦

 

      什么时候使用泛型呢?


            泛型通常在集合框架中很常见,只要见到<>就要定义泛型,<>就是用来接收类型的,当使用集合时,


            将集合中要存储的数据类型作为参数传递到<>中即可(<>接受的是引用数据类型)。

       

      泛型定义中的术语


            ArrayList<E>类定义和ArrayList<Integer>类引用中涉及一下术语


                  1.   整个称为:ArrayList<E>泛型类型


                  2.   ArrayList<E>中的E称为:类型变量或类型参数。


                  3.   整个ArrayList<Integer>称为:参数化的类型。


                  4.   ArrayList<Integer>中的Integer称为:类型参数的实例或实际类型参数


                  5.   rrayList<Integer>中的<>念:typeOf。


                  6.   ArrayList称为:原始类型。


      注意:参数化类型与原始参数化类型可以美容,也就是说等号左右两边可以只加一个泛型。


                        Vector v = new Vector<String>();            //编译可以通过,原始类型可以引用参数化类型


                        Vector<String> v =  new Vector();           //编译可以通过,参数化类型可以引用原始类型


                  参数化类型不考虑类型参数的继承关系,等号一边是父类,一边是子类的情况不可以。


                       也就是说当等号两边都加了反省的时候,等号两边泛型应该一致。


                        Vector<Object> v = new Vector<String>();            //编译不通过,哪怕有一边不写都过了。不能是继承关系


                  在创建数组实例时,数组的元素不能使用参数化的类型。如:


                        Vector<Integer> vectorList[] = new Vector<Integer>[]              //会编译失败


            思考:Vector v1= new Vector<String>();       Vector<Object>v = v1;可否通过编译


                        可以!因为v1是原始类型,参数化类型可以指向原始类型。V是参数化类型,原始类型可以指向参数化类型。

 

      通配符


            当泛型类型不确定时,使用?通配符可以引用其他各种参数化类型。?通配符定义的变量主要用作引用。


                  可以调用与参数化无关的方法。不能调用与参数有关的方法

 

            个人理解:当不知道要用的集合是什么类型时,用通配符


            限定通配符的上下边界

 

                  限定通配符的上边界


                        ? extends E:可接收E类型或E类型的子类型;称之为上限。


                                     如:ArrayList<?extends Number>x = new ArrayList<Integer>();


                  限定通配符的下边界


                        ? super E:可接收E类型或E类型的父类型;称之为下限。


                                      如:ArrayList<?super Integer>x = new ArrayList<Number>();

 

                  限定通配符总包括自己。

 

            通配符练习

/*
泛型

通配符的上边界演示
*/

//建立一个人 父类
import java.util.*;

class Person
{
	private String name;
	Person(String name )
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
}

//建立学生类,继承人 类
class Student extends Person
{
	private String name;
	Student(String name)
	{
		super(name);
	}

}

class GenericTest1  
{
	public static void main(String[] args) 
	{
		//创建一个接收Person类对象的集合并添加元素
		ArrayList<Person> al1 = new ArrayList<Person>();
		al1.add(new Person("zhangsan01"));
		al1.add(new Person("zhangsan02"));
		al1.add(new Person("zhangsan03"));

		//创建一个接收Student类对象的集合并添加元素
		ArrayList<Student> al2 = new ArrayList<Student>();
		al2.add(new Student("pt.....1"));
		al2.add(new Student("pt.....2"));
		al2.add(new Student("pt.....3"));

		//调用输出方法
		printCollection(al1);
		printCollection(al2);
	}

	//定义一个输出集合的方法,其中接受的集合的类型变量为Person或他的子类
	public static void printCollection(Collection<? extends Person> coll)
	{	
		Iterator<? extends Person> it = coll.iterator();

		while(it.hasNext())
		{
			//输出学生姓名
			System.out.println(it.next().getName());
		}	
	}
}


                  运行结果




 

      泛型类


            若类实例对象中要使用到同一泛型参数,即这些地方引用类型要保持同一个实际类型时,


                  这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型。

 

            什么时候定义泛型类?


                  当类中要操作的引用数据不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展。


                   泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

 

            类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:


                  GenericDao<String>  dao = null;


                  new  GenericDao<String>();

 

            格式:


                        class Utils<XX>{


                              private  XX  s;


                              public void  setxx(XX s){


                                    this.s=s;


                              }


                              public XX getXX(){


                                    return s;


                              }


                        }

 

      泛型方法


            为了让方法可以操作不同类型,而且类型还不确定,那么就可以将泛型定义在方法上。

            

                  格式


                        public<T> void show(T t) {};              //<T>在修饰符之后,返回值类型之前。

 

            静态泛型方法


                  特殊:静态泛型方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。

 

                            格式

                                    public  static <T> void show (T t){}

 

            用于放置泛型的类型参数的尖括号应该出现在方法的其他所有修饰符之后和在方法的返回值类型之前,也就是紧邻着返回值类型之前。


                  按照惯例,类型参数通常用单个大写字母表示。

 

            只有引用类型才能作为方法的实际参数,就是说作为实际参数不能是基本数据类型。

 

            除了在应用泛型可以使用extends限定符,在定义泛型时也可已使用extends限定符。例如


                  Class.getAnnotation方法


                        public<A extends Annotation> AgetiAnnotation(class<A>  annotationClass);


                  并且可以使用&来指定多个边界,如


                        <V extends Serializable & cloneable>void method(){}。

 

            普通方法、构造函数和静态方法中都可以使用泛型。

 

            可以用类型变量表示异常,称之为参数化的异常,可用于方法的throws列表中,但是不能用于catch子句中。

 

            在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。例如:


                  public static <K,V> V getValue(K key) { return map.get(key);}

 

      通配符和自定义泛型的区别


            在使用通配符的方法中不可以使用add方法,因为不知道什么参数化的类型要调用这个方法。


            而自定义的泛型可以,因为T是类型变量,可以指向某个类型,可以通过在方法上加参数的形式把T类型的元素通过add方法加入到集合中。


                  如 : public <T>void show(Collection<T> c , T t) {


                                    c.add(t);


                           }

 

      记住:泛型方法前面在返回值类型之前用一个<>说明即可。


      在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。


            当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型)而不能被静态变量和静态方法调用,


            因为静态成员是被所有参数化类型共享的,所以静态成员不应该有类级别的类型参数


通过反射获得泛型的实际类型参数


      通过反射获得泛型实例类型参数是不可以的,因为泛型到了字节码阶段就不存在了,


            所以可以通过获取方法对象的方式获取,可以获得方法参数的实际类型参数


      步骤


            1.   通过反射的方式,获得A方法对象。


            2.   调用Method类的Type[]  getGenericParameterTypes()方法获取A方法的参数类型数组


            3.   因为获得的是Type数组,所以我们要根据索引获取我们需要的参数类型,如果A方法只有一个参数那就获取Type数组的第一个元素


                  但Type是接口,不能建立对象来接受参数类型,所以要用到它的子类ParameterizedType类的引用性变量来接收A方法参数的参数类型对象。


            4.   调用ParameterizedType的 Type[]  getActualTypeArguments()方法,获取参数类型的实际类型参数的数组。


                  因为会出现一个参数类型对应几个实际类型参数的情况,所以用数组接收,


                  如果A方法的参数只有一个实际类型参数,那么就是数组的第一个元素

     

      小知识点:两个方法都接收同样的参数,实际类型参数不一样也视为同一个方法,不是重载


      用反射方法获得泛型的实际类型参数示例如下

/*
用反射方法获取泛型示例

如获取Vector<Date>的泛型
*/
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Vector;
import java.util.Date;

class  GenericReflectDemo
{
	public static void main(String[] args) throws Exception
	{
		//使用反射获取这个方法的对象
		Method appleMethod = GenericReflectDemo.class.getMethod("applyVector" , Vector.class);

		//通过Method类的getGenericParameterTypes()方法,获取参数列表的参数类型
		Type[] types = appleMethod.getGenericParameterTypes();

		//返回值类型为Type数组,但Type是接口,不能作为对象接收参数类型,所以要用Type的子类
		//ParameterizedType接收,获取数组中的第一个元素,因为applyVector只有一个参数
		ParameterizedType pt = (ParameterizedType)types[0];

		//调用ParameterizedType类的getRawType()方法,来看看我们现在得到的参数类型是否是我们想要的
		System.out.println("现在得到的参数类型是:"+pt.getRawType());

		//调用ParameterizedType类的getActualTypeArguments()方法,返回此类型实际参数的数组。
		//并打印第一个元素,因为参数只有一个实际参数类型,所以是数组中的一个元素
		System.out.println("参数的实际参数类型是:"+pt.getActualTypeArguments()[0]);
	}
	//定义一个接受VectorD<Date>参数的方法
	public static void applyVector(Vector<Date>  v)
	{
	
	}
}


            运行结果



泛型这块看着有点儿乱吧,我觉得写的有点儿乱,可是又说不出是那里乱,反正我尽力了!!泛型很重要,反射也重要,大家要好好学习!!

 

Collections


      Collections是一个工具类


            集合框架工具类,方法都是静态的。没有构造函数是不需要创建对象的,因为对象中并未封装特有的数据。都是共享的情况下定义为静态最方便。

 

      下面来介绍几个Collections的方法


            1.   static <T extends  Comparable<? super T>>  void  sort(List<T>  list)


                  根据元素的自然顺序对指定列表按升序进行排序。给List排序用的方法


                  TComparable的子类,因为T要具备比较性,要不程序运行时期会挂,


                  <? super T>Comparable接口的泛型,为了提高扩展性也可传入T的父类


                  (一般ComparableComparator后面都是super


            2.   static <T extends Object& Comparable<? super T>>  T  max(Collection<? extends T>  coll)


                        根据元素的自然顺序,返回给定Collection 的最大元素。


                  static <T> T max(Collection<? extends T> coll , Comparator<? super T> comp)


                        根据指定比较器产生的顺序,返回给定 collection 的最大元素。


            3.   static <T> int  binarySearch(List<? extends Comparable<? super T>> list ,  T key)


                  使用二分搜索法搜索指定列表,以获得指定对象。因为是折半查找,List集合必须是有序的,


                  所以如果集合无序要先使用sort方法给集合按自然顺序排序。


                  如果要寻找的元素不存在,那么返回的值为-1(插入点)-1。如”aaa”在只有”aa”,”abcd”的集合中查找,返回值就为:-1-1 = -2


            4.   static <T> void  fill(List<? super  T>  list , T  obj)


                  使用指定元素替换列表中所有元素。


            5.   static <T> boolean  replaceAll(List<T>  list , T  oldVal , T  newVal)


                  使用另一个值替换列表中出现的所有某一指定值。


            6.   static  void  reverse(List<?>  list)


                  反转指定列表中元素的顺序


            7.   static <T> Comparator<T>  reverseOrder()


                  返回一个比较器,它强行逆转实现了Comparable 接口的对象 Collection 的自然顺序。


                  就是说,将一个集合按照传入的比较器将集合对象的顺序按比较器顺序排,再把它反转。


                        例:TreeSet<String>  ts =new TreeSet<String>(Collection.recerseOrder(new 长度比较器));

                 

                              现在获得的集合就是按长度从长到短排序的


            8.   static  void  swap(List<?> list , int  i , int  j)


                  在指定列表的指定位置交换元素。置换集合中两个元素的位置


            9.   static  void  shuffle(List<?>  list)


                  使用默认随机源对指定列表进行置换。就是将集合中的元素随机置换(洗牌)

 

      面试题!!!


            Collection和Collections的区别


                  Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法,有两个常用的子接口。


                              List:对元素都有定义索引,有序的,可以重复元素


                              Set:不可重复的,是无序的


                  Collections是集合框架中的一个工具类,该类中的方法都是静态的。


                        提供的方法中有可以对List集合进行排序,二分查找等方法。通常常用的集合都是线程不安全的,因为要提高效率,


                        如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合转换成安全的。

 

      Collections类中的同步方法


            1.   static <T> Collection<T>  synchronizedCollection(Collection<T> c)


                  返回指定 collection 支持的同步(线程安全的)Collection


            2.   static <T> List<T> synchronizedList(List<T> list)


                  返回指定列表支持的同步(线程安全的)列表


            3.   static <K,V>Map<K,V> synchronizedMap(Map<K , V> m)


                  返回由指定映射支持的同步(线程安全的)映射


            4.   static <T> Set<T> synchronizedSet(Set<T> s)


                  返回指定 set 支持的同步(线程安全的)set


            5.   static <K , V> SortedMap<K , V>  synchronizedSortedMap(SortedMap<K , V> m)


                  返回指定有序映射支持的同步(线程安全的)有序映射


            6.   static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T>  s)


                  返回指定有序 set 支持的同步(线程安全的)有序 set

 

      Collections类中的方法演示

/*
Collections中方法的演示

1.	static <T extends Comparable<? super T>> void sort(List<T> List)
根据元素的自然顺序 对指定列表按升序进行排序。给List排序用的方法

2.	static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
根据元素的自然顺序,返回给定 collection 的最大元素。
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp
根据指定比较器产生的顺序,返回给定 collection 的最大元素。

3.	static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
使用二分搜索法搜索指定列表,以获得指定对象。
因为是这版查找,List集合必须是有序的,所以要先使用sort方法。
如果要寻找的元素不存在,那么返回的值为-1(插入点)-1。
如”aaa”在只有”aa”,”abcd”的集合中查找,返回值就为:-1-1 = -2

4.	static <T> void fill(List<? super T> list, T obj)
使用指定元素替换列表中所有元素。

5.	static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值。

6.	static void reverse(List<?> list)
反转指定列表中元素的顺序

7.	static <T> Comparator<T> reverseOrder()
返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。
就是说,将一个集合按照传入得比较器将集合对象的顺序按比较器顺序排,再把它反转。
例:TreeSet<String>  ts = new TreeSet<String>(Collection.recerseOrder(new 长度比较器));

8.	static void swap(List<?> list, int i, int j)
在指定列表的指定位置交换元素。置换集合中两个元素的位置

9.	static void shuffle(List<?> list)
使用默认随机源对指定列表进行置换。就是将集合中的元素随机置换(洗牌)


*/
import java.util.*;

class  CollectionsTest
{
	public static void main(String[] args) 
	{
		//先来创建一个集合
		List<String> list1 = new ArrayList<String>();
		//往集合中添加元素
		list1.add("ancda");
		list1.add("sdfd");
		list1.add("aq");
		list1.add("dfe");
		list1.add("ertgas");
		list1.add("s");

		//输出原有集合
		sop("原有集合:"+list1);

		//1.给List集合按自然顺序排序,sort方法
		Collections.sort(list1);
		//打印按自然排序后的结果
		sop("自然排序后的集合:"+list1);
		
		//2.按元素的自然顺序,返回集合中的最大元素,max方法
		String max1 = Collections.max(list1);
		sop("list1中自然顺序最大元素为:"+max1);
		//按指定比较器来获取最大元素,与上面使用的max是重载形式
		//要在集合后面传入一个比较器对象,这个比较器是按照我们自己想要的方法排序的
		String max2 = Collections.max(list1,new lenComparator());
		sop("按自定义比较器排序后的最大值为:"+max2);

		//3.用二分法查找List集合中元素的位置,binarySearch方法,元素必须是有序的
		//因为前面使用过sort方法了,所以直接找就好
		int index = Collections.binarySearch(list1,"ertgas");
		sop("ertgas在按自然顺序排位的位置是:"+index);

		//4.使用另一个值替换列表中所有某一指定值,replaceAll
		//用haha替换 sdfd
		Collections.replaceAll(list1,"sdfd","haha");
		sop("替换元素后的集合:"+list1);

		//5.反转列表中元素的顺序,reverse
		Collections.reverse(list1);
		sop("反转后的集合:"+list1);

		//6.返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序
		//reverseOrder,为了更为直观,我们这里创建一个方法,来看代码
		//调用演示reverseOrder方法
		showReverseOrder();

		//7.置换集合中两个元素的位置,swap 交换 1和3 的位置
		Collections.swap(list1,1,3);
		sop("交换两个元素之后的集合:"+list1);

		//8.将集合中的元素随机置换,shuffle
		Collections.shuffle(list1);
		sop("随机置换后的集合:"+list1);

		//9.使用指定元素替换列表中所有元素,fill,将所有元素替换成我要去黑马
		Collections.fill(list1,"我要去黑马");
		sop("全部替换后的集合为"+list1);
	}

	//演示reverseOrder方法
	public static  void showReverseOrder()
	{
		//创建一个有序的集合这样比价好出效果,就用TreeSet吧
		// 把比较器对象作为参数传入reverseOrder方法中,然后reverseOrder再返回一个比较器,
		//这个被返回的比较器把集合按传入的比较器排序,并逆转。
		//所以现在会输出的结果是,按照字符串长度从长到段排序
		TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new lenComparator()));

		//添加元素
		ts.add("acd");
		ts.add("r");
		ts.add("z");
		ts.add("aaaa");

		//输出集合
		sop("按照字符串长度排序并反转后的集合:"+ts);
	}

	//打印方法
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

//创建一个按元素的长度来排序的比较器
class lenComparator implements Comparator<String>
{
	//复写compare方法
	public int compare(String s1 , String s2)
	{
		//得到两个元素的长度,并相减,用一个int类型数据记住
		int num = s1.length() - s2.length();
		//如果num==0,那就说明元素长度相同
		if(num == 0)
			//所以要比较长度相同两个元素的自然顺序,并返回
			return s1.compareTo(s2);
		//如果num!=0 返回num
		return num;	
	}
}


            运行结果


                  

 

Arrays


      Arrays是用于操作数组的工具类,里面都是静态方法,不需要创建对象。


      Arrays的常见方法


            1.   static  void  sort(基本数据类型数组 引用型变量)


                        参数类型为基本数据类型数组的情况,就按照数字大小给数组进行排序。


                  static  void  sort(Object[]  a)


                        参数是Object[]类型的情况,就按自然顺序给数组排序


                  static <T> void  sort(T[]  a , Comparator<? superT>  c)


                        根据指定比较器产生的顺序对指定对象数组进行排序。就是说按比较器给数组排序。


            2.   static  String  toString(基本数据类型 引用型变量)


                  返回指定数组内容的字符串表示形式。


            3.   static <T>  List<T> asList(T... a)


                  将数组变为List集合

 

      把数组变成集合的好处


            可以使用集合的思想和方法来操作数组中的元素。


                 注意:将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的,


                              如果增删了会发生UnsupportedOperationException 不支持操作异常。


                              如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成了集合中的元素。


                              如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

 

      Arrays的方法演示

/*
Arrays中方法演示

1.	static void sort(基本数据类型数组 变量)
参数类型为基本数据类型数组的情况,就按照数字大小给数组进行排序。
static void(Object obj)
参数是Object类型的情况,就按自然顺序给数组排序
static <T> void sort(T[] a, Comparator<? super T> c)
根据指定比较器产生的顺序对指定对象数组进行排序。就是说按比较器给数组排序。

2.	static String toString(基本数据类型 变量)
返回指定数组内容的字符串表示形式。

3.	static <T> List<T> asList(T... a)
将数组变为List集合


*/
import java.util.*;

class ArraysTest 
{
	public static void main(String[] args) 
	{
		//基本数据类型数组
		int[] arri = new int[]{5,8,1};

		//Steing类型数组,因为String是特殊的对象,我们就用它
		String[] arrs = new String[]{"zzc","dddsd","asdf"};

		//输出基本数据类型数组,返回数组的字符串表现形式,toString
		sop("基本数据类型数组:"+Arrays.toString(arri));
		
		//将将字符串数组转为集合,asList方法
		List<String> list1 = Arrays.asList(arrs);
		//输出串数组
		sop("字符串数组为:"+list1);

		//将基本数据类型数组按数字排序,sort
		Arrays.sort(arri);
		//输出排序结果
		sop("基本数据类型数组按数字大小排序:"+Arrays.toString(arri));

		//将字符串数组按照自然排序,sort
		Arrays.sort(arrs);
		//输出结果
		sop("字符串数组按照自然顺序排序:"+Arrays.toString(arrs));

		//将字符数组按照自定义比较器排序,sort
		Arrays.sort(arrs,new lenComparator());
		//输出结果
		sop("字符串数组按照自定义比较器顺序排序:"+Arrays.toString(arrs));		
	}
	//输出方法
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

//创建一个按元素的长度来排序的比较器
class lenComparator implements Comparator<String>
{
	//复写compare方法
	public int compare(String s1 , String s2)
	{
		//得到两个元素的长度,并相减,用一个int类型数据记住
		int num = s1.length() - s2.length();
		//如果num==0,那就说明元素长度相同
		if(num == 0)
			//所以要比较长度相同两个元素的自然顺序,并返回
			return s1.compareTo(s2);
		//如果num!=0 返回num
		return num;	
	}
}


            运行结果



 

      

集合变数组


      Collection接口中的toArray方法


            <T>  T[]  toArray (T[]  a)


                  返回包含此collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。


                  例:ArrayList<String>  al = new ArrayList<String>();


                        String[]  arr = al.toArray(new String[al.size()]);

 

      1.   指定类型的数组到底要定义多长呢?


            当指定类型的数组长度小于集合的size,那么该方法会常见一个新的数组,长度为集合的size。


            当指定类型的数组长度大于集合的size,就不会创建新数组,而是使用传递进来的数组,并且多出的位置会用null来表示。


            所以创建一个正好的数组最优先。

 

      2.   为什么要将集合变为数组?


            为了限定对元素的操作。


            因为数组的长度不能改变,所以不可以增删元素,可以保持元素的完整性,可以查阅,但不能修改。

 

      集合变数组演示

/*
集合变数组演示
*/
import java.util.*;

class  CollectionToArray  
{  
    public static void main(String[] args)   
    {  
		//创建一个集合
        ArrayList<String> al = new ArrayList<String>();  
  
		//添加元素
        al.add("pt1");  
        al.add("pt2");  
        al.add("pt3");

        //将集合变为String数组,长度为集合的size
        String[] arr = al.toArray(new String[al.size()]);  
        //打印String数组 
        System.out.println(Arrays.toString(arr));  
    }  
}  

            

            运行结果



 

下面来介绍几个JDK1.5版本之后的新特性

      

      1.   高级for循环


            格式


                  for( 数据类型 变量名 :  被遍历的集合或者数组 ){要执行的语句}


                        例: for(String str : al) {


                                    System.out.println(str);


                                }

            高级for循环对集合进行遍历


                  只能获取元素,但是不能对集合进行操作。可以看做是迭代器的简写形式。


                  迭代器除了遍历还可以进行remove集合中元素的动作,如果使用ListIterator,还可以在遍历中进行,增删改查的动作。

 

            传统for循环和高级for循环的区别


                  高级for循环有一个局限性,必须有被遍历的目标(集合或数组)


                  建议:在遍历数组时还是希望使用传统for循环,因为传统for循环可以定义角标。

 

                  (支持迭代器的集合都支持高级for循环)


            注意:在定义集合时要写泛型,这样高级for循环才可以进行,如果定义集合时不加泛型。


                      高级for循环里的数据类型为Object,两个功能都是JDK1.5版本之后的,所以最好加上泛型。

 

            高级for循环演示示例

/*
高级for循环演示
*/
import java.util.*;

class ForTest
{  
    public static void main(String[] args)   
    {  
        //定义一个ArrayList集合  
        ArrayList<String> al = new ArrayList<String>();  
		//添加元素
        al.add("abc1");  
        al.add("abc2");  
        al.add("abc3");  
  
		//使用高级for循环遍历集合
		sop("高级for循环遍历集合");
        for(String str : al)  
        {  
           sop(str);
        }  
  
        //定义一个数组 
        int[] arr = {3,5,1};  
		
		//传统for循环遍历数组
		sop("传统for循环遍历数组");
        for(int x=0; x<arr.length; x++)  
        {  
            sop(arr[x]);  
        }
		//高级for循环遍历数组
		sop("高级for循环遍历数组");
        for(int i : arr)  
        {  
            System.out.println(i);  
        }  
  
        //定义一个HashMap集合  
        HashMap<Integer,String> hm = new HashMap<Integer,String>();  
		//添加元素
        hm.put(1,"a");  
        hm.put(2,"b");  
        hm.put(3,"c");  
  
        //利用keySet和高级for循环遍历Map数组元素
		sop("利用keySet和高级for循环遍历Map数组元素:");
		//用keySet方法,将Map集合中的元素全部取出,存入一个Set集合中
        Set<Integer> keySet = hm.keySet();  
		//利用高级for循环,遍历keySet集合,并取出Integer类型的key
        for(Integer key : keySet)  
        {  
			//使用get()方法根据key获取value,并输出key value
            System.out.println(key+"..."+hm.get(key));  
        }  
  
        //利用entrySet和高级for循环遍历Map数组元素
		sop("利用entrySet和高级for循环遍历Map数组元素");
		//利用entrySet方法,将Map几何中的映射关系存入一个Set集合中
		Set<Map.Entry<Integer,String>> entrySet = hm.entrySet();
		//利用高级for循环,遍历entrySet集合
		//并取出Map.Entry<Integer,String>类型的元素
        for(Map.Entry<Integer,String> me : entrySet)  
        {  
			//利用Map.Entry中的getKey和getValue方法取出key和value,并输出
            System.out.println(me.getKey()+"------"+me.getValue());  
        }    
    } 
	
	//输出方法
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}  


                  运行结果



 

      

      2.   可变参数


            如果一个方法在参数列表中传入多个参数,但是个数不确定,那么每次都要复写该方法,这时可以用数组作为形式参数。


            但是在传入时,每次都需要定义一个数组对象作为实际参数。在JDK1.5版本后,就提供了一个新特性:可变参数。

 

            可变参数其实就是每次都要新建数组的简写形式,不用每一次都手动的建立数组对象,


            只要将操作的元素作为参数传递即可,隐式的将这些参数封装成了数组

 

            格式:


                  public  static  void  show(int… arr){}

 

            方法的可变参数在使用时注意:可变参数一定要定义在参数列表的最后。

 

            可变参数示例

/*
可变参数演示代码
*/
class KeBianCanShuTest 
{
	public static void main(String[] args)   
    {  
		//调用show方法
        show("pt",0,3,1,8,2);
		//整数个数不同
		show("pjz",4,2);
    }  
	//定义一个可变参数方法,...就表示可变参数,将传入的整数变成了一个数组
    public static void show(String str,int... arr)  
    {  
		//输出数组长度
        System.out.println(str+"数组长度:"+arr.length);  
    }  
}


                  运行结果




      3.   静态导入


            例:import static java.util.Arrays.*;        //导入的是Arrays这类中所有的静态成员。

 

            没加static导入的是类,加上static导入的是某一个类中所以的静态成员。这样写在调用该类的静态方法时可以不用再写类名。


                  如:Arrays.ToString(数组);            //就可以直接写sort(数组);

 

            注意:当类名重名时,需要指定具体的包名。

                      当方法重名时,要指定具体所述的对象或者类

 




谢谢大家的观看~!

-----------android培训java培训、java学习型技术博客、期待与您交流!---------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值