3. Java 泛型编程实践

本文详细介绍了Java中的泛型使用,包括在方法返回值中的应用,泛型类和接口的定义,泛型方法的创建。讨论了泛型字母规范,并对比了Class、T与T.class的区别。此外,还探讨了如何创建Class类型的实例,以及泛型在方法参数中的必要性。通过实例展示了泛型在提高代码安全性和灵活性方面的优势。
摘要由CSDN通过智能技术生成

目录

1. java 方法返回值中使用泛型

2. 定义泛型类、接口

3. 定义泛型方法

4. 泛型字母规范

5. Class、T 、T.class 的区别 

6. 如何创建一个 Class 类型的实例,

7. 方法中为什么需要 T 修饰

        

1. java 方法返回值中使用泛型

public class FooService<T> {
	// 使用泛型返回
	public <T> T getFoo() {
		Foo foo = new Foo();
		foo.setId(1);
		foo.setName("1");
		return (T) foo;
	}
	// 使用Object 直接返回
	public Object getFoObject() {
		Foo foo = new Foo();
		foo.setId(2);
		foo.setName("2");
		return foo;
	}
	
	public static void main(String[] args) {
		FooService<Foo> my = new FooService<Foo>();
		Foo foo1 = my.getFoo();
		System.out.println(foo1.getName());
		Foo foo2 = (Foo) my.getFoObject();
		System.out.println(foo2.getName());
	}
}

        使用泛型后 getFoo 方法的返回值不需要强制类型转换,避免了发生ClassCastException 异常,编译时更安全,因为泛型是再运行时才确定类型,而并非再编译时确定。

        所以再使用泛型后,可以再同一方法灵活的实现返回值类型。

2. 定义泛型类、接口

        定义任意泛型的类、接口,只要在定义它们时用<>来指定类型参数即可。

        例如:public class Fruit<T> { ... },其中<T>指定了该泛型的类型参数,这个T是一个类型参数名,用户可以任意命名(就像方法参数的形参名一样),只有在使用该泛型的对象时将T替换成指定的具体类型从而产生一个实例化的泛型对象,例如:Fruit<String> fruit = new Fruit<>(...);

        类型形参可以在整个接口、类体内当成普通类型使用,集合所有可使用普通类型的地方都可以使用类型形参,例如

public interface MyGneric<E> {  
    E add(E val);  
    Set<E> makeSet();  
    ...  
}  

        定义在<> 中的泛型的类型参数在定义他的类、接口里面就可以像普通类一样使用。

        定义泛型构造器:泛型的构造器还是类名本身,不用使用菱形语法,定义构造器无需MyGeneric<T>(...) { ... }了,只有在new的时候需要用到菱形语法;

public class MyGenric<T> {  
    MyGeneric(...) { ... }  
    ...  
}  

        实现/继承泛型接口/泛型类:

        泛型也是在定义的时候必须使用形参(虚拟参数,用户自己随意命名),但是在使用泛型的时候(比如定义泛型引用、继承泛型)就必须使用实参,而泛型的实参就是具体的类型,像String、Integer等具体的类型(当然也可以是自定义类型)。Java还支持一种特殊的语法,可以让你从泛型继续派生出泛型,而泛型的类型参数可以继续传承下去;

class Father<T> { ... }  
  
class Son<T> extends Father<T> { ... }  

        这个具体可以看 JDK 的 List 类,Collection 相关接口都是这么设计的。 在编译器中,是无法知道K和V具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。具体可以参考Map 接口的设计。

public class Container <K, V>{
	private K key;
	private V value;
	public Container(K key, V value) {
		this.key = key;
		this.value = 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 static void main(String[] args) {
		Container<String, String> container = new Container<String, String>("1", "2");
		System.out.println(container.getKey());
	}

3. 定义泛型方法

        定义泛型方法需要在返回值前加入 <T> 来声明这是一个泛型方法。当然返回值也可以不是T。如果在类名旁已经定义了<T>, 也可以直接在方法里返回 T ,不需要再方法的返回值前加入<T> 也可以使用。

public class FooService {
	
	public <T> T getFoo() {
		Foo foo = new Foo();
		foo.setId(1);
		foo.setName("1");
		return (T) foo;
	}
}

public class FooService<T> {
	
	public T getFoo() {
		Foo foo = new Foo();
		foo.setId(1);
		foo.setName("1");
		return (T) foo;
	}
}

       Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,作为Class 类型的对象,c 就可以拥有Class 对象的方法,可以根据反射来创建泛型类的对象。

public class FooService<T> {
	public T getT(Class<T> t) throws InstantiationException, IllegalAccessException {
		T a= t.newInstance();
		return a;
	}
}

4. 泛型字母规范

  • E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
  •  K,V — Key,Value,代表Map的键值对
  •  N — Number,数字
  •  T — Type,类型,如String,Integer等等

        字母是没有特定意义的!只是为了提高可读性

5. Class<T>、T 、T.class 的区别 

        单独的T 代表一个类型 ,而 Class<T>代表这个类型所对应的类, Class<?>表示类型不确定的类。

6. 如何创建一个 Class<T> 类型的实例,

        可以通过 Class.forName() 或者使用类常量 X.class 。 Class.forName() 被定义为返回 Class<?> 。 另一方面,类常量 X.class 被定义为具有类型 Class<X> , 所以 String.class 是 Class<String>  类型的。

7. 方法中为什么需要 <T> T 修饰

        泛型的声明,必须在方法的修饰符(public,static,final,abstract等)之后,返回值声明之前。其中第一个<T>是与传入的参数Class<T>相对应的,相当于返回值的一个泛型,后面的T是返回值类型,代表方法必须返回T类型的(由传入的Class<T>决定)

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值