2、泛型(Generic)

当集合中存储的对象类型不同时,那么会导致程序在运行的时候的转型异常

 1 import java.util.ArrayList;
2 import java.util.Iterator;
3
4 public class Demo5 {
5 public static void main(String[] args) {
6 ArrayList arr = new ArrayList();
7 arr.add(new Tiger("华南虎"));
8 arr.add(new Tiger("东北虎"));
9 arr.add(new Sheep("喜羊羊"));
10 System.out.println(arr);
11 Iterator it = arr.iterator();
12 while (it.hasNext()) {
13 Object next = it.next();
14 Tiger t = (Tiger) next;
15 t.eat();
16 }
17
18 }
19 }
20 class Tiger {
21 String name;
22
23 public Tiger() {
24
25 }
26
27 public Tiger(String name) {
28 this.name = name;
29 }
30
31 @Override
32 public String toString() {
33
34 return "Tiger@name:" + this.name;
35 }
36
37 public void eat() {
38 System.out.println(this.name + "吃羊");
39 }
40 }
41
42 class Sheep {
43 String name;
44
45 public Sheep() {
46
47 }
48
49 public Sheep(String name) {
50 this.name = name;
51 }
52
53 @Override
54 public String toString() {
55 return "Sheep@name:" + this.name;
56 }
57
58 public void eat() {
59 System.out.println(this.name + "吃青草");
60 }
61 }

原因 :发现虽然集合可以存储任意对象,但是如果需要使用对象的特有方法,那么就需要类型转换,如果集合中存入的对象不同,可能引发类型转换异常.

[Tiger@name:华南虎, Tiger@name:东北虎, Sheep@name:喜羊羊]
华南虎吃羊
东北虎吃羊
Exception in thread "main" java.lang.ClassCastException: cn.itcast.gz.map.Sheep cannot be cast to cn.itcast.gz.map.Tiger
at cn.itcast.gz.map.Demo5.main(Demo5.java:17)

出现问题:

存入的是特定的对象,取出的时候是Object对象,需要强制类型转换,可能诱发类型转换异常.

无法控制存入的是什么类型的对象,取出对象的时候进行强转时可能诱发异常.而且在编译时期无法发现问题.

虽然可以再类型转换的时候通过if语句进行类型检查(instanceof),但是效率较低.(例如吃饭的时候,还需要判断米饭里有没有沙子,吃饭效率低).可以通过给容器加限定的形式规定容器只能存储一种类型的对象.

就像给容器贴标签说明该容器中只能存储什么样类型的对象。

所以在jdk5.0后出现了泛型

泛型应用

格式

1.  集合类<类类型>  变量名  = new  集合类<类类型>();

 1 public class Demo5 {
2 public static void main(String[] args) {
3 // 使用泛型后,规定该集合只能放羊,老虎就进不来了.
4 ArrayList<Sheep> arr = new ArrayList<Sheep>();
5 arr.add(new Sheep("美羊羊"));
6 arr.add(new Sheep("懒洋洋"));
7 arr.add(new Sheep("喜羊羊"));
8 // 编译失败
9 // arr.add(new Tiger("东北虎"));
10 System.out.println(arr);
11 Iterator<Sheep> it = arr.iterator();
12 while (it.hasNext()) {
13 // 使用泛型后,不需要强制类型转换了
14 Sheep next = it.next();
15 next.eat();
16 }
17
18 }
19 }

优点

1. 将运行时的异常提前至编译时发生。

2. 获取元素的时候无需强转类型,就避免了类型转换的异常问题

格式  通过<> 来指定容器中元素的类型.

什么时候使用泛型:当类中操作的引用数据类型不确定的时候,就可以使用泛型类.

JDK5.0之前的Comparable

package java.lang;
public interface Comparable { public int compareTo(Object o);
}

JDK5.0之后的Comparable

package java.lang;
public interface Comparable<T> { public int compareTo(T o);
}

这里的<T>表示泛型类型,随后可以传入具体的类型来替换它.

细节一:声明好泛型类型之后,集合中只能存放特定类型元素

 1 public class Demo6 {
2 public static void main(String[] args) {
3 //创建一个存储字符串的list
4 ArrayList<String> arr=new ArrayList<String>();
5 arr.add("gz");
6 arr.add("itcast");
7 //存储非字符串编译报错.
8 arr.add(1);
9 }
10 }

细节二:泛型类型必须是引用类型

 1 public class Demo6 {
2 public static void main(String[] args) {
3 // 泛型类型必须是引用类型,也就是说集合不能存储基本数据类型
4 // ArrayList<int> arr2=new ArrayList<int>();
5
6 // 使用基本数据类型的包装类
7 ArrayList<Integer> arr2 = new ArrayList<Integer>();
8
9
10 }
11 }

细节三: 使用泛型后取出元素不需要类型转换.

 1 public class Demo6 {
2 public static void main(String[] args) {
3
4 ArrayList<String> arr = new ArrayList<String>();
5 arr.add("gzitcast");
6 arr.add("cditcast");
7 arr.add("bjitcast");
8 //使用泛型后取出元素不需要类型转换.
9 String str=arr.get(0);
10 System.out.println();
11 }
12 }

泛型方法

需求:写一个函数,调用者传递什么类型的变量,该函数就返回什么类型的变量?

实现一:

由于无法确定具体传递什么类型的数据.那么方法的形参就定义为Object类型.返回值也就是Object类型.但是使用该函数时需要强制类型转换.

private Object getDate(Object obj) {
return obj;
}

当不进行强制类型转换能否写出该功能.?

目前所学的知识无法解决该问题

就需要使用泛型类解决

使用的泛型的自定义来解决以上问题。

泛型: 就是将类型当作变量处理。规范泛型的定义一般是一个大写的任意字母。

1. 函数上的泛型定义

          当函数中使用了一个不明确的数据类型,那么在函数上就可以进行泛型的定义。

          public <泛型的声明> 返回值类型  函数名( 泛型 变量名  ){

          }
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5 }; new Demo6().getData(5); } public <T> T getData(T data) {
return data;
}

细节:

使用泛型方法前需要进行泛型声明,使用一对尖括号 <泛型>,声明的位置在static后返回值类型前。

当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上。

泛型类

格式
2. 类上的泛型声明 修饰符 class 类名<泛型>{ }
 1 import java.util.Arrays;
2
3 public class Demo6<T> {
4 public static void main(String[] args) {
5 // 使用泛型类,创建对象的时候需要指定具体的类型
6 new Demo6<Integer>().getData(5);
7 }
8
9 public T getData(T data) {
10 return data;
11 }
12
13 // 反序任意类型数组
14 public void reverse(T[] arr) {
15 int start = 0;
16 int end = arr.length - 1;
17 for (int i = 0; i < arr.length; i++) {
18 if (start < end) {
19 T temp = arr[start];
20 arr[start] = arr[end];
21 arr[end] = temp;
22 }
23 }
24
25 }
 1 import java.util.Arrays;
2
3 public class Demo6<T> {
4 public static void main(String[] args) {
5 // 使用泛型类,创建对象的时候需要指定具体的类型
6 new Demo6<Integer>().getData(5);
7 }
8
9 public T getData(T data) {
10 return data;
11 }
12
13 // 反序任意类型数组
14 public void reverse(T[] arr) {
15 int start = 0;
16 int end = arr.length - 1;
17 for (int i = 0; i < arr.length; i++) {
18 if (start < end) {
19 T temp = arr[start];
20 arr[start] = arr[end];
21 arr[end] = temp;
22 }
23 }
24
25 }

在泛型类中定义一个静态方法

 public class Demo6<T> {
public static void main(String[] args) {
System.out.println(getData2(100));
} public T getData(T data) {
return data;
} //静态方法
public static T getData2(T data) {
return data;
} }

注意:静态方法不可以使用类中定义的泛型

因为类中的泛型需要在对象初始化时指定具体的类型,而静态优先于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前

泛型类细节:

1、创建对象的时候要指定泛型的具体类型
2、创建对象时可以不指定泛型的具体类型(和创建集合对象一眼)。默认是Object,例如我们使用集合存储元素的时候没有使用泛型就是那么参数的类型就是Object
3、类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么
需要在函数上独立声明。
4、如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作一种数据类型。
5、所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型。

泛型练习:

定义泛型成员

 public class Demo7 {
public static void main(String[] args) {
Father<String> f = new Father<String>("jack");
System.out.println(f.getT());
Father<Integer> f2 = new Father<Integer>(20);
System.out.println(f2.getT());
} } class Father<T> {
private T t; public Father() { } public Father(T t) {
super();
this.t = t;
} public T getT() {
return t;
} public void setT(T t) {
this.t = t;
} }

如果Father类有子类,子类该如何实现

 public class Demo7 {
public static void main(String[] args) {
Father<String> f = new Father<String>("jack");
System.out.println(f.getT());
Father<Integer> f2 = new Father<Integer>(20);
System.out.println(f2.getT());
} } class Father<T> {
private T t; public Father() { } public Father(T t) {
super();
this.t = t;
} public T getT() {
return t;
} public void setT(T t) {
this.t = t;
} }
//子类指定了具体的类型
class Son extends Father<String>{ }
//子类也需要使用泛型
class Son3<T> extends Father<T>{ }
//错误写法,父类上定义有泛型需要进行处理
class Son2 extends Father<T>{ }

泛型接口

 public class Demo8 {
public static void main(String[] args) {
MyInter<String> my = new MyInter<String>();
my.print("泛型"); MyInter2 my2 = new MyInter2();
my.print("只能传字符串");
}
} interface Inter<T> {
void print(T t);
} // 实现不知为何类型时可以这样定义
class MyInter<T> implements Inter<T> {
public void print(T t) {
System.out.println("myprint:" + t);
}
}
//使用接口时明确具体类型。
class MyInter2 implements Inter<String> { @Override
public void print(String t) {
System.out.println("myprint:" + t); } }

day1 java基础回顾-泛型的更多相关文章

  1. day1 java基础回顾- 文件路径

    绝对路径 以根目录或某盘符开头的路径(或者说完整的路径) 例如: l  c:/a.txt (Windows操作系统中) l  c:/xxx/a.txt (Windows操作系统中) l  /var/x ...

  2. day1 java基础回顾-内省

    为什么要学内省? 开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性. 内省是用于操作j ...

  3. day1 java基础回顾- Properties类与配置文件

    Properties配置文件说明 Properties类对应.properties文件.文件内容是键值对,键值对之间使用"="或空格隔开.开头是"#"的表示注释 ...

  4. day1 java基础回顾-Junit单元测试

    Junit单元测试框架的基本使用 一.搭建环境: 导入junit.jar包(junit4) 二.写测试类: 0,一般一个类对应一个测试类. 1,测试类与被测试类最好是放到同一个包中(可以是不同的源文件 ...

  5. day1 java基础回顾-多线程

    启动线程方式 方式一:继承Thread. 1. 自定义一个类继承Thread类. 2. 重写Thread的run方法,把自定义线程的任务代码定义在run方法上. 3. 创建Thread子类的对象,并且 ...

  6. day1 java基础回顾-IO流

    IO流的分类 注:这几个类都是抽象类. IO解决问题: 解决设备与设备之间 的数据传输问题. 比如: 硬盘--->内存 内存----->硬盘 字节流: 输入字节流:---------| I ...

  7. day1 java基础回顾-集合

    1.集合 1.1 集合的类型与各自的特性 ---|Collection: 单列集合 ---|List: 有存储顺序, 可重复 ---|ArrayList: 数组实现, 查找快, 增删慢 由于是数组实现 ...

  8. 四、Android学习第四天——JAVA基础回顾(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...

  9. 黑马程序员:Java基础总结----泛型(高级)

    黑马程序员:Java基础总结 泛型(高级)   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...

随机推荐

  1. 【BZOJ4453】cys就是要拿英魂! 后缀数组+单调栈+set

    [BZOJ4453]cys就是要拿英魂! Description pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个 ...

  2. EasyNVR无插件流媒体服务器前端技术防止重复提交的方法

    现在随着接触EasyNVR时间越来越长,越发的觉得EasyNVR真的是一个"神器".从功能上来说自身不仅可以拉出来使用(具体功能搜索EasyNVR一定有惊喜!),也可以作为设备端与 ...

  3. 九度OJ 1154:Jungle Roads(丛林路径) (最小生成树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:832 解决:555 题目描述: The Head Elder of the tropical island of Lagrishan has ...

  4. 九度OJ 1021:统计字符 (基础题)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5418 解决:3146 题目描述:     统计一个给定字符串中指定的字符出现的次数. 输入:     测试输入包含若干测试用例,每个测试用 ...

  5. iframe式ajax调用

    1.新建 a.html <!doctype html> <html> <head> <meta charset='utf-8'> <title&g ...

  6. 【转载】基于注解的SpringMVC简单介绍

    SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是DispatcherServlet,DispatcherServlet负责转发每一个Request请 ...

  7. eslint 配合 git (husky)

    为了保证每次提交的 git 代码是正确的,为此我们可以使用 eslint 配合 git hook, 在进行git commit 的时候验证eslint规范 如果 eslint 验证不通过,则不能提交. ...

  8. delphi XE7 HttpEncode 编码问题

    近期在做网址编码相关的工作,发现在用 XE5 编译的时候,一切正常,拿 到 XE7下 就 结果错误了.百度了下,谷歌 了下,有人提出,但是,我没有找到答案,也许都没有碰到这个问题,也许都己经自己默默的 ...

  9. nodejs中的子进程,深入解析child_process模块和cluster模块

    Node.js的进程管理   node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作.node的 ...

  10. NPM 与 Nodejs

    安装了Nodejs之后,NPM也安装好了 如何知道当前是否已经安装Nodejs和NPM了呢? node -v //查看当前nodejs的版本 npm -v //查看当前npm的版本 NPM 初始化 n ...