目录
1.定义:
允许在定义类、接口和方法时,不指定具体的数据类型,而是通过一个或多个类型参数来表示。这样,你可以编写更通用、可重用的代码,而不需要重复编写不同数据类型的相似代码。
2.定义语法:
class 类名称 <泛型标识、泛型标识,...> {
private 泛型标识 变量名;
......
}
3.泛型类的使用语法:
类名<具体的数据类型> 对象名 = new 类名<>();
1.案例:
public static void main(String[] args) {
// 泛型类在创建对象的时候来指定操作的具体数据类型
Generic<String> stringGeneric = new Generic<>("a");
String key = stringGeneric.getKey();
System.out.println("key:" + key);
System.out.println("------------------------");
Generic<Integer> integerGeneric = new Generic<>(100);
Integer key1 = integerGeneric.getKey();
System.out.println("key1:"+key1);
// 总结:泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。
System.out.println("----------注意点1:--------------");
// 泛型类在创建对象的时候,没有指定泛型类,将按照Object类型来操作
Generic generic = new Generic("ABC");
Object key3 = generic.getKey();
System.out.println("key3:"+key3);
System.out.println("----------注意点2:--------------");
// 泛型类不支持基本数据类型,原因就是我们在编译期间会将这个 T 编译成 Object
// 基本数据类型无法转化为 object类型
// Generic<int> intGeneric = new Generic<>(100);
System.out.println("----------注意点3:--------------");
// 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
System.out.println(integerGeneric.getClass() == stringGeneric.getClass());
}
例:1.实现栈:
未使用泛型时:
package Stack;
//int类型的栈
public class Stack {
private int[] arr;
private int i = -1;
public Stack(int size){
arr = new int[size];
}
public void add(int value){
i++;
arr[i] = value;
}
public int get(){
return arr[i--];
}
}
package Stack;
//字符串类型
public class StringStack {
private String[] arr;
private int i = -1;
public StringStack(int size){
arr = new String[size];
}
public void add(String value){
i++;
arr[i] = value;
}
public String get(){
return arr[i--];
}
}
package Stack;
public class Test {
public static void main(String[] args) {
Stack stack = new Stack(10);
stack.add(1);
stack.add(2);
stack.add(3);
stack.add(4);
System.out.println(stack.get());
System.out.println(stack.get());
System.out.println(stack.get());
System.out.println(stack.get());
StringStack stringStack = new StringStack(5);
stringStack.add("beijing");
stringStack.add("shanghai");
System.out.println(stringStack.get());
System.out.println(stringStack.get());
}
}
运行结果:
使用泛型:
package Stack;
public class Test {
public static void main(String[] args) {
Stack stack = new Stack(10);
stack.add(1);
stack.add(2);
stack.add(3);
stack.add(4);
System.out.println(stack.get());
System.out.println(stack.get());
System.out.println(stack.get());
System.out.println(stack.get());
Stack stack1 = new Stack(10);
stack.add("beijing");
stack.add("shanghai");
System.out.println(stack1.get());
System.out.println(stack1.get());
}
}
package Stack;
public class Stack <法老> {
private 法老[] arr;
private int i = -1;
public Stack(int size){
arr = (法老[])new Object[size];
}
public void add(法老 value){
i++;
arr[i] = value;
}
public 法老 get(){
return arr[i--];
}
}
1.泛型类:
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
在这个例子中,Box
类使用了泛型 T
,可以存储任何类型的对象。
2.使用泛型类:
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
3.泛型方法:
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
4.注意事项:
- 泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
- 泛型的类型参数只能是类类型,不能是基本数据类型
- 泛型类型在逻辑上可以看成是多个不同的类型,但实际上是相同类型
5.例:年终抽奖:
/**
* 抽奖器
* @param <T>
*/
public class ProductGetter<T> {
//奖金或者奖品
private T product;
// 定义奖品、奖金池
ArrayList<T> arrayList = new ArrayList<>();
// 添加奖品到奖品池
public void addProduct(T t){
arrayList.add(t);
}
// 定义一个随机数,用来抽选奖品
Random random = new Random();
//抽奖
public T getProduct(){
product = arrayList.get(random.nextInt(arrayList.size()));
return product;
}
}
public static void main(String[] args) {
ProductGetter<String> stringProductGetter = new ProductGetter<>();
String[] strPro = {"苹果手机","华为手机","扫地机器人","咖啡机"};
//将奖品放入奖金池
for (int i = 0;i< strPro.length;i++){
stringProductGetter.addProduct(strPro[i]);
}
String product = stringProductGetter.getProduct();
System.out.println("恭喜您抽中了:"+product);
System.out.println("******************************");
ProductGetter<Integer> IntegerProductGetter = new ProductGetter<>();
Integer[] intPro = {100,1000,10000,20000};
//将奖品放入奖金池
for (int i = 0;i< intPro.length;i++){
IntegerProductGetter.addProduct(intPro[i]);
}
Integer product1 = IntegerProductGetter.getProduct();
System.out.println("恭喜您,获的了:"+product1+"元");
}
6.泛型接口:
interface 接口名称 <泛型标识,泛型标识,...>{
泛型标识 方法名();
......
}
泛型接口的使用(2种情况)
- 实现类不是泛型类,接口要明确数据类型
- 实现类也是泛型类,实现类和接口的泛型类型要一致
二、从泛型类派生子类(2种情况)
- 子类也是泛型类,子类和父类的泛型类型要保持一致
class ChildGeneric<T> extends Generic<T>
- 子类不是泛型类,父类要明确泛型类的数据类型
class ChildGeneric extends Generic<String>
关键点:
- 子类泛型类型继承:子类可以继承泛型父类,并保留或指定泛型类型参数。
- 具体类型实例化:可以在创建对象时指定具体的泛型类型。
- 类型参数约束:可以使用边界来限制泛型类型的范围,以便于更严格的类型检查和方法实现。
例:从泛型类派生子类:
public class SubClass<T> extends GenericClass<T> {
private String additionalValue;
public SubClass(T value, String additionalValue) {
super(value);
this.additionalValue = additionalValue;
}
public String getAdditionalValue() {
return additionalValue;
}
public void setAdditionalValue(String additionalValue) {
this.additionalValue = additionalValue;
}
}
解析:
SubClass<T>
是一个泛型类,T
是类型参数。extends GenericClass<T>
表示SubClass<T>
继承自GenericClass<T>
,并且SubClass
继承了GenericClass
中的所有功能,并且泛型参数T
也被传递到了父类GenericClass
。additionalValue
是SubClass
的一个成员变量,用于存储附加的字符串信息。- 它是
private
,意味着它只能在SubClass
内部访问。 - 这个构造函数接受两个参数:
T value
:一个泛型类型的值,这个值将传递给父类GenericClass
的构造函数。String additionalValue
:一个字符串,用于初始化additionalValue
成员变量。
super(value)
调用父类GenericClass
的构造函数,并传递泛型参数value
。this.additionalValue = additionalValue
初始化SubClass
中的additionalValue
成员变量。getAdditionalValue()
:返回additionalValue
的值。setAdditionalValue(String additionalValue)
:设置additionalValue
的值。