第十一节、轻松学Java_泛型

泛型与泛型类

泛型的本质是类型参数化, 也就是说操作的数据类型被指定为一个参数, 即“类型的变量”。
采用泛型类, 就可以将封装方式相同但是属性类型不同的多个类用一个泛型表示, 减少程序的开发工作量,提高软件的开发效率。
通过定义泛型类,可以将变量的类型作为参数来定义,而变量的具体类型是在创建泛型类的对象时再确定的。

如果想表示任意类型对象的数组,则数组中封装的数组类型应该是Object,但是数组对象中的数组元素可以是不同类型的。如果使用泛型,则可以保证每一个数组类对象中的元素都是同一类型的。

package com.test;

class GenericArray<T> // 泛型类,类型参数名T
{
	int n; // 数组的总长度
	int total; // 数组的实际长度
	private Object arr[]; // Object 类型的对象数组

	public GenericArray(int n) // 构造方法
	{
		this.n = n;
		total = 0;
		arr = new Object[n];
	}

	public void add(T obj) // 将一个T 型对象加到数组中
	{
		arr[total++] = obj;
	}

	public T indexOf(int i) // 获得第i 个元素,返回值类型是T 型
	{
		return (T) arr[i]; // 返回前强制转换成T 型
	}

	public int length() {
		return total;
	}
}
package com.test;
public class Test {
	public static void main(String args[]) {
		int i;
		String str[] = new String[2]; // 一个String 类的对象数组
		str[0] = "Beijing";
		str[1] = "Shanghai";
		GenericArray<String> arrObj1 = new GenericArray<String>(10);
		// 创建一个泛型类对象,所有元素均为String 型
		for (i = 0; i < str.length; i++) // 将每个元素加到数组对象中
			arrObj1.add(str[i]);
		for (i = 0; i < arrObj1.length(); i++) // 输出元素
			System.out.println(arrObj1.indexOf(i)); // 获得第i 个元素后直接输出,不用强制类型转换
		// -------------------------------------------------
		System.out.println("-----------");
		Integer intObj[] = new Integer[2]; // 一个Integer 类的对象数组
		intObj[0] = new Integer(123);
		intObj[1] = new Integer(-456);
		GenericArray<Integer> arrObj2 = new GenericArray<>(10);
		// 创建一个泛型类对象,所有元素均为Integer 型
		for (i = 0; i < intObj.length; i++) // 将每个元素加到数组对象中
			arrObj2.add(intObj[i]);
		for (i = 0; i < arrObj1.length(); i++) // 输出元素
			System.out.println(arrObj2.indexOf(i).intValue());
		// 获得第i 个元素后直接输出,不用强制类型转换
		// -------------------------------------------------
		System.out.println("-----------");
		Object obj[] = new Object[2]; // 一个Object 类型的对象数组
		obj[0] = "Beijing"; // 第0 个元素是String 型
		obj[1] = new Integer(-123); // 第1 个元素是Integer 型
		GenericArray<String> arrObj3 = new GenericArray<>(10);
		// 创建一个泛型类对象,所有元素均为String 型
		arrObj3.add("Beijing");
		// arrObj3.add(-123);//泛型类对象arrObj3 只能加String 型对象,写上这行语句,编译不能通过
		for (i = 0; i < arrObj3.length(); i++)
			System.out.println(arrObj3.indexOf(i));
	}
}

输出:
在这里插入图片描述
泛型类名[<实际类型>] 对象名=new 泛型类名<>
其中的实际类型不能是基本数据类型,必须是类或者接口。

泛型方法

定义方法时声明了类型参数, 这样的类型参数只限于在该方法中使用。 泛型方法可以定义在泛型类中, 也可以定义在非泛型类中。

package com.test;
import java.util.Date;
public class Test {
	public static <T> void print(T t)// 泛型方法
	{
		System.out.println(t);
	}

	public static void main(String args[]) {
		// 调用泛型方法
		print("Apple");
		print(123);
		print(-487.76);
		print(new Date());
	}
}

输出:
Apple
123
-487.76
Sun Jul 11 23:16:31 CST 2021

形参中放入数组,数组本身具有相对应的参数类型

package com.test;
public class Test {
	static <T> void print(T... ts)// 泛型方法,形参是可变参数
	{
		for (int i = 0; i < ts.length; i++)// 访问形参数组中的每一个元素
			System.out.print(ts[i] + " ");
		System.out.println();
	}

	public static void main(String args[]) {
		print("北京市", "长安街", "故宫博物院");// 3 个实际参数,类型一样
		print("这台电脑", "价格", 3000.00, "元");// 4 个实际参数,类型不一样
		String fruit[] = { "apple", "banana", "orange", "peach", "pear" };// String 对象数组
		print(fruit);// 一个参数
	}
}

输出:
北京市 长安街 故宫博物院
这台电脑 价格 3000.0 元
apple banana orange peach pear

泛型接口

package com.test;

interface Generics<T> // 泛型接口
{
	public T next();
}
package com.test;

class SomethingGenerics<T> implements Generics<T>// 泛型类,实现泛型接口
{
	private T something[];// 泛型域
	int cursor;// 游标,标示something 中的当前元素

	public SomethingGenerics(T something[])// 构造方法
	{
		this.something = something;
	}

	public T next()// 获取游标处的元素,实现接口中的方法
	{
		if (cursor < something.length)
			return (T) something[cursor++];
		return null;// 超出范围则返回空
	}
}

package com.test;

public class Test {
	public static void main(String args[]) {
		String str[] = { "Beijing", "Shanghai", "Tianjin" };// String 对象数组,直接实例化
		Generics<String> cityName = new SomethingGenerics<String>(str);// 创建泛型对象
		while (true)// 遍历,将泛型对象表示的元素显示出来
		{
			String s = cityName.next();
			if (s != null)
				System.out.print(s + " ");
			else
				break;
		}
		System.out.println();
		Integer num[] = { 123, -456, 789 };// Integer 对象数组,直接实例化
		Generics<Integer> numGen = new SomethingGenerics<Integer>(num);// 创建泛型对象
		while (true)// 遍历,将泛型对象表示的元素显示出来
		{
			Integer i = numGen.next();
			if (i != null)
				System.out.print(i + " ");
			else
				break;
		}
		System.out.println();
	}
}

输出:
Beijing Shanghai Tianjin
123 -456 789

泛型参数

class LtdGenerics<T extends Number>
// 泛型类,实际类型只能是Number 的子类,Ltd=Limited
{
	private T arr[]; // 域,数组

	public LtdGenerics(T arr[]) // 构造方法
	{
		this.arr = arr;
	}

	public T max() // 找最大数
	{
		T m = arr[0];// 假设第0 个元素是最大值
		for (int i = 1; i < arr.length; i++) // 逐个判断
			if (m.doubleValue() < arr[i].doubleValue())
				m = arr[i];// Byte、Double、Float、Integer、Long、Short 类型
		// 的对象都可以调用doubleValue 方法得到对应的双精度数
		return m;
	}

	public T min()// 找最小值
	{
		T m = arr[0];// 假设第0 个元素是最小值
		for (int i = 1; i < arr.length; i++) // 逐个判断
			if (m.doubleValue() > arr[i].doubleValue())
				m = arr[i];
		return m;
	}
}

public class Test {
	public static void main(String args[]) {
		// 定义整型数的对象数组,自动装箱
		Integer integer[] = { 34, 72, 340, 93, 852, 37, 827, 940, 923, 48, 287, 48, 27 };
		// 定义泛型类的对象,实际类型是Integer
		LtdGenerics<Integer> ltdInt = new LtdGenerics<Integer>(integer);
		System.out.println("整型数最大值:" + ltdInt.max());
		System.out.println("整型数最小值:" + ltdInt.min());
		// 定义双精度型的对象数组,自动装箱
		Double db[] = { 34.98, 23.7, 4.89, 78.723, 894.7, 29.8, 34.79, 82., 37.48, 92.374 };
		// 创建泛型类的对象,实际类型是Double
		LtdGenerics<Double> ltdDou = new LtdGenerics<Double>(db);
		System.out.println("双精度型数最大值:" + ltdDou.max());
		System.out.println("双精度型数最小值:" + ltdDou.min());
		String str[] = { "apple", "banana", "pear", "peach", "orange", "watermelon" };
		// 下面的语句创建泛型类的对象,这是不允许的,因为String 不是Number 类的子类
		// 如果加上下面这条语句,程序不能编译通过
		// LtdGenerics<String> ltdStr=new LtdGenerics<String>(str);
	}
}

输出:
整型数最大值:940
整型数最小值:27
双精度型数最大值:894.7
双精度型数最小值:4.89

方法与构造方法的引用

package com.test;

public interface InterNew<String, Integer> {
	Integer InterNew(String string);
}
package com.test;

public class FuncNew {
	public static void main(String[] args) {
		// 引用静态方法valueOf()
		InterNew<String, Integer> in2 = Integer::valueOf;
		// 使用valueOf()方法将字符串转换为Integer 类型,接口中的InterNew函数代表valueOf
		Integer i2 = in2.InterNew("25");
		System.out.println("方法引用-String -> Integer:" + i2);
	}
}

输出:
方法引用-String -> Integer:25

package com.test;

public class Fruit {
	private String name;
	private String color;

	public Fruit(String name, String color) {
		super();
		this.name = name;
		this.color = color;
		System.out.println("name = " + name + ",color = " + color);
	}

	public Fruit() {
		super();
	}
}
package com.test;

public interface FruitInter<f extends Fruit> {
	// 在接口中定义抽象方法Fruit,返回的f只能是Fruit的类的子类
	f Fruit(String name, String color);
}
package com.test;

public class Test {
	public static void main(String args[]) {
		FruitInter<Fruit> fi = Fruit::new; //获取Fruit 类构造方法的引用,接口中的Fruit相当于Fruit类构造函数
		Fruit fruit = fi.Fruit("apple", "red"); //Java 编译器自动根据fi.Fruit()方法的签名,选择合适的构造函数
	}
}

输出:
name = apple,color = red

Lambda作用域

利用Lambda表达式直接访问外层的局部变量

package com.test;

public class Test {
	public static void main(String[] args) {
		int number = 6;
		//下面一行是Lambda表达式,定义了一个变量,接口中函数InterNew(5)相当于方法(t),将5+6值以字符串方式传回
		InterNew<Integer, String> inn = (t) -> String.valueOf(t + number);
		System.out.println("访问局部变量:" + inn.InterNew(5));
	}
}

输出:
访问局部变量:11

利用Lambda表达式访问对象字段与静态变量

在 Lambda 表达式中修改变量 number (本地常量)同样是不允许的。 与本地变量不同, Lambda 表达式内部对于对象的字段以及静态变量是即可读又可写。

package com.test;

public class Test {
	public static int sNum;
	public int num;

	public void varTest() {
		InterNew<Integer, String> is = (t) -> {
			num = 56; // 成员变量
			return String.valueOf(t);
		};
		//(t)相当于接口中InterNew,返回的是Integer类的信息
		System.out.println(is.InterNew(5));
		InterNew<Integer, String> is2 = (t) -> {
			sNum = 98; // 静态变量
			return String.valueOf(t);
		};
		System.out.println(is2);
	}

	public static void main(String[] args) {
		Test l = new Test();
		l.varTest();
	}
}

输出:
5
com.test.Test$$Lambda$2/0x0000000100000400@3abfe836

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值