java程序员从笨鸟到菜鸟之(二十七)集合之Jdk5以后新特性

回顾一下集合的遍历方式

1  普通for循环---size和get方法---向下转型

2  Collection集合的iterator()方法迭代器(iterator()方法)----hasNext和next方法---向下转型

3  List集合的迭代器迭代器(listIterator方法)--同上

4  toArray----转成Object类型数组,length属性----向下转型

5  增强for循环

增强for循环

  JDK5以后提供了很多 特性
  泛型、增强for循环、可变参数、静态导入、自动拆装箱、枚举等
 
  增强for循环
  语法格式
  for(集合或者数组中的 数据类型 变量名:集合或者数组的 对象名){
  输出 变量名;
}
 
 增强for循环的 弊端
   遍历数组或者集合的时候,数组对象或者集合对象 不能为null
    如果 对象为空,则出现java.lang.NullPointerException---- 空指针异常,所以 一般加上非空判断

    增强for循环的出现就是为了替代迭代器遍历集合的,以后开发中常用增强for遍历元素
 实例1

package org.westos.Jdk5_news;

import java.util.ArrayList;
import java.util.Iterator;

public class ForDemo {
	
	public static void main(String[] args) {
		System.out.println("int数组普通for循环遍历---------------------");
		//定义一个数组,静态初始化
		int[] arr = {11,22,33,44,55} ;
		//普通for循环的遍历
		for(int x = 0 ; x < arr.length ; x ++){
			System.out.println(arr[x]);
		}
		
		System.out.println("int数组增强for循环遍历---------------------");
		//使用增强for遍历
		for(int i :arr){
			System.out.println(i);
		}
		//思考:增强for循环代码简单,但是执行速率呢?(有机会了看一看)
		
		
		System.out.println("String数组增强for循环遍历-------------------");
		//定义一个字符串数组,并遍历
		String[] strArray = {"hello","world","java"};
		for(String s : strArray){
			System.out.println(s);
		}
		
		
		System.out.println("集合的增强for循环遍历-------------------");
		//创建ArrayList集合对象,添加并遍历元素
		ArrayList<String> array = new ArrayList<String>() ;
		//添加元素
		array.add("hello") ;
		array.add("world") ;
		array.add("java") ;
		
		/*
		使用增强for遍历该集合
		for(String s :array){
			//需求:判断当前集合中是否有"world",如果有就添加元素
			//获取到每一个元素
			//出现异常--java.util.ConcurrentModificationException
			//理解上:理解为一个Iterator迭代器
			if("world".equals(s)){
				array.add("javaee") ;
			}
		}
		*/
		//为防止出现java.lang.NullPointerException:空指针异常--做非空判断
		if(array!=null){
			//增强for循环
			for(String s:array){
				System.out.println(s);
			}
		}
		
	}
}

泛型

泛型:英文genericity
使用ArrayList存储元素时,给ArrayList集合存储了一些元素:String类型的元素或Integer类型的元素,但是通过迭代器遍历元素,由于系统不知道集合中存储了哪些元素,所以使用String类型接收(不下转型,直接接受)就会出现ClassCastException---类转换异常,这样设计不够好!

再回看字符串数组的定义:

String[] str = new String[3] ;
str[0] = "hello" ;
str[1] = "world" ;
str[2] = 100 ;
 for(String s:str){
  System.out.println(s);
  }

 数组这样设计好处:提前告诉了开发者,这里只能装String类型的元素,不需要转型了,Java根据数组特点---->引出了泛型
 泛型:把数据类型的明确工作提前到了创建对象或者是调用方法的时期明确的一种特殊类型.

 参数化类型:可以像参数一样进行传递
格式:
  <引用类型>---泛型只能放引用类型
  泛型好处
   1)将运行时期异常提前到了编译时期
   2)解决了黄色警告线问题
   3)获取数据的时候,不用强制类型转换
 泛型应用
 一般情况下,泛型可以应用在接口、或者方法上;主要用在集合中比较多!

实例2

package org.westos_01;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericDemo2 {
	
	public static void main(String[] args) {
		
		//创建一个ArrayList集合对象
		ArrayList<String> array = new ArrayList<String>() ;//泛型
		/*
		 * jdk7特性:泛型推断
		 * 前面声明了集合存储元素的类型,后面可以不添加
		 * 建议:后面永远给出类型!!!
		 * 
		 */
		
		//给集合中添加元素
		array.add("hello") ;
		array.add("world") ;
		array.add("java") ;
		
		//获取迭代器对象并遍历
		Iterator<String> it = array.iterator() ;
		//遍历
		while(it.hasNext()){
			//好处:不用强制类型转换了
			String s = it.next() ;
			System.out.println(s);
		}
		
	}
}
练习:使用ArrayList集合存储自定义对象(Student)并遍历

补充jdk5以前的情况

早期的时候(JDK5以前),用Object类型代表任意的类型,向上转型是不会出现问题的,但是向下转型的时候,由于隐藏了类型转换,导致出现错误!也即程序不安全,JDK5以后,提供了泛型可以解决程序的安全性

cmd编译出现的相应警告


实例3   ObjectTool工具类

package org.westos_02;

public class ObjectTool {
	
	private Object obj ;
	
	//获取
	public Object getObj(){
		return obj ;
	}
	
	//设置
	public void setObj(Object obj){//Object obj = new Integer(27) ; //向上转型
		this.obj = obj ;
	}
}
测试类

package org.westos_02;
/**
 * 没有泛型时,向上转型是不会出现问题的,但是向下转型的时候,由于隐藏了类型转换,导致出现错误!
 */
public class ObjectToolDemo {
	
	public static void main(String[] args) {
		
		//创建ObjectTool对象
		ObjectTool ot = new ObjectTool() ;
		//设置数据
		ot.setObj(27) ;//Object obj = new Integer(27):向上转型
		//获取
		Integer i = (Integer) ot.getObj() ;//向下转型
		System.out.println("年龄是:"+i);
		
		
		ObjectTool ot2 = new ObjectTool() ;
		//设置
		ot2.setObj("高圆圆") ;//Object obj = new String("高圆圆") ;
		//获取
		String str = (String) ot2.getObj() ;//类型转换了:向下转型:隐藏了类型转换
		System.out.println("姓名是:"+str);
		
		System.out.println("-------------------------------");
		
		ObjectTool ot3 = new ObjectTool() ;
		ot3.setObj("邓超") ;
		//java.lang.ClassCastException
		Integer ii = (Integer) ot3.getObj() ;//强制类型转换的接收类型不匹配----程序不安全
		System.out.println("姓名是:"+ii);
	}
}	
解决思路  将 泛型定义在类上(集合)

实例4  工具类

package org.westos_03;

public class ObjectTool<T> {
	
	private T obj;
	
	//获取
	public T getObj(){
		return obj ;
	}
	
	//设置
	public void setObj(T obj){
		this.obj = obj ;
	}
}
测试类

package org.westos_03;

public class ObjectToolDemo {
	
	public static void main(String[] args) {
		
		//创建ObjectTool<T>对象
		ObjectTool<String> ot = new ObjectTool<String>() ;
		//设置数据
		ot.setObj("高圆圆") ;
		//获取数据
		//编译都通过不了
//Integer i = ot.getObj() ; 由于给类上加入了泛型,在实际测试中,给定了数据类型,获取数据的时候就必须应该类型来接收,否则不匹配
		String name = ot.getObj() ;
		System.out.println("姓名是:" +name);
		
		//创建对象
		ObjectTool<Integer> ot2 = new ObjectTool<Integer>() ;
		//设置数据
		ot2.setObj(27) ;
		
		//获取数据
//String s = ot2.getObj() ;
		Integer i = ot2.getObj() ;
		System.out.println("年龄是:"+i);
	}
}
实例5  将 泛型定义在方法
package org.westos_04;

//在工具类中定义几个成员方法
/*public class ObjectTool<T> {
	
	//形式参数是String
	public void show(String s){
		System.out.println(s);
	}
	
	//形式参数是Integer类型
	public void show(Integer i){
		System.out.println(i);
	}
	
	public void show(Boolean b){
		System.out.println(b);
	}
	
	public void show(T t){
		System.out.println(t);
	}
代码的冗余度比较高	
}*/


public class ObjectTool{
	
	//将泛型定义在方法上,根据传入的类型,调用相应的输出
	public <T> void show(T t){
		System.out.println(t);
	}
}
测试类

package org.westos_04;

//测试类
public class ObjectToolDemo {

		public static void main(String[] args) {
			
                       /* 创建工具类对象
			ObjectTool ot = new ObjectTool() ;
			ot.show("hello") ;
			ot.show(100) ;
			ot.show(true) ;*/
			
		     /*	ObjectTool<String> ot1 = new ObjectTool<String>() ;
			ot1.show("hello") ;
			
			ObjectTool<Integer> ot2 = new ObjectTool<Integer>() ;
			ot2.show(100) ;
			
			ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>() ;
			ot3.show(true) ;*/
			
			//泛型可以定义在方法上吗? ---OK---public <T> void show(T t){}
			
			//创建工具类对象
			ObjectTool ot = new ObjectTool() ;
			ot.show("hello") ;
			ot.show(true) ;
			ot.show(100) ;
		}
}
实例6  接口加入了泛型

接口

//把泛型定义在接口上
public interface Inter<T> {

	public abstract void show(T t) ;
}
接口的实现类

package org.westos_04;

//第一种情况:接口的子实现类已经知道传递的是什么数据类型
/*public class InterImpl<String> implements Inter<String> {

	@Override
	public void show(String t) {
		System.out.println(t);
	}

}*/


//第二种情况:接口的子实现类在实现接口的时候,不知道具体的数据类型是什么
//在测试类的时候,传入具体数据类型

//面向接口编程

//JavaEE---Sping框架的AOP---面向切面编程
public class InterImpl<T> implements Inter<T>{

	@Override
	public void show(T t) {
		System.out.println(t);
	}
	
	
}
测试类

package org.westos_04;

public class InterDemo {

	public static void main(String[] args) {
		//创建接口对象
		//第一种情况的测试
		Inter<String> i = new InterImpl<String>() ;
		i.show("hello") ;
		
		System.out.println("-----------------------------");
		
		//第二种情况:
		Inter<Integer> i2 = new InterImpl<Integer>() ;
		i2.show(27) ;
		
		Inter<String> i3 = new InterImpl<String>() ;
		i3.show("高圆圆") ;
	}
}
泛型的高级: 通配符

<?> :可以是任意类型,包括Object类型以及任意的Java类
<? extends E>:向下限定,E类型以及E类型的子类
<? super E>:向上限定,E类型以及E类型的父类

实例7  集合嵌套(泛型)

工具类

package org.westos_02;

public class Student {
	
	private String name ;
	private int age ;
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	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;
	}
	
	
}
测试类

package org.westos_02;

import java.util.ArrayList;

/**
 * 假设有一个Java班,看成一个容器,这个容器里面有很多学生
 * ArrayList<Student>,但是又不止一个Java班,
 * 大的集合:ArrayList<ArrayList<Student>>
 * 集合的嵌套遍历
 * @author Apple
 */
public class ArrayListTest {
	
	public static void main(String[] args) {
		
		// 创建一个大集合的对象
		ArrayList<ArrayList<Student>> bigArray = new ArrayList<ArrayList<Student>>();
		//ArrayList<> bigArray = new ArrayList<>();与上面的区别
		//创建第一个子集合对象ArrayList<Student>
		ArrayList<Student> firstArray = new ArrayList<Student>() ;
		
		//创建学生对象
		Student s1 = new Student("唐", 30) ;
		Student s2 = new Student("猪", 22) ;
		Student s3 = new Student("孙", 26) ;
		
		//给第一个集合中添加元素
		firstArray.add(s1) ;
		firstArray.add(s2) ;
		firstArray.add(s3) ;
		
		//将第一个子集合添加到大集合中
		bigArray.add(firstArray) ;
		
		//创建第二个子集合对象
		ArrayList<Student> secondArray = new ArrayList<Student>() ;
		
		//创建学生对象
		Student s4 = new Student("高圆圆", 30) ;
		Student s5 = new Student("邓超", 22) ;
		Student s6 = new Student("朱亚文", 26) ;
		
		//给第二个子集合中添加元素
		secondArray.add(s4) ;
		secondArray.add(s5) ;
		secondArray.add(s6) ;
		
		//将第二个子集合添加到大集合中
		bigArray.add(secondArray) ;
		
		//创建第二个子集合对象
		ArrayList<Student> thirdArray = new ArrayList<Student>() ;
		
		//创建学生对象
		Student s7 = new Student("高圆圆", 30) ;
		Student s8 = new Student("邓超", 22) ;
		Student s9 = new Student("朱亚文", 26) ;
		
		//给第二个子集合中添加元素
		thirdArray.add(s7) ;
		thirdArray.add(s8) ;
		thirdArray.add(s9) ;
		
		
		//将第二个子集合添加到大集合中
		bigArray.add(thirdArray) ;
		
		
		//遍历大集合
		//增强for遍历
		//ArrrayList<ArrayList<student>>
		for(ArrayList<Student> array :bigArray){
			//子集合:ArrayList<Student>
			for(Student s : array){
				System.out.println(s.getName()+"---"+s.getAge());
			}
		}
		
		
	}
}

实例8

package org.westos_04;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 泛型的高级:通配符
 * <?> :可以是任意类型,包括Object类型以及任意的Java类
 * <? extends E>:向下限定,E类型以及E类型的子类
 * <? super E>:向上限定,E类型以及E类型的父类
 * @author Orange
 */
public class GenericDemo {
	
	public static void main(String[] args) {
		//(1)引用类型与创建对象的类型必须一致,否则编译器报错
		ArrayList<Object> c1 = new ArrayList<Object>() ;
		c1.add("hello");
		//(2)由于jdk7的泛型推断---创建对象的参数类型可以不写(系统知道)
		Collection<Object> c2 = new ArrayList<>() ;
		c2.add("hello");//成功
		/**
		 * 为了说明:想写一个即可以打印list1,又可以打印list2的方法--引出通配符(随后补充)
		 * (3)为了解决泛型引用和创建两端不匹配问题!---解决方案是<?>:通配符
		 * 说明:
		 * 1)<?> :可以是任意类型,包括Object类型以及任意的Java类
		 * 2)通配符只能出现在引用的定义中(声明中),而不能出现在创建对象中
		 * 3)其实使用通配符后,引用类型与创建对象的类型还是一致(只是系统不知道)
		 * 
		 */
		ArrayList<?> c3 =c1;
		//与上面等价===Collection<?> c1=new ArrayList<Object>() 
		//c3.add("1");----报错原因:使用了与泛型有关的方法---原因:?不知道是啥?
        System.out.println(c3.get(0));//虽然返回值类型是?,但?类型(任意类型)也是Object类的子类

		//(4)那么分析这种通配符方式和泛型推断的区别?
		/**
		 * (1)通配符方式:
		 * 参数中的通配符可以被赋任何值(类型),但同时你也不知道通配符被赋了什么值(类型);
		 * 当你不知道“?”是什么时,就不能使用任何与泛型相关的方法;
		 * 也就是说add()方法的参数类型(E=?)不知道是啥?不能再使用它的与泛型相关的方法了
		 * 注意:可以使用get()方法---与泛型无关,接受类型为Object(非泛型E),得益于Object类是所有类的父类
		 * (2)泛型推断方式:
		 * 可以使用与泛型有关的方法
		 * ********************************************
		 * 例如:
		 * c2.add("hello");是正确的
		 * 而c3.add(“k”)是错误的,因为Collection类的add()方法的参数是T类型,
		 * 由于<?>使你不知道T是什么类型, 你怎么去添加String的东西给add呢?
		 */
		
		//(5)<? extends E>:向下限定,E类型以及E类型的子类
		ArrayList<? extends Object> c5 = c1 ;
		//c1对象的的引用参数类型是:Object
		//c5.add("hello");---不能使用与泛型相关的方法(主要是方法的参数类型是泛型的情况)
		System.out.println(c5.get(0));
		//补充
		List<? extends Number> list=new ArrayList<Double>();
		
		//(6)<? super E>:向上限定,E类型以及E类型的父类
		ArrayList<? super Animal> c6 = c1;
		c6.add(new Cat());
		//底层:? e=new Cat();----向上转型了---只知道?是Cat的父类,实际?是Object类
        //可以使用与泛型有关的方法
		List<? super Integer> list1=new ArrayList<Number>();
	}
}

//自定义两个类
class Animal{
	
}

class Cat extends Animal{
	
}

相关链接:1点击打开链接,2点击打开链接(里面的推荐阅读),3点击打开链接

未完待续


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值