数组可以在创建的时候就指定存放的数据类型,这样放入不同类型的时候就会发生编译错误。
而集合却可以存储多种不同类型,这样的话如果是遍历的时候在集合中装了好多不同的数据类型的时候,十分容易发生类型转换错误
集合也模仿数组的做法,在创建对象的时候明确数据的数据类型
这种技术被称为:泛型 泛型是一种把类型明确的工作推迟到创建对象或者调用方法的时候才明确的特殊的类型。参数化类型,把类型当做参数一样的传递。
格式:<数据类型> 此处的数据类型只能是引用数据类型 好处:
把运行期的问题提前到了编译期间
避免了强制类型转换
优化了程序设计,解决了黄色警告线 泛型的由来:
程序早期使用的是Object代替任意引用数据类型,但是在实际用用中会出现类型转换问题,索引JDK5引入了泛型来解决这个安全性问题
package com.Generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
* 定义了一个List集合,先后加入了两个字符串类型的值和一个Integer类型的值,这时候,此时list的默认类型为Object
* 在之后的循环中,由于忘记之前在list中也加入了Integer,引发类型转换异常
* 为了让集合能够记住集合内元素各种类型,且能达到只要编译期不出现问题,运行期间就不会出现类型转换异常,引入了
* 泛型
*
* 什么是泛型?
* 泛型,即“参数化类型”。一提到参数,最熟悉的就是已定义方法时有形参,然后调用此方法传递实参。那么参数化类型怎
* 么理解呢?顾名思义,就是将原来的类型由具体的类型参数化,类似于方法中的变量参数,此时类型也可以定义成参数形
* 式(可以称之为类型形参),然后在使用时传入具体的类型(类型实参)
*
*
* 采用泛型写法后,在test02中想加入Integer类型会出现编译错误,通过List<String>,直接限定了list集合中只能含有
* String类型的元素,从而在遍历的时候不需要进行强制类型转换,因为此时,集合能够记住元素的类型,编译期已经可以
* 确定它是String类型了
*
*结合上面的泛型定义,我们知道在List<String>中,String是形式参数,也就是说,相应的List接口中肯定含有类型的形参。
*而且get()方法的返回结果也是直接此形参类型(也就是对应的传入的类型实参)。
*
*可以看到,在List接口中采用泛型化定义后,<E>中的E表示类型参数,可以接受具体的类型实参,接口定义中,凡是出现E的
*地方均表示相同的接受外部的类型实参
*/
public class GenericTest {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("guo");
list.add("liu");
//list.add(100);这里就无法添加进入Integer类型的元素了 for(int i=0;i<list.size();i++){
String name=list.get(i);//这里不需要强制转换了
System.out.println("name:"+name);
}
} public void test01(){
//引出泛型
List list=new ArrayList();
list.add("guo");
list.add("liu");
list.add(100); for(int i=0;i<list.size();i++){
String name=(String) list.get(i);
System.out.println("name:"+name);
}
}
public void test02(){
//第一次使用泛型
List<String> list=new ArrayList<String>();
list.add("guo");
list.add("liu");
//list.add(100);这里就无法添加进入Integer类型的元素了 for(int i=0;i<list.size();i++){
String name=list.get(i);//这里不需要强制转换了
System.out.println("name:"+name);
}
}
} interface Listyuanma<E> extends Collection<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean add(E e); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean addAll(int index, Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); void clear(); boolean equals(Object o); int hashCode(); E get(int index); E set(int index, E element); void add(int index, E element); E remove(int index); int indexOf(Object o); int lastIndexOf(Object o); ListIterator<E> listIterator(); ListIterator<E> listIterator(int index); List<E> subList(int fromIndex, int toIndex);
} package com.Generic;
/*
* 从前面了解了泛型的具体运作过程。也知道了接口、类、方法可以使用泛型去定义以及相关的使用。是的,在具体使用时候,可以分为泛型接口,泛型类,泛型方法
*
* 在泛型接口、泛型类和泛型方法的定义过程中,我们常用的如T K V E等形式的参数常常用于表示泛型形参,由于接受外部使用的时候传入的类型实参。那么对于传入的不同类型参数,
* 生成的相应对象实例的类型是不是不一样的呢?
*
* 下面的例子,我们发现,在使用泛型类的时候,虽然传入了不同的泛型实参,但是并没有真正意义上生成不同的类,传入不同泛型参数的泛型类在内存中只有一个,即还是原来的最基
* 本的类型,当然,在java中可以理解成多个不同的泛型类型
*
* 究其原因,在于java中泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确的泛型检查泛型结果后,会将泛型的相关信息擦除。也就是说,成功编译
* 后的class文件中是不包含任何泛型信息的,泛型信息不回进入到运行阶段。
*
* 对比总结成一句话:泛型类型在逻辑上看已堪称多个不同的类型,实际上都是相同的基本类型
*/
public class GenericTest02 {
public static void main(String[] args) {
Box<String> name=new Box<String>("corn");
Box<Integer> age=new Box<Integer>(712);
//System.out.println(name.getData()); System.out.println("name class:"+name.getClass());
System.out.println("age class:"+age.getClass());
System.out.println(name.getClass()==age.getClass());
}
} /*GenericTest02 的class文件反编译后
public class GenericTest02
{ public GenericTest02()
{
} public static void main(String args[])
{
Box name = new Box("corn");
Box age = new Box(Integer.valueOf(712));
System.out.println((new StringBuilder("name class:")).append(name.getClass()).toString());
System.out.println((new StringBuilder("age class:")).append(age.getClass()).toString());
System.out.println(name.getClass() == age.getClass());
}
} */ class Box<T>{
private T data; public Box(){ } public Box(T data){
this.data=data;
} public T getData(){
return data;
}
} package com.Generic;
/*
* 通过前面的结论我们知道,Box<Number>和Box<Intefer>实际上都是Box类型,现在需要探讨一个问题,那么在逻辑上
* ,类似于Box<Number>和Box<Integer>是否可以看成是具有父子关系的泛型呢?
*
* 我们发现,在age调用getData(Box<Number> data)会报错:The method getData(Box<Number>) in the type GenericTest03 is not applicable for the arguments (Box<Integer>)
* 显然,我们知道,Box<Number>在逻辑上不能视为Box<Integer>的父类,原因何在呢?
*
* 在这个例子中出现错误,我们可以使用反证法来说明。
*
* 假如Box<Number>在逻辑上可以视为Box<Integer>的父类,那么就不会报错了。那么问题来了,通过getDate取出来的 到底是什么类型呢?Integer、Number?且由于在编程过程中的顺序不可控,
* 导致在必要的时候必须要进行类型判断,然后进行强制类型转换,显然,这与泛型的理念相矛盾。因此,在逻辑上Box<Number>不能视为Box<Integer>的父类
*
* 解决问题:
* 定义一个新的函数,方法的重载?这与java中的多态理念是相违背的。因此我们需要一个用来表示同时是Box<Integer>和Box<Number>父类的一个引用类型,由此,类型通配符应运而生。
*
* 类型通配符一般使用?代替具体的参数类型。注意了,此处是类型实参,而不是类型形参!且Box<?>在逻辑上是Box<Integer>、Box<Integer>等所有Box<具体类型实参>的父类。由此,我们仍然
* 可以定义泛型方法来完成此需求。
*
* 有时候,我们可能对类型实参有进一步限制?此时可能用到通配符上限和通配符下限
* Box<? extends Number>代表Box的泛型只能是Number和Number的子类
* Box<? super Number>代表Box的泛型只能是Number和Number的父类
*
* java泛型主要是用在集合中,并没有泛型数组一说
*/
public class GenericTest03 {
public static void main(String[] args) {
Box<Number> name=new Box<Number>(99);
Box<Integer> age=new Box<Integer>(712);
Box<Double> h=new Box<Double>(0.2);
Box<String> s=new Box<String>("12s");
getData03(name);
getData03(age);
//getData03(h); 报错,类型
//getData03(s); 报错,类型
}
public void test01(){
Box<Number> name=new Box<Number>(99);
Box<Integer> age=new Box<Integer>(712);
Box<Double> h=new Box<Double>(0.2);
Box<String> s=new Box<String>("12s");
getData02(name);
getData02(age);
getData02(h);
//getData02(s); 这里会报错
} public void test02(){
Box<Number> name=new Box<Number>(99);
Box<Integer> age=new Box<Integer>(712);
Box<Double> h=new Box<Double>(0.2);
Box<String> s=new Box<String>("12s");
getData(name);
getData(age);
getData(h);
getData(s);
}
public static void getData00(Box<Number> data){
System.out.println("data:"+data.getData());
}
//Box的所有泛型
public static void getData(Box<?> data){
System.out.println("data:"+data.getData());
} //限制只能是泛型为Number和Number的子类泛型
public static void getData02(Box<? extends Number> data){
System.out.println("data:"+data.getData());
}
//限制只能是泛型为Integer和Integer的父类泛型
public static void getData03(Box<? super Integer> data){
System.out.println("data:"+data.getData());
}
}
package jdk5的新特性;

/*
* 可变参数
* 举个例子:如果需要计算一组数的和,但不知道计算的数有多少个,那怎么办呢?
* 使用方法重载? 这是不现实的。
* 所以我们有了可变参数
* 形式: 数据类型...变量名 表示接受n个该类型的变量
* 可变参数的方式接受到了数据怎么使用呢?
* 通过查看源码,反编译的方式。我们发现,可变参数其实本质上是一个指定类型数组类型的参数,
* 在调用方法的时候构建固定长度的固定类型数组,然后传入方法
* 使用可变参数的时候需要注意:
* 可变参数一般放在参数列表的最后面。可变参数的形参名表示的是一个数组名
*/
public class ChangeParam {
public static void main(String[] args) {
System.out.println(getCount(1,2,3));
System.out.println(getCount(1,2));
System.out.println(getCount());
System.out.println(getCount(new int[]{1,2,3}));
}
/*public int getCount(int a,int b){
return a+b;
}
public int getCount(int a,int b,int c){
return a+b+c;
}*/
//...
public static int getCount(int...in){
int c=0;
for(int s:in){
c+=s;
}
//return 0;
return c;
}
} package jdk5的新特性; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class ArrayAsList {
//发现Arrays的asList使用的是可变参数
//public static <T> List<T> asList(T... a)
public static void main(String[] args) {
ArrayList<Integer> al=new ArrayList<Integer>();
List ss= Arrays.asList(12,24,12);
// ss.add(3);
//ss.remove(3); 通过它获得的实质上是一个数组,只能修改内容,不能操作长度
ss.set(2, 23);
System.out.println(ss); }
}
package jdk5的新特性;

//import java.sql.Date;

public class StaticImport {
public static void main(String[] args) {
//System.out.println(Date.valueOf("12"));
//System.out.println(java.sql.Date.valueOf("12"));
}
}
/*
* 原来的导入都是导入的是类。使用import 包名.类名
* 如果需要不导入类,就需要这样:java.sql.Date.valueOf("12")
* jdk5提供了静态导入的功能:
* 在类名的上面导入静态方法,暂时没找到例子
* import 类名.方法名格式。 注意方法必须是静态方法
* 当静态导入的方法与类中的方法重名的时候,必须使用这种形式java.sql.Date.valueOf("12")
*/

JDK5的新特性:泛型、可变参数、静态导入的更多相关文章

  1. JDK5的新特性之可变参数&Arrays.asList()方法

    [代码] package com.hxl; import java.util.Arrays; import java.util.List; public class Test { public sta ...

  2. JDK5新特性之 可变参数的方法

    可变参数的方法:不知道这个方法该定义多少个参数 注意: > 参数实际上是数组 > 必须写在参数列表最后一个 package cn.itcast.day24.varparam; import ...

  3. jdk1.5新特性之------->可变参数

    /* jdk1.5新特性之------->可变参数 需求: 定义一个函数做加法功能(函数做几个数据 的加法功能是不确定). 可变参数的格式: 数据类型... 变量名 可变参数要 注意的细节: 1 ...

  4. JDK5新特性:可变参数方法

    JDK1.5增加可变参方法,其定义格式为: 访问修饰符 返回值类型 方法标识符(参数类型 参数标识符1,参数类型 参数标识符2,参数类型...参数标识符){} 如可能要定义一个求和功能的方法,但求和的 ...

  5. C++11新特性之五——可变参数模板

    有些时候,我们定义一个函数,可能这个函数需要支持可变长参数,也就是说调用者可以传入任意个数的参数.比如C函数printf(). 我们可以这么调用. printf(); 那么这个函数是怎么实现的呢?其实 ...

  6. JDK5 新特性之 可变参数的方法(2)---asList

    > Arrays.asList(T - a)方法的使用 >UnsupportedOperationException分析     Arrays.asList(T - a)方法的使用 pac ...

  7. java新特性之可变参数

    public class NewDemo01 {     public static void main(String[] args) {         System.out.print(" ...

  8. Java JDK5新特性-泛型

    2017-10-30 22:47:11 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质 ...

  9. Javaweb学习笔记——(七)——————myexlipse基本使用、jdk5.0新特性及反射讲解

    1.debug调试模式: *使用这种模式,调试程序(看到程序运行停止在这一行) -显示出来行号 -双击左边,出现一个圆点,表示设置了一个断点 *使用debug as方式,运行程序 -特使是否进入到调试 ...

随机推荐

  1. mysqldump 导出统一限制每张数据表导出的记录数

    mysqldump 导出统一限制每张数据表导出的记录数 在工作过程中,需要将生产的数据导出到本地开发环境,我希望可以导出部分数据.而服务器数据量比较大(上千万),如果选择直接从服务器导出数据, 正在运 ...

  2. MR的shuffle和Spark的shuffle之间的区别

    mr的shuffle mapShuffle 数据存到hdfs中是以块进行存储的,每一个块对应一个分片,maptask就是从分片中获取数据的 在某个节点上启动了map Task,map Task读取是通 ...

  3. Windows7系统运行hadoop报Failed to locate the winutils binary in the hadoop binary path错误

    程序运行的过程中,报Failed to locate the winutils binary in the hadoop binary path  Java.io.IOException: Could ...

  4. python基础之if语句

    python之if语句 通用格式 if <test1>: <do something> elif: <do something> else: <do some ...

  5. 2018-2019 ACM-ICPC, Asia East Continent Finals Solution

    D. Deja vu of … Go Players 签. #include <bits/stdc++.h> using namespace std; int t, n, m; int m ...

  6. windows监听socket和标准输入

    原来的代码 def input_command(self): msg = raw_input('\nPlease input the command:') remote_id = raw_input( ...

  7. SQL学习笔记之MySQL查询练习2

    (网络搜集) 0x00 数据准备 CREATE TABLE students (sno ) NOT NULL, sname ) NOT NULL, ssex ) NOT NULL, sbirthday ...

  8. 2017-2018-1 Java小组-1623 第二周作业

    2017-2018-1 Java小组-1623 第二周作业 关于游戏软件的问题 讨论结果 20162301张师瑜 20162305李昱兴 20162306陈是奇 20162308马平川 2016231 ...

  9. ESXi主机遗忘密码重置密码

    ESXi版本:6.0.0 VMware-VMvisor-Installer-6.0.0.update02-3620759.x86_64-Dell_Customized-A00.iso 使用和服务器系统 ...

  10. 从0开始学习 GITHUB 系列之「GITHUB 常见的几种操作」【转】

    本文转载自:http://stormzhang.com/github/2016/09/21/learn-github-from-zero8/ 版权声明:本文为 stormzhang 原创文章,可以随意 ...