Java之泛型参数化使用于类,接口,方法上知识


第一:参数类型用于类上案例:

编写泛型类GenericClass:

package com.test.cgb;

/**
 * 
 * @Description: 定义泛型类,在类名后添加 对尖括号
   *  并在尖括号中填写类型参数,参数可以有多个,多个参数使用逗号分隔
 * T表示的是任意类型  type
 * E表示的是元素的类型 element
 * K表示的是key/value中的key
 * V表示的是key/value中的value
   *    通常类型参数我们都是使用大写。
 * @author: caigb
 * @createTime: 2020年2月29日
 * @version:
 */
public class GenericClass<T> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

  编写测试类:

public class GenericDemo {
	public static void main(String[] args) {
                // 参数类型为String
		GenericClass<String> genericClassOfString = new GenericClass<>();
		genericClassOfString.setValue("用于类上的泛型");
		String str = genericClassOfString.getValue();
		System.out.println("str = " + str);
		
                // 参数类型为Integer
		GenericClass<Integer> genericClassOfInteger = new GenericClass<>();
		genericClassOfInteger.setValue(111);
		Integer intNum = genericClassOfInteger.getValue();
		System.out.println("intNum = " + intNum);
}                            

  输出结果为:

str = 用于类上的泛型
intNum = 111

==================================================================================================================================

第二个:泛型接口:

定义接口如:

/**
 * 
 * @Description: 用于接口上的泛型
 * @author: caigb28355
 * @createTime: 2020年2月29日
 * @version:
 */
public interface GenericInterface<T> {
	void show(T value);
}

 那么针对这个接口我们可以分别定义多种类型的实现类如:

IntegerShowGenericInterfaceImpl:

package com.test.cgb;
// 泛型类型参数为Integer
public class IntegerShowGenericInterfaceImpl implements GenericInterface<Integer>{

	@Override
	public void show(Integer value) {
		System.out.println(" 整数型 "+ value);
	}

}

  StringShowGenericInterfaceImpl:

package com.test.cgb;
// 泛型类型参数为String
public class StringShowGenericInterfaceImpl implements GenericInterface<String>{

	@Override
	public void show(String value) {
		System.out.println(" 字符串 "+ value);		
	}

}

  编写测试类如下:

public class GenericDemo {
	public static void main(String[] args) {
		GenericInterface IntFace = new IntegerShowGenericInterfaceImpl(); // 向上转型
		IntFace.show(200);
		GenericInterface StringFace = new StringShowGenericInterfaceImpl(); // 向上转型
		StringFace.show("字符串");

}

// 输出结果为:
 整数型 200
 字符串 字符串

==================================================================================================================================

第三:泛型方法,可以定义在泛型类中,也可以定义在普通类中。如果可以定义泛型方法,那就尽量定义泛型方法

泛型方法类定义如:

package com.test.cgb;
/**
 * 
 * @Description: 泛型方法,可以定义在泛型类中,也可以定义在普通类中
  *    定义泛型方法,在返回值前边,修饰符后边添加尖括号,并在其中填写类型参数 
  *    如果可以定义泛型方法,那就尽量定义泛型方法
 * @author: caigb
 * @createTime: 2020年2月29日
 * @version:
 */
public class GenericFun {
	public static<T> void saveScore(T score) {
		// 这是一个保存分数的方法,分数的类型可以是int,double,float...数值类型
		// 我们对分数进行复杂操作......
		System.out.println("score = " + score);
	}
}

  编写测试类如下:

public class GenericDemo {
	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
}
打印结果如下:
score = 20.0
score = 20

  但是上面这个例子有个不足的就是,命名这个方法是用来保存分数的,由于使用了static<T>形式,所以可以接收所有类型的值比如字符串中文,那么就有点违背最初的想法了,如:

	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
		GenericFun.saveScore("保存分数的入参竟然是中文");
}
打印结果有:
score = 20.0
score = 20
score = 保存分数的入参竟然是中文

  所以为了改进上面的缺陷,我们需要限制一下参数类型,于是要对引入类型参数做一下限定,这个限定可以是类,也可以是接口,而且可以同时限定多个,如果有多个,可以使用&符号连接,如果限定中既有类又有接口,那么类一定要写在前面<T extends Number>或者<T extends Number & Comparable>如:

public class GenericFun {
	// T extends Number表示T这个类型必须继承自Number类型,也就是一定要是Number类的字类,那么也就不能是String类型了
	public static<T extends Number> void saveScore(T score) {
		// 这是一个保存分数的方法,分数的类型可以是int,double,float...数值类型
		// 我们对分数进行复杂操作......
		System.out.println("score = " + score);
	}
	// Double 和Float都是继承字Number类如:
//	public final class Double extends Number implements Comparable<Double> {
//	    /**
//	     * A constant holding the positive infinity of type
//	     * {@code double}. It is equal to the value returned by
//	     * {@code Double.longBitsToDouble(0x7ff0000000000000L)}.
//	     */
//	    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
//	}
	
//	public final class Float extends Number implements Comparable<Float> {
//	    /**
//	     * A constant holding the positive infinity of type
//	     * {@code float}. It is equal to the value returned by
//	     * {@code Float.intBitsToFloat(0x7f800000)}.
//	     */
//	    public static final float POSITIVE_INFINITY = 1.0f / 0.0f;

}

  

  这样改造之后,在测试类中如果还是调用GenericFun.saveScore("保存分数的入参竟然是中文")方法的话就会报错如:

public class GenericDemo {
	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
// 下面这句报错信息就是The method saveScore(T) in the type GenericFun is not applicable for the arguments (String)
		GenericFun.saveScore("这里有中文");
}

===============================================================================================================================

泛型之类型擦出重要知识点扩展:下面让我们一起学习下泛型是如何擦出的,我们要知道,对于JVM来说,根本没有泛型这个概念,只有具体类型也就是说在运行期间根本就没有GenericClass<String>,有的只是普通类和方法。JVM都会自动提供了一个相应的原始类型替换。在编译期间必要时会插入强制类型转换方法。

JVM在泛型编译时,做两件事:

1.去掉类名后的尖括号和尖括号的类型参数,剩下的名字就是对应的类名

2.对于类中使用了类型参数的变量的类型,如果没有限制类型的情况下,使用Object替换,如果有类型限定,使用限定的类型替换。下面我们一起看看:

首先我们在工作空间找到对应的class字节码文件路径,然后在该路径打开命令符窗口:

 

最初我们的源文件GenericClass.java代码如:

public class GenericClass<T> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

第二步我们可以在cmd.exe窗口输入命令javap -help可以看到各种命令:

 

 第三步我们可以输入输入命令javap -c -s GenericClass.class,我们可以看到Object类

 

 那么如果源代码是这样的呢?就是有类型限定的如:

public class GenericClass<T extends Number> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

  

那么就替换成Number了:


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM