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. Netty入门 - 秒懂

    目录 Netty 入门 前言: 建立项目 编写一个Discard Handler 处理器 编写一个Discard 服务器 线程组 启动帮助类 设置Channel 通道的选项 测试:发送消息到Disca ...

  2. regularexpression_action

    re.compile('"ssid":"[^"]*"}',re.MULTILINE) regex ,str_= re.compile('"s ...

  3. Webpack探索【8】--- 模块热替换详解

    本文主要讲模块热替换相关内容.

  4. Redis3.x HA 方案(基于 Sentinel 方式)

    第一部分 Redis-HA 搭建 一.Redis-HA 拓扑 一主两从,主从复制,故障时主从切换 三个Redis节点 + Sentinel 节点 Master          127.0.0.1   ...

  5. 使用 Docker LNMP 部署 PHP 运行环境

    简介 Docker LNMP 是基于 Docker 的 PHP 集成开发环境. Github 地址:https://github.com/YanlongMa/docker-lnmp 包含软件 ngin ...

  6. Gemini.Workflow 双子工作流入门教程五:业务表单开发

    简介: Gemini.Workflow 双子工作流,是一套功能强大,使用简单的工作流,简称双子流,目前配套集成在Aries框架中. 下面介绍本篇教程:业务表单开发. 业务表单开发 业务表单的开发,和在 ...

  7. empty blank

    非nil对象才能调用 empty nil: 对象是否存在empty: ”“ []blank: nil emptypresent: ! blank

  8. save create

    其中 create 和 create!就等於 new 完就 save 和 save!,有無驚嘆號的差別 在於 validate 資料驗證不正確的動作,無驚嘆號版本會回傳布林值(true 或 false ...

  9. P5012 水の数列

    P5012 水の数列 离线处理出选择每个数得到区间数得到刚开始的得分 \(RMQ_{ij}\)表示\(i\)~\(i\)+\(2^j\)-1的区间最大值 #include<cstdio> ...

  10. System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration sect

    An error has occurred creating the configuration section handler for userSettings/Microsoft.SqlServe ...