java泛型基本知识及通用方法

网友投稿 421 2023-01-10


java泛型基本知识及通用方法

泛型的基本使用

泛型是java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类、接口和方法的创建中, 分别称为泛型类、泛型接口、泛型方法.  Java语言引入泛型的好处是安全简单.

今天就从以下几个方面介绍一下java的泛型: 基础, 泛型关键字, 泛型方法, 泛型类和接口.

基础:

通过集合的泛型了解泛型的基本使用

public void testBasis(){

List list = new ArrayList();

// new ArrayList();

}

//这是最基本的泛型使用, 就不多说了, 不过要注意的是泛型只能是引用数据类型, 不能是基本类型, 而且泛型只在编译期有效, 在编译后的class文件中是不存在泛型信息的

注意: 泛型只在编译期有效, 在编译后的class文件中是不存在泛型信息的

泛型关键字:

通配符?表示任意引用类型, extends关键字表示子类及其本身, super关键字是表示父类及其本身. 通过一个例子看一下, 解释说明都在例子中

public void testKeyWord() throws Exception {

//实例化参数类型必须指明具体类型

List> list = new ArrayList();

//由于list中类型不明确, 所以不能进行添加操作

// list.add("sk");

//通配符?表示任意引用类型

List> list1 = new ArrayList>();

//list1的参数化类型是一个List, 而这个List也是一个参数化类型, 它的类型是任意类型, 所以list1可以添加任意List类型对象

list1.add(new ArrayList());

list1.add(new ArrayList());

//实例化list2时指明了类型参数List, 只不过这个List是一个泛型类型

//从这里可以看到关键字extends的用法, 其实就是继承, 如下这里的list2中的参数化类型List(在这里记为paramList)的参数化类型是继承自Number的

//所以在list2在添加的时候只能添加参数化类型为Number及其子类的paramList

List l1 = new ArrayList();

Lihttp://st l2 = new ArrayList();

List l3 = new ArrayList();

List> list2 = new ArrayList>();

list2.add(l1);

list2.add(l2);

// list2.add(l3); //这里使用了extends关键字, 所以不能添加Number的父类

//相信大家也猜到了, 既然extends关键字表示子类及其本身, 那么super关键字是表示父类及其本身, 是的, 没错

//和上面的不一样了, l1不能添加, 因为Integer是Number的子类, 并不是Number的父类

List> list3 = new ArrayList>();

// list3.add(l1); //这里使用了super关键字, 所以不能添加Number的子类

list3.add(l2);

list3.add(l3);

}

泛型方法:

java中任何类型必须先定义才能使用, 泛型也是如此. 既然要使用泛型作为参数, 所以要先定义, 泛型的定义在访问修饰符和返回类型之间, 注意不要掉了尖括号

//无返回值有参的方法, 参数为泛型

public void show(T t){

System.out.println("t-=-=" + t);

}

//有返回值的有参方法, 只有一个参数化类型, 这里定义泛型的方式和上面一样, 也是先定义后使用, 只不过这里的返回类型是泛型

public T get(T t){

return t;

}

//有返回值的有参方法, 有多个参数化类型, 这里以两个为例

public K get(T t, K k){

return k;

}

@Test

public void testGeneric() throws Exception {

show(3);

show("generic");

System.out.println("----------------");

System.out.println("我返回Integer类型-" + get(4));

System.out.println("我返回String类型-" + get("returnGeneric"));

System.out.println("------------------");

System.out.println("我返回String类型-" + get(1, "a"));

System.out.println("我返回Integer类型-" + get("b", 2));

}

本来想写无参的泛型方法, 可是写着写着感觉那样没有什么意义, 不知道各位有什么见解.

泛型类和接口:

写泛型类的时候只需要在类名后面加上泛型即可, 就像这样

public class GenericClass {

public T get(T t){

return t;

}

public void scr(T t){

System.out.println(t);

}

public void show(){

GenericClass gc = new GenericClass();

// GenericClass gc1 = new GenericClass();

gc.get(3);

gc.scr(5);

//下面2个会报错

// gc1.get(3);

// gc1.scr(5);

}

}

从上面的例子中可以看到, 参数化类型是在创建对象的时候具体化的, 那么除此之外, 还可以再什么时候具体化参数化类型呢?

如果是在继承或实现中, 可以在子类或实现类中确定具体类型

使用java泛型设计通用方法

泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张student表.

user:

student:

如果要根据id查询数据, 你会怎么做呢?写2个方法分别查询user和student?其实这时候我们就可以使用泛型和反射写一个通用的方法.

user的实体类:

private Integer id;

private String username;

private String password;

private String hobby;

//getXxx方法和setXxx方法

student实体类:

private Integer id;

private String name;

private Integer age;

//getXxx方法和setXxx方法

BaseDao接口:

public interface BaseDao {

//根据id查询的方法

T findById(Integer id);

}

BaseDaoImpl类, 实现了BaseDao接口, 通用方法就在这里面完成:

//设置为抽象的, 不让他实例化, 让其子类实例化就行了

//通过泛型设计通用方法的关键就是利用反射拿到泛型的具体类型

public abstract class BaseDaoImpl implements BaseDao {

private String tableName;  //表名

private Class actualType;//真实类型

/**

* findById(Integer id)这个方法被子类继承了, 假设我们在UserDaoImpl中操作, 此时参数化类型T为User

* 下面的讲解都假设是在UserDaoImpl中进行的

*/

//把公共部分可以放到构造方法中

@SuppressWarnings("unchecked")

public BaseDaoImpl() {

//返回类型是Type 是 Java 编程语言中所有类型的公共高级接口. 它们包括原始类型、参数化类型、数组类型、类型变量和基本类型.

//Type的已知子接口: ParameterizedType 表示参数化类型, 如 Collection.

//getClass()得到UserDaoImpl的Class, 得到Class一般有3中方式: getClass(), 类名.class, Class.forName()

Type type = getClass().getGenericSuperclass();//获取UserDaoImpl的参数化类型的父类BaseDaoImpl

//由于我们得到的是一个参数化类型, 所以转成ParameterizedType, 因为需要使用里面的方法

ParameterizedType pt = (ParameterizedType) type;//强转

Type[] actualTypeArr = pt.getActualTypeArguments();//获取真实参数类型数组[User.class], 可以调试看到这里的值

actualType = (Class) actualTypeArr[0];//数组只有一个元素

tableName = actualType.getSimpleName();

}

@Override

public T findById(Integer id) {

String sql = "select * from " + tableName + " where id = ?";

try {

return QRUtils.getQueryRunner().query(sql, new BeanHandler(actualType), id);

} catch (SQLException e) {

e.printStackTrace();

}

return null;

}

}

连接数据库操作是用的c3p0和dbutils, 有关这方面的内容可以参看我以前的随笔.

UserDao接口, 继承BaseDao接口:

public interface UserDao extends BaseDao {

}

UserDaoImpl类, 实现UserDao接口, 继承BaseDaoImpl类, 可以看到里面什么方法也没有:

public class UserDaoImpl extends BaseDaoImpl implements UserDao {

}

StudentDao接口, 继承BaseDao接口:

public interface StudentDao extends BaseDao {

}

StudentDaoImpl类, 实现StudentDao接口, 继承BaseDaoImpl类, 也可以看到里面什么方法也没有:

public class StudentDaoImpl extends BaseDaoImpl implements StudentDao {

}

从以上dao可以看到, 我是在继承BaseDaoImpl类时把泛型具体化了.

测试:

@Test

public void testGeneric() throws Exception {

UserDao userDao = new UserDaoImpl();

System.out.println(userDao.findById(1));

System.out.println("-------------------");

StudentDao studentDao = new StudentDaoImpl();

System.out.println(studentDao.findById(1));

}

看一下测试的结果: 同一个方法把2张表中的数http://据都查出来了


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:子类继承父类的实现接口(继承父类和接口的区别)
下一篇:微服务网关小流量(微服务网关流量管控)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~