黑马程序员之----------Java泛型

来源:互联网 发布:php断点续传 上传 编辑:程序博客网 时间:2024/05/18 17:27


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培

训、.Net培训</a>、期待与您交流! -------

------------------------java泛型笔记-------------------------- 

 

 

1. 泛型在类、接口和方法中定义,在实现和实例化时使用。

/* 泛型就是指在对象建立时,不指定类中属性的具体类型,由外部声明及实例化对象时指定具体类型。

 * 其只要原理是在类声明时通过一个标识,表示类中某个属性的类型或者是某个方法的返回值及参数类型。

 * 这样在类声明或实例化的时候只要指定好需要的具体类型即可。

 * public class <T ,M ....> {

 *      private T t;

 *      public T show (){}

 *      public int show (T t){}

 * }

 */

//声明泛型

class Point<T>{//此处可以是任意标识符

private T var;//此变量由外部决定

public T getVar(){//返回值由外部决定

return var;

}

public void setVar(T var){

this.var=var;

}

}

public class GenericsDemmo1 {

public static void main(String [] args){

//里面的var类型为Integer

Point <Integer> pp=new Point<Integer>();

//设置泛型可以保证数据类型的一致接受的都是Integer类型

//设置数字,自动装箱

pp.setVar(30);

//会报错,设置的内容与泛型不一致

//pp.setVar("zhang");

System.out.print(pp.getVar()*2);

}

}

 

2./* 泛型方法

 * 1.定义一个可以接收任意类型的数据

 * public <T> T fun(T t){return t};

 */

 

class Pointer<T> {// 此处可以是任意标识符

private T var;// 此变量由外部决定

public Pointer(T var){//构造函数声明,与类上声明无关

this.var=var;

}

 

public T getVar() {// 返回值由外部决定

return var;

}

 

public void setVar(T var) {//设置类型由外部决定

this.var = var;

}

}

 

public class GenericsDemmo2 {

public static void main(String[] args) {

// 里面的var类型为String

Pointer<String> pp = new Pointer<String>("小白");

Pointer<Integer> pp1 = new Pointer<Integer>(23);

//方法中的两个对象类型必须一致,否则编译错误

//add(pp,pp1);

}

//静态方法书写规范 public static <E> set<E> add(set<E> s1,set<E> s2) ; 

public static <T> void add(Pointer<T> PP,Pointer<T> PP1){

//

//System.out.print("名字叫:"+pp.getVar()+pp1);

}

}

3./* 如果在使用类是不指定泛型,默认的为Object.

 * 会出现安全隐患

 * 通配符<?>表示任意泛型,并且如果使用<?>接受泛型对象时,不能设置被泛型指定的内容

 * Info <?> i=new Info<String>();

 * 表示接收的泛型类型<?>

 * i.setVar("小白")//错误,不能设置

 * 但是此时可以设置为null

 * i.setVar(null);//可以设置

 */

 

class Notepad<K,V> {// 此处可以是任意标识符

private K key;// 此变量由外部决定

private V value;

 

public K getKey() {// 返回值由外部决定

return key;

}

 

public void setKey(K key) {//设置类型由外部决定

this.key=key;

}

public V getValue() {// 返回值由外部决定

return value;

}

 

public void setValue(V value) {//设置类型由外部决定

this.value=value;

}

}

 

public class GenericsDemmo3 {

public static void main(String[] args) {

// 里面的var类型为String

Notepad<String,Integer> pp = new Notepad<String,Integer>();

pp.setKey("小白");

pp.setValue(3);

System.out.print("名字叫:"+pp.getKey()+"现在"+pp.getValue()+"岁");

}

}

 

4./* 上限和下限

 * 上限:表示泛型类型为Person 或者是其子类

 * 声明对象:Person <? extend Person> st;

 * 定义类:public Person <T extends Person>

 * 

 * 下限:表示泛型类型为Person 或者是其父类或者是Object类

 * 声明对象:Person <? super Person> st;

 * 定义类:public Person <T extends Person>

 * 

 * 子类可以通过对象的多态性为其父类实例化。但是在泛型中,子类的泛型类型

 * 无法使用父类泛型接收。

 *  Info <String> i=new Info<String>();

 *  Info <Object> i2=i;//错误,类型不匹配

 *  虽然String是Object的子类,但在泛型中,没有此概念。只能用<?>接受

 *  Info <?> =i;//正确

 *  

 */

class Info<T extends Number>{

private T var;

public T getVar(){//返回值由外部决定

return var;

}

public void setVar(T var){

this.var=var;

}

public String toString(){

return this.var.toString();

}

}

public class GenericsDemmo4 {

public static void main(String[] args) {

Info <Integer> i=new Info<Integer>();//接收Number的子类

Info <Float> i2=new Info<Float>();//接收Number的子类

i.setVar(23);

i2.setVar(30.f);

fun(i);

fun(i2);

}

//这里设置了接收的范围上限,包括Number及其子类<? extends T>

//集合中存放元素的时候一般使用上限,可以添加父类型的元素,也可以添加子类型的元素,提高了扩展性 

public static void fun(Info<? extends Number> temp){

System.out.print(temp+",");

}

}

 

5./*

 * 下限

 */

 

class Info1<T>{//类型为T(Object)

private T var;

public T getVar(){//返回值由外部决定

return var;

}

public void setVar(T var){

this.var=var;

}

public String toString(){

return this.var.toString();

}

}

public class GenericsDemmo5 {

public static void main(String[] args) {

Info1 <String> i=new Info1<String>();//接收String型

Info1 <Object> i2=new Info1<Object>();//接收Object型

i.setVar("小白");

i2.setVar(new Object());

fun(i);

fun(i2);

}

//这里设置了范围的下限,包括String及其父类Object,<? super T>

//通常对集合中的元素进行取出操作时,可以使用下限,表示取出的元素(父类共性类型)

//也就是说对传进迭代器中的元素,全用父类去接收,以保证全部接受。

public static void fun(Info1<? super String> temp){

System.out.print(temp+",");

}

}

 

6./*泛型接口

 * public interface Info<T>{}

 * 两种实现方式

 * 1.子类实例化时,指定泛型接口类型

 * interface A <T>{

public T getVar();

}

//定义泛型接口的子类,也必须是T

class B <T> implements A <T>{

private T var;

public B(T var){

this.setVar(var);

}

public void setVar(T var){

this.var=var;

}

public T getVar(){

return this.var;

}

}

public class GenericsDemmo6 {

public static void main(String[] args) {

//定义接口的泛型类型

B <String> b=new B<String>("小白");

System.out.print("名字叫:"+b.getVar());

}

}

 * 2.继承接口时,直接指定泛型类型

 * 

 */

interface A <T>{

public T getVar();

}

//定义泛型接口的子类,也必须是T

class B  implements A <String>{

private String var;

public B(String var){

this.setVar(var);

}

public void setVar(String var){

this.var=var;

}

public String getVar(){

return this.var;

}

}

public class GenericsDemmo6 {

public static void main(String[] args) {

//实例化子类的时候,不能指定泛型 

B  b=new B("小白");

System.out.print("名字叫:"+b.getVar());

}

}

 

7. 注意:

 定义类或接口时,使用"<E extends Fruit>"这种形式,之后就可以在类中对E进行操作。

 

 定义方法所接收的参数时,使用"List<? extends Fruit>"这种形式,就可以接收这个范围的List做参数。

 

 实例化时,不能使用问号这种形式来指定泛型——不能new List<? extends Apple>();

 

 继承或实现时,也不能使用问号这种形式来指定泛型——不能public interface MyList extends List 

 <? extends Apple>

 

 不能实例化泛型类型的数组:new List<String>[3]是不合法的。 

 但是在可以确定类型的情况下,将Object数组强制转换成泛型数组是合法的,

 例如ArrayList的源码:return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 

 

 

8. 泛型的继承原则: 

1,相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。即List<String>是Collection                        <String>的子类型,List<String>可以替换Collection<String>。这种情况也适用于带有上下界的类型声明。

 

2,当泛型类的类型声明中使用了通配符的时候, 其子类型可以在两个维度上分别展开。如对Collection<? extends Number>来说,其子类型可以在Collection这个维度上展开,即List<? extends Number>和Set<? extends Number>等;也可以在Number这个层次上展开,即Collection<Double>和 Collection<Integer>等。如此循环下去,ArrayList<Long>和 HashSet<Double>等也都算是Collection<? extends Number>的子类型。

 

3,如果泛型类中包含多个类型参数,则对于每个类型参数分别应用上面的规则。 

 

 

9. 泛型的定义原则: 

1,泛型类与一般的Java类基本相同,只是在类和接口定义上多出来了用<>声明的类型参数。 

2,一个类可以有多个类型参数,如 MyClass<X, Y, Z>。 

3,每个类型参数在声明的时候可以指定上界。 

4,所声明的类型参数在Java类中可以像一般的类型一样作为方法的参数和返回值,或是作为域和局部变量的类型。 

5,由于类型擦除机制,类型参数并不能用来创建对象或是作为静态变量的类型。 

  

 

 

--------------------------------------------------------------------------------

 

 

import java.util.ArrayList;

import java.util.List;

 

class AbstractTester {

 

}

 

class Fruit {

 

}

 

class Apple extends Fruit {

 

}

 

class GenericTester extends AbstractTester {

public void test1() {

List<Apple> appleList = new ArrayList<Apple>();

appleList.add(new Apple()); // 先定义List<Apple>,填入元素,限定Apple类型

Fruit fruit = Basket.getFruit(appleList); // List<Apple>类型符合List<? extends Fruit>的要求

}

 

public void test2() {

List<Fruit> fruitList = new ArrayList<Fruit>();// 先定义List<Fruit>,填入元素,限定Fruit类型

Basket.addApple(fruitList, new Apple()); // List<Fruit>符合List<? super Apple>的要求

 

}

 

}

class Basket {

// 从泛型化的list中取出Fruit,里面的元素一定是Fruit的子类,所以都可以当作Fruit返回

public static Fruit getFruit(List<? extends Fruit> list) {

return list.get(0);

}

 

// 将Apple放入泛型化的list(这个list可以接收的类型是Apple的父类,所以一定可以接收apple或apple的子类)

public static void addApple(List<? super Apple> list, Apple apple) {

list.add(apple);

}

}

public class GenericCompileTester {

public void addInteger1(List<?> list) {

list.add(1); // 编译错误,因为问号代表“编译时不确定,但运行时确定”的类型,Integer不一定符合要求,其实这里相当于<?

// extends Object>

}

 

public void addInteger2(List<Object> list) {

list.add(1); // 编译通过,因为编译时和运行时都确定了是Object类型,Integer肯定符合要求

}

 

public void test() {

List<String> list = new ArrayList<String>();

addInteger2(list); // 编译错误,因为List<String>不能当作List<Object>传入,否则数字1将被当作String添加,类型将不再安全

}

 

public void test3() {

List<? extends Fruit> fruitList = new ArrayList<Apple>();

fruitList.add(new Apple()); // 编译错误,编译器无法确定List允许的是Fruit的具体哪一个子类

fruitList.add(new Fruit()); // 编译错误,编译器无法确定List允许的是Fruit的具体哪一个子类

}

 

public void test4() {

List<? super Apple> fruitList = new ArrayList<Fruit>();

fruitList.add(new Apple()); // 编译通过,Apple和Apple的子类都可以保证符合条件要求

fruitList.add(new Fruit()); // 编译错误,编译器无法确定List允许的是Apple的具体那个级别的父类或接口

}

}

 


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培

训、.Net培训</a>、期待与您交流! -------

0 0