import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Genericj {
/*
2017-02-19 14:22:27
泛型
编译时不检查类型发生的异常
ClassCatException异常
参数化泛型parameterizen type
允许程序在创建集合是指定集合元素的类型
使集合只能保存指定类型的数据
参数化类型被称为泛型 Geneic
*/
/*
2017-02-19 14:42:51
泛型类、接口
当创建带泛型声明的自定义类,为该类定义构造器是,构造器还是原来的类名,不要增加泛型声明
从泛型类派生子类
可以为带有泛型的接口、类创建实现类、子类
当extends 或者implements 时 不能包含类型形参
其实并不存在泛型类,
ArrayList <String> 当成ArrayList的子类
事实上 ArrayList<String> 类也确实像一种特殊的ArrayList类
但是 <String>只是一个类型
系统并没有为 ArrayList<String> 生成新的class文件, 也不会当做新的类来处理
不管泛型的类型是什么 ,在运行时总是有同样的class
不管传入什么类型,依然是一个class
在内存中也只占用一块内存,
因此在静态方法、静态初始化块、静态变量的声明和初始化中不允许使用类型作为类型形参
instanceof 运算符 后不能使用泛型类
*/
/*
2017-02-19 15:39:04
类型通配符
当形参的类型不确定时,就需要使用通配符来定义 泛型
? 匹配任何
List<?> 表示list 可以是任何List的父类
? enteds Type 限制通配符
表示 只有Type的子类型才可以
?表示未知类型,但必须是Type 的子类型
这个称为 通配符的上限(upper bound)
? super Type 限制通配符
表示 只有Type 本身或者是Type 的父类才可以
泛型设计的原则:
只要代码在编译时没有出现警告,就不会遇到运行时的ClassCaseExcpetion
类型推断
可以通过调用方法的上下文来推断类型参数的目标类型
在方法调用链中,将推断得到的类型参数传递到最后一个方法
泛型声明的类总应该带着类型参数
在使用时可以不指定实际的类型参数,
如果没有指定实际的类型参数
则该类型参数被称作 raw type 原始类型
默认是声明该类型参数时的第一个上限类型
当一个具有泛型信息的对象赋予一个没有泛型信息的变量时,所有的泛型信息都将被扔掉
被称作擦出
*/
/*
2017-02-19 16:41:19
泛型方法Generic Method
定义方法时也可以自己定义类型形参
修饰符<T,S> 返回值类型 方法名 (形参列表){
}
比普通的方法签名多了一个类型形参声明
*/
/*
2017-02-19 16:54:25
泛型方法和类型通配符的区别
泛型方法允许类型参数被用来表示方法的一个或多个参数之间的类型以来关系
或者方法返回值与类型之间的类型依赖关系
如果没有这样的类型依赖关系,就不应该使用泛型方法
类型形参 T 产生的唯一效果是可以在不同的调用点传入不同的实际类型
这种情况,需要使用通配符
通配符就是被设计用来支持灵活的子类化
类型通配符既可以在方法签名中定义形参的类型,也可以用于定义类型变量的类型
泛型方法中的类型形参必须在对应方法中显示声明
*/
/*
2017-02-19 17:35:57
泛型构造器
泛型方法允许在方法签名中声明类型形参一样,
Java也允许在构造器签名中声明类型形参
这样就产生所谓的泛型构造器
允许调用构造器时使用一对尖括号来代表泛型信息
程序显示指定了泛型构造器中声明的类型形参的实际类型
则不可以使用菱形语法
*/
/*
2017-02-19 18:03:26
泛型与数组
如果一段代码在编译时没有突出 unchecked 未经检查的转换警告,则程序在运行时不会引发ClassCastException异常
所以数组元素的类型不能包含类型变量或类型形参
除非是无上限的类型通配符
但可以声明元素类型包含类型变量或类型形参的数组
// List<String>[] err =new ArrayList[2];
但是不能创建该对象
会引发ClassCastException 异常
*/
<T> void method2 (T[] t ,Collection<T> collection) {
for (T val : t) {
collection.add(val);
}
//将固定的类型全部改为 T
}
void method1(String[] strings , Collection<String> collection){
//将一个字符数组中的元素添加到一个集合中国
for (String s : strings) {
collection.add(s);
}
}
public static void main(String[] args) {
List<String> arraylist = new ArrayList<>(); // 创建list 只能存储string类型的数据
arraylist.add("arraylist");
arraylist.add("array");
arraylist.add("list");
arraylist.add(null);
arraylist.forEach(e -> System.out.println(e)); // 输出list 中的内容
Map<Integer, Integer> hashMap = new HashMap<>();
//用菱形的括号 来包含数据类型 这种语法也叫做 菱形语法
List<Integer> intArrayList = new ArrayList<>();
intArrayList.add(1);
intArrayList.add(3);
intArrayList.add(5);
intArrayList.forEach(e -> System.out.println(e));
// 通配符
// List<?> list = new ArrayList<>(); 不能这样写, 则不能添加元素
System.out.println();
Apple<String> apple = new Apple("pingguo"); //传入String类型的
System.out.println(apple.getInfo());
Apple<Integer> apple2 = new Apple(2);// 传入int 类型
System.out.println(apple2.getInfo());
new <Integer> Apple(2);
}
}
interface Generici<g> { // 声明接口时定义一个类型形参,该形参名为 g
/*
* 允许在定义接口、类声明类型形参,类类型形参在正科接口、类体内可以当场类型使用,几乎所有可以使用普通类型的地方都可以使用这种类型形参
* 包含泛型声明的类型可以在定义变量、创建对象时传入一个类型实参,从而可以动态的生成无数个逻辑上的子类,但这种子类在物理上并不存在
*/
}
class Apple<T> {
private T info;
private T t;
public Apple() {
//构造方法不用带 类型
}
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
public <T> Apple(T t) {
System.out.println("泛型构造器");
System.out.println(t);
}
}
class c extends Apple{
// 继承带泛型的类时 不能跟类型形参
}
class a extends Apple<String>{
//传入string 类型
}
// class b extends Apple<T>{ 不能直接跟 类型形参
class e< T extends Number>{ //类型的上限是Nuber 则实际类型只能是Number 中的类型
T col;
public e() {
e<Integer> e1 =new e<Integer>();
e<Double> e2 =new e<Double>();
// e<String> e2 =new e<String>(); 则会报错
}
}
class q <T extends Apple<?>>{
public q() {
q<c> qc = new q<>();
// q<e> qe = new e<>(); e 非 apple 的子类 ,则编译报错
}
}
Generic
最新推荐文章于 2024-04-14 13:50:15 发布