java泛型

一、为什么要有泛型(Generic)?

二、使用泛型

三、泛型的几个重要应用

四、通配符的使用

一、为什么要有泛型(Generic)?

1. 解决元素存储的安全性问题

2. 解决获取数据元素时,需要类型强转的问题



泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。
        Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。

二、使用泛型

Ⅰ、泛型的声明:
interface List<T> 和 class GenTest<K,V> 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。

Ⅱ、泛型的实例化:
     一定要在类名后面指定类型参数的值(类型)。如:
          List<String> strList = new ArrayList<String>();
          Iterator<Customer> iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。但可以使用包装类填充
把一个集合中的内容限制为一个特定的数据类型,这就是generics(泛型)背后的核心思想

三、泛型的几个重要应用

Ⅰ、在集合中使用泛型

Ⅱ、自定义泛型类

public class Person<E> {

	E e;
	
	public void setE(E e){
		this.e = e;
	}
	
	public E getE(){
		return e;
	}
}

Ⅲ、自定义泛型方法

public <T> T getT(T t){
	return t;
}

public static <T> T getT(T t){
	return t;
}

Ⅳ、自定义泛型接口

public interface MyInterface<T> {

	T getT();
}

Ⅰ、在集合中使用泛型

1. 对象实例化时不指定泛型的话,默认为:Object。
2. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如<E1,E2,E3>
3. 泛型类的构造器如下:
    public GenericClass(){}。而如下是错误的:
    public GenericClass<E>(){}
4.从泛型类派生子类,泛型类型需具体化

5.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。

6.静态方法中不能使用类的泛型
7.异常类不能是泛型的

8.加入集合中的对象类型必须与指定的泛型类型一致。
9.泛型不同的引用不能相互赋值。
      尽管在编译时ArrayList<String>和ArrayList<Integer>是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
10. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
11. 不能使用new E[]。但是可以:
E[] elements = (E[])new Object[capacity];

注:对于6、7

public V getV() {
		/*
		 * 编译不通过:异常的类型不能是泛型
		try {
			
		} catch (T t) {
			// TODO: handle exception
		}
		*/
		return v;
	}
	
	/*
	 * 静态方法中不能使用类的泛型,因为泛型的类型是在创建对象的时候指明的
	public static K getT(){
		return k;
	}
	*/
	

注意区分:

静态方法中:类的泛型与泛型方法:

说明:在静态方法中使用类的泛型会泛型编译异常,因为创建对象调用方法时,不能够确定泛型的类。而使用静态方法,则可以确定类型在创建对象调用的时候

class Student<T>{
	/* 编译正确
	 * 静态方法中泛型方法
	 * 注意:泛型方法是可以使用static来修饰的,因为调用方法的时候我们就知道了泛型的类型
	 */
	public static <E> E getE2(E e){
		return e;
	}
	/* 编译错误
	 * 静态中方法中类的泛型
	 * 注意: 因为创建对象调用该方法时,不能够确定泛型的类型
	 */
	public static T getT3(){
		return t;
	}
	
}

注意区分:

类的泛型定义的一般方法与泛型方法:

说明:自定义的泛型方法必须要在方法名前加上<>并在里面标识泛型

class Student<T>{
	
	T t;

	public T getT() {//使用T类型定义的一般方法
		return t;
	}
	public <E>  E  getE(E e){//自定义泛型方法
		return e;
	}
}

Ⅱ、自定义泛型类

class Person<T>{
	//使用T类型定义变量
	private T info;
	//使用T类型定义一般方法
	public T getInfo(){
		return info;
	}
	public void setInfo(T info){
		this.info = info;
	}
    //使用T类型定义构造器
    public Person(){}
    public Person(T info){
	    this.info = info;
    }
}

如何给父类指明泛型类型?

        第一种方式:子类在继承父类的时候,可以直接声明父类的泛型类型。
public class Student extends Person<String>

第二种方式:子类在继承父类的时候,可以通过子类对象来指明父类的泛型类型

public class Student<T> extends Person<T>

                        Student<String> student = new Student<String>();

Ⅲ、自定义泛型方法

方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。

泛型方法的格式:[访问权限]  <泛型>  返回类型  方法名([泛型标识 参数名称])  抛出的异常


Ⅳ、自定义泛型接口

如果Men是Person的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G<Man>并不是G<Person>的子类型!
比如:String是Object的子类,但是List<String >并不是List<Object>的子类。


public void testGenericAndSubClass() {
	Person[] persons = null;
	Man[] mans = null;
	// 而 Person[] 是 Man[] 的父类.
	//在数组上
	persons = mans;
	Person p = mans[0];

	// 在泛型的集合上
	List<Person> personList = null;
	List<Man> manList = null;
	// personList = manList;(报错)
}

四、通配符的使用

1.使用类型通配符:? 
比如:List<?>   ,Map<?,?>
List<?>是List<String>、List<Object>等各种泛型List的父类。
2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。
唯一的例外是null,它是所有类型的成员。

通配符的使用说明:

① 可以理解成通配符是所有泛型的父类

②使用通配符的集合只能存放null值

② 使用通配符的集合可以遍历所有的数据

通配符的限制说明:

<? extends Number> : 泛型只能使用NumberNumber子类

<? extends 接> : 泛型只能使用口的实现类

<? super Number> :泛型只能使用NumberNumber的父












。。。

JavaJava中一种强大的特性,允许编写类安全且可重用的代码,能创建灵活的组件处理不同数据类,同时保持代码的简洁性和可读性,对于编写高质量Java程序至关重要[^2]。 ### 基本概念 通俗理解,让类可以像方法的参数一样传递。例如`List<String>`中的`String`就是类参数,它告知编译器该`List`只能存放`String`类的对象[^3]。 ### 使用场景 - **类安全**:在没有时,需要强制类转换,容易导致`ClassCastException`,而使用能在编译时检查类安全,避免运行时异常。 - **代码复用**:不使用时,为不同类需要编写相似的代码,使用一套代码就可以适用于多种类。 - **代码清晰度**:没有时,需要查看文档或注释才能知道集合中存储的类,使用可直接从类声明了解集合中存储的类[^3]。 ### 使用方法 #### 类 在实例化类的时候指明的具体类。例如: ```java class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } } // 使用 Box<String> stringBox = new Box<>(); stringBox.set("Hello"); String value = stringBox.get(); ``` #### 方法 在调用方法的时候指明的具体类。示例如下: ```java public <T> T genericMethod(Class<T> tClass) throws InstantiationException, IllegalAccessException { T instance = tClass.newInstance(); return instance; } // 使用 try { String str = genericMethod(String.class); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } ``` ### 通配符 在代码中,问号`?`称为通配符,用来表示未知类。通配符可在多种情况下使用,如作为参数、字段或局部变量的类,有时也可作为返回类,但永远不会用作调用方法、创建类或超类实例的类参数。例如: ```java public static void printList(java.util.List<?> list) { for (Object element : list) { System.out.println(element); } } ``` ### 原理 Java是通过类擦除实现的。在编译时,编译器会把信息擦除,替换为原始类(如`List<String>`会被擦除为`List`),并在必要的地方插入类转换代码,以保证类安全。 ### 最佳实践 - **合理使用类和方法**:根据实际需求选择合适的形式,若类参数与类的整体相关,可使用类;若只与某个方法相关,则使用方法。 - **使用通配符提高灵活性**:当需要处理不同的集合时,合理使用通配符能提高代码的灵活性和复用性。 - **注意类擦除的影响**:由于类擦除,在运行时无法获取的具体类信息,编写代码时需考虑这一点。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值