Java笔记--泛型总结与详解
泛型简介:
在泛型没有出来之前,编写存储对象的数据结构是很不方便的。如果要针对每类型的对象写一个数据结构,
则当需要将其应用到其他对象上时,还需要重写这个数据结构。如果使用了Object类型,编写的数据结构虽然
通用性很好,但是不能保证存入的对象的安全性。
--支持知识共享,转载请标注地址"http://www.cnblogs.com/XHJT/p/3958036.html "——和佑博客园,谢谢~~--
代码实例1:
不用泛型实现栈结构
1.用Object和自定义栈类实现的一个入栈和出栈的小case;
2.理解栈:栈是算法世界中经常要用到的一种数据结构,它可以实现元素的先进后出。常用于实现字符串反转,
· 四则运算等。package com.xhj.generics.unused; /**
* 自定义Stack类
*
* @author XIEHEJUN
*
*/
public class UsedStack {
private Object[] os = new Object[10];
private int index = 0; /**
* 将一个元素入栈
*
* @param o
* 要添加的元素对象
*/
public void push(Object o) {
if (index != os.length) {
os[index++] = o;
}
} /**
* 元素出栈,删除一个元素对象
*
* @return 返回出栈的元素对象
*/
public Object pop() {
if (index != -1) {
return os[--index];
}
return null;
} public boolean isEmty() {
if (index == 0) {
return true;
} else {
return false;
}
} /**
* 输出栈中所有元素
*/
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < os.length; i++) {
if (os[i] != null)
sb.append(os[i]);
} return sb.toString();
} public static void main(String[] args) {
UsedStack us = new UsedStack();
System.out.println("===================元素入栈====================");
System.out.println("向栈添加三个元素");
String[] strs = { "您好!", "我叫和佑!", "我喜欢Java!" };
us.push(strs[0]);
System.out.println("添加元素后的栈为:" + us);
us.push(strs[1]);
System.out.println("添加元素后的栈为:" + us);
us.push(strs[2]);
System.out.println("添加元素后的栈为:" + us); System.out.println("===================元素出栈====================");
for (int i = 0; i < us.os.length; i++) {
if (!us.isEmty()) {
System.out.println("删除元素");
System.out.println(us.pop());
} else {
System.out.println();
}
}
} }
注:从本实例可以看出:1.要想获取到适当的值,需要对类型进行强制转换,而本实例则通过重定义toString方法实现。
2.在本实例任何类型都可入栈,这意味着若是InputStream等类型入栈,在调用toString方法时将会抛出异常。如:将上面的代码:us.push(strs[0]);
转换成:us.push(new InputStreamReader(System.in, "xhj"));
将会抛出:Exception in thread "main" java.io.UnsupportedEncodingException: xhj
at sun.nio.cs.StreamDecoder.forInputStreamReader(StreamDecoder.java:52)
at java.io.InputStreamReader.<init>(InputStreamReader.java:83)
at com.xhj.generics.unused.UsedStack.main(UsedStack.java:67)
使用泛型实现栈结构:
1.泛型是Java中的一个重要特性,使用泛型编程可以使代码获得最大的重要。
2.在使用泛型时要指明泛型的具体类型,这样可以避免类型转换。
3.泛型类是一个参数类型可变的类;固泛型参数只能是类类型。
代码实例:
package com.xhj.generics.used; import java.util.LinkedList; /**
* 使用泛型实现栈的使用
*
* @author XIEHEJUN
*
* @param <T>
*/
public class UsedStack<T> {
private LinkedList<T> list = new LinkedList<T>(); /**
* 入栈 向栈添加元素
*
* @param
*/
public void push(T t) {
list.addFirst(t);
} /**
* 出栈 删除元素
*
* @return
*/
public T pop() {
return list.removeFirst();
} /**
* 判断栈是否为空
*
* @return
*/
public boolean isEmty() {
if (list.size() == 0) {
return true;
} else {
return false;
}
} /**
* 重写toString方法
*/
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
if (list.get(i) != null)
sb.append(list.get(i));
}
return sb.toString();
} public static void main(String[] args) {
UsedStack<String> us = new UsedStack<String>();
System.out.println("===================元素入栈====================");
System.out.println("向栈添加三个元素"); String[] strs = { "您好!", "我叫和佑!", "我喜欢Java!" };
us.push(strs[0]);
System.out.println("添加元素后的栈为:" + us);
us.push(strs[1]);
System.out.println("添加元素后的栈为:" + us);
us.push(strs[2]);
System.out.println("添加元素后的栈为:" + us); System.out.println("===================元素出栈====================");
for (int i = us.list.size() - 1; i >= 0; i--) {
if (!us.isEmty()) {
System.out.println("删除元素");
System.out.println(us.pop());
System.out.println("栈中元素还有个数为:" + i);
} else {
System.out.println("栈内已没有元素");
}
} }
}
注:泛型可以很好的解决上面出现的那两个问题,他的主要魅力就在于让程序有更好的可读性和安全性。
自定义泛型化数组类:
1.在Java虚拟机中并没有泛型类型的对象,所有有关泛型的信息都被擦除了。这虽然可以避免C++语言
的模版代码膨胀问题,但是也引起了其他问题。如:不能直接创建泛型数组等。2.Java中的泛型不支持实例化类型变量。
3.通过Java的反射机制创建一个泛型化数组
newInstance(Class<?> componentType,int length)
代码实例:
package com.xhj.generics.used; import java.lang.reflect.Array; /**
* 利用Java反射机制泛型化数组
*
* @author XIEHEJUN
*
* @param <T>数组类型
*/
public class GenericsArray<T> {
private T[] array;
private int size; /**
* 泛型化数组构造函数
*
* @param type
* 数组类型
* @param size
* 数组长度
*/
@SuppressWarnings("unchecked")
public GenericsArray(Class<T> type, int size) {
array = (T[]) Array.newInstance(type, size);
this.size = size;
} /**
* 向泛型化数组添加元素
*
* @param index
* @param item
*/
public void put(int index, T item) {
if (index >= 0 && index < size) {
array[index] = item;
}
} /**
* 根据数组下标获取相应值
*
* @param index
* @return
*/
public T get(int index) {
if (index >= 0 && index < size) {
return array[index];
}
return null;
} /**
* 将泛型化数组打印输出
*
* @param t
*/
public void printService(T[] t) {
put(0, t[0]);
System.out.println("添加的元素为:" + get(0));
put(1, t[1]);
System.out.println("添加的元素为:" + get(1));
put(2, t[2]);
System.out.println("添加的元素为:" + get(2));
} public static void main(String[] args) {
System.out.println("向泛型化数组添加String元素");
GenericsArray<String> gStrArray = new GenericsArray<String>(
String.class, 3);
String[] strs = { "您好!", "我叫和佑!", "我喜欢Java!" };
gStrArray.printService(strs); System.out.println("\n向泛型化数组添加Integer元素");
GenericsArray<Integer> gIntArray = new GenericsArray<Integer>(
Integer.class, 3);
Integer[] arrays = { 10, 52, 32 };
gIntArray.printService(arrays);
} }
总结:
Java泛型的局限性1.不能使用基本类型作为其类型参数;
2.不能抛出或捕获泛型类型的实例、
3.不能直接使用泛型数组、
4.不能实例化类型变量
5.对于某些不足,可以通过Java的反射机制进行弥补。
泛型方法与数据查询
众所周知在使用JDBC查询数据库中数据的时候,返回的结果是ResultSet对象,这种机制,
我们在实际使用过程中是很不方便的。当然Java还提供了Commons DbUtils组件来将ResultSet转化为Bean列表的方法,但是该在使用的时候是需要根据不同的Bean对象创建不同的查询方法的。
下面我将在此方法基础上使用泛型进行包装,以便提高它的通用性。
在Java中,不仅可以声明泛型类,还可以声明泛型方法:
1.使用<T>格式来表示泛型类型参数,参数个数可多个;
2.类型参数列表要放在访问权限修饰符、static和final之后;
3.类型参数列表要放在返回值类型、方法名称、方法参数之前。
代码实例:
对象实体类
package com.xhj.generics.used.entity; /**
* 用户实体类
*
* @author XIEHEJUN
*
*/
public class User {
private String userName;
private String userId;
private int userAge;
private String userAddress;
private String gende;
private long userTell; public User() {
super();
} public User(String userName, String userId, int userAge,
String userAddress, String gende, long userTell) {
this.userName = userName;
this.userId = userId;
this.userAge = userAge;
this.userAddress = userAddress;
this.gende = gende;
this.userTell = userTell;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getUserId() {
return userId;
} public int getUserAge() {
return userAge;
} public void setUserAge(int userAge) {
this.userAge = userAge;
} public String getUserAddress() {
return userAddress;
} public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
} public String getGende() {
return gende;
} public void setGende(String gende) {
this.gende = gende;
} public long getUserTell() {
return userTell;
} public void setUserTell(long userTell) {
this.userTell = userTell;
} @Override
public String toString() {
return "User{" + "\n\tuserId =" +userId+ "\n\tuserName =" + userName
+ "\n\tuserAge =" + userAge + "\n\tgende =" + gende
+ "\n\tuserAddress =" + userAddress + "\n\tuserTell =" + userTell
+ "\n\t}";
}
}
泛型数据访问操作类
package com.xhj.generics.used.dao; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List; import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler; /**
* 数据库操作类,定义增删改查等操作方法
*
* @author XIEHEJUN
*
*/
public class GenericQuery {
private static String URL = "jdbc:oracle:thin:@192.168.100.13:1521:SIGMA";
private static String DRIVRR = "ojdbc6";
private static String USER = "PCD_Online_V2";
private static String PASSWORD = "password";
private static Connection con; /**
* 获取数据库连接
*
* @return
*/
public static Connection getConnecton() {
DbUtils.loadDriver(DRIVRR);
try {
con = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
System.out.println("连接失败");
}
return con;
} /**
* 查询数据
*
* @param sql
* SQL语句
* @param type
* 实体类类型
* @return
*/
@SuppressWarnings("unchecked")
public static <T> List<T> query(String sql, Class<T> type) {
QueryRunner qr = new QueryRunner();
List<T> list = null;
try {
list = (List<T>) qr.query(getConnecton(), sql, new BeanListHandler(
type));
} catch (SQLException e) {
System.out.println("SQL语句不正确");
e.printStackTrace();
}finally{
DbUtils.closeQuietly(con);
}
return list;
} /**
* 更新数据--增/删/改
*/
public static void queryUpdate(String sql) {
QueryRunner qr = new QueryRunner();
try {
qr.update(getConnecton(), sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
DbUtils.closeQuietly(con);
}
}
}
业务操作类
package com.xhj.generics.used.service; import java.util.List;
import com.xhj.generics.used.dao.GenericQuery;
import com.xhj.generics.used.entity.User; /**
* 调用数据库操作方法,对数据进行增删改查等操作
*
* @author XIEHEJUN
*
*/
public class Service {
/**
* 插入数据
*
* @param user
*/
public static void update(User user) {
String sql = "insert into XHJUSER values('" + user.getUserId() + "','"
+ user.getUserName() + "','" + user.getUserAge() + "','"
+ user.getGende() + "','" + user.getUserAddress() + "','"
+ user.getUserTell() + "')";
GenericQuery.queryUpdate(sql);
} /**
* 修改数据
*
* @param sql
*/
public static void update(String sql) {
GenericQuery.queryUpdate(sql);
} /**
* 查询数据
*
* @param user
* @param sql
*/
public static void select(User user, String sql) {
List<User> list = GenericQuery.query(sql, User.class);
System.out.println("表中数据有:");
for (int i = 0; i < list.size(); i++) {
System.out.println(i + "号对象属性值为:" + list.get(i));
}
} /**
* 删除数据
*
* @param user
*/
public static void delete(String sql) {
GenericQuery.queryUpdate(sql);
}
}
测试类:
package com.xhj.generics.used.main; import com.xhj.generics.used.entity.User;
import com.xhj.generics.used.service.Service; /**
* 测试类
*
* @author XIEHEJUN
*
*/
public class Test { public static void main(String[] args) {
User user = new User("B", java.util.UUID.randomUUID().toString(), 12,
"湖南", "女", 1213344455);
Service.update(user); String sql = "select * from XHJUser where username = 'B'";
Service.select(user, sql); sql = "update XHJuser set username = 'D' where userid ='1ab3ee1b-1c52-43d2-8df5-ffefb92c9c5c'";
Service.update(sql); sql = "delete from XHJuser where username = 'C'";
Service.delete(sql);
} }
注:泛型类与泛型方法的重要区别
1.在使用泛型类时,需要注意不能将泛型参数类型用于静态域和静态方法中,而对于泛型方法则可以是静态的。2.这种区别主要是"擦除"产生的。由于在泛型方法中已经指明了参数的具体类型,故即使发生擦除,也不会丢失。
泛型化方法与最小值
1.在Java中除了数值可以比较大小外,任何实现了Comparable接口的类的实例,都可以比较大小。
2.在比较类的对象是,需要限制比较的对象实现Comparable接口即:<T extends Comparable>3.当泛型参数类型被限制为接口的子类型时,也使用extends关键字。
代码实例:
package com.xhj.generics.used; /**
* 利用泛型比较类对象实例大小
*
* @author XIEHEJUN
*
*/
public class GenericComparable {
/**
* 比较并获取最小类对象实例
*
* @param array
* @return
*/
public static <T extends Comparable<T>> T getMin(T[] array) {
if (array.length == 0 || array == null) {
return null;
} else {
T min = array[0];
for (int i = 0; i < array.length; i++) {
if (min.compareTo(array[i]) > 0) {
min = array[i];
}
}
return min;
}
} public static void main(String[] args) {
String[] strs = { "您好!我是和佑b,来自和佑博客园", "您好!我是和佑a,来自和佑博客园",
"您好!我是和佑c,来自和佑博客园" };
System.out.println("最小的类对象实例为:" + getMin(strs));
} }
注:1.compareTo()方法先是逐步比较ASCII码,若是此时仍无法得出结果,再比较其长度
2.泛型类型参数的限定一般有两种情况:a.小于某一个"范围"
b.大于某一个"范围"
范围即可以是一个类,也可以是一个接口,还可以是类和接口的组合,对于组合来说,需要将类放在第一位,并且用&分隔。
泛型化接口与最大值
1.在Java中除了可以定义类和方法,还可以定义泛型接口。泛型接口的作用和普通接口一样,只是它的实用性更强。对于很多具体类型通用的方法,可以将其提取到一个泛型接口中,再编写一个泛型类实现这个接口即可。
2.定义泛型接口和定义泛型类是相似的,直接在接口名称后面加上<T>即可。T就是泛型类型参数,可以是多个。
3.在实现此接口时要注意,实现类的泛型参数和接口的泛型参数要相匹配。
代码实例:
泛型接口
package com.xhj.generics.used.ginterface; /**
* 定义一个泛型接口
*
* @author XIEHEJUN
*
*/
public interface GenericComparableInterface {
public <T extends Comparable<T>> T getMax(T[] array);
}
实现泛型接口
package com.xhj.generics.used.ginterface; public class GenericComparableImp implements GenericComparableInterface { @Override
public <T extends Comparable<T>> T getMax(T[] array) {
if(array==null||array.length==0){
return null;
}else{
T max = array[0];
for (int i = 0; i < array.length; i++) {
if(max.compareTo(array[i])<0){
max = array[i];
}
}
return max;
}
} public static void main(String[] args) {
GenericComparableImp gci = new GenericComparableImp();
String[] strs = { "您好!我是和佑b,来自和佑博客园", "您好!我是和佑a,来自和佑博客园",
"您好!我是和佑c,来自和佑博客园" };
System.out.println("最小的类对象实例为:" +gci.getMax(strs));
}
}
注:泛型接口的应用
一个大型网站的后台往往使用多个数据表,可以将一些公共的操作如数据的增删改以及保存等放在一个泛型的DAO接口中定义,在针对使用的持久层技术,编写此DAO的实现类,这些对于每一个持久化的对象,直接继承这个实现类,再去实现特有方法即可。
使用通配符增强泛型
1.Java中的数组支持协变类型,即如果方法参数是数组T,而S是T的子类,则方法也可以使用参数S。对于泛型类则没有这个特性。
为了弥补这个不足,Java推出了通配符类型参数。2.使用通配符"?"可以让泛型在实际应用当中更加的灵活
3.通配符可以利用"extends"关键字来设置取值上限,如:<? extends Number>,参数类型要求继承Number
4.通配符可以设置取值下限,如:<?super Number>,参数类型要求是Number的父类
5.通配符可有多个"界限",如:实现多个接口,在接口间用&分隔。
代码实例:
package com.xhj.generics.used; import java.util.ArrayList;
import java.util.List; /**
* 通配符在泛型中作用
*
* @author XIEHEJUN
*
*/
public class Wildcard {
/**
* 获取基于Number父类下的list的中间数
*
* @param list
* @return
*/
public static Object getMiddle(List<? extends Number> list) {
return list.get(list.size() / 2);
} /**
* 获取任何继承Object的List下的中间值
*
* @param list
* @return
*/
public static Object getMiddles(List<? extends Object> list) {
return list.get(list.size() / 2);
} public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(182);
list.add(0115);
list.add(8);
list.add(502);
list.add(233);
System.out.println(getMiddle(list).toString()); List<String> liststr = new ArrayList<String>();
liststr.add("您好!");
liststr.add("吃饭了吗!");
liststr.add("美女!");
liststr.add("下午有空吗!");
liststr.add("看电影去吧!");
System.out.println(getMiddles(liststr).toString());
} }
泛型化的折半查找法
1.查找就是在一组给定的数据集合中找出满足条件的数据。
2.折半查找要求数据集合中的元素必须可比较,且各元素按升序或者降序排列:取集合的中间元素作为比较对象,则:
a.如果给定的值与比较对象相等,则查找成功,并返回中间元素的序号。
b.若大于比较对象,则在中间元素的右半段进行查找
c.若小于比较对象,则在中间元素的左半段进行查找
3.循环执行上述过程,直至查找成功,此时折半查找的平均时间复杂度是log2n
代码实例:
package com.xhj.generics.used; /**
* 泛型化折半查找算法
*
* @author XIEHEJUN
*
*/
public class HalfSearch { /**
* 折半查找的实现方法
*
* @param key
* @param array
* @return
*/
public static <T extends Comparable<? super T>> int search(T key, T[] array) {
int low = 0;
int high = array.length - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (key.compareTo(array[mid]) == 0) {
return mid;
} else if (key.compareTo(array[mid]) > 0) {
low += 1;
} else {
high -= 1;
}
}
return -1;
} public static void main(String[] args) {
Integer[] array = { 12, 3, 8, 45, 26, 68 };
String str = "GFISUDGHUIW";
String[] arraystr = { str, "GYFSGHFUIH", "CD" };
System.out.println("在String数组中'GFISUDGHUIW'的索引为:"
+ search(str, arraystr));
System.out.println("在整型数组中'3'的索引为:" + search(3, array));
} }
Java笔记--泛型总结与详解的更多相关文章
- java笔记--枚举总结与详解
由于工作原因,已经有两礼拜没有更新博客了,好不容易完成了工作项目,终于又可以在博客园上愉快的玩耍了. 嗯,今天下午梳理了一下关于java枚举的笔记,比较长,不过还是觉得挺厚实的,哈哈,有出入的地方,欢 ...
- java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET
java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了! 社区福利快来领取免费参加MDCC大会机会哦 Tag功能介绍—我们 ...
- 使用Java操作文本文件的方法详解
使用Java操作文本文件的方法详解 摘要: 最初java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了Reader和Writer两个类 最初java是不支持对文本文件的处理的,为了弥补这个缺憾而 ...
- Java网络编程和NIO详解9:基于NIO的网络编程框架Netty
Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...
- JAVA反射概念及使用详解(超详细)
JAVA反射概念及使用详解 一.什么是反射? 反射:框架设计的灵魂 框架:半成品软件.可以在框架的基础上进行软件开发,简化编码 反射:将类的各个组成部分封装为其他对象,这就是反射机制 好处: ...
- 【山外笔记-数据库】Memcached详解教程
本文打印版文档下载地址 [山外笔记-数据库]Memcached详解教程-打印版.pdf 一.Memcached数据库概述 1.Memcached简介 (1)Memcached是一个自由开源的,高性能, ...
- Java开发利器Myeclipse全面详解
Java开发利器Myeclipse全面详解: Ctrl+1:修改代码错误 Alt+Shift+S:Source命令 Ctrl+7:单行注释 Ctrl+Shift+/ :多行注释 Ctrl+I :缩进( ...
- Java中的main()方法详解
在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是 ...
- [译]Java Thread join示例与详解
Java Thread join示例与详解 Java Thread join方法用来暂停当前线程直到join操作上的线程结束.java中有三个重载的join方法: public final void ...
随机推荐
- HoloLens开发手记 - Unity之Spatial mapping 空间映射
本文主要讨论如何在Unity项目中集成空间映射功能.Unity内置了对空间映射功能的支持,通过以下两种方式提供给开发者: HoloToolkit项目中你可以找到空间映射组件,这可以让你便捷快速地开始使 ...
- HoloLens开发手记 - Known issues 已知问题
本文主要提及一份问题清单,这些问题都可能对我们开发HoloLens应用造成困扰. Visual Studio 在使用VS 2015 Update 1连接HoloLens时,可能会有些小问题.但是这些小 ...
- Quartz.NET syudy
Quartz.NET Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它 ...
- 聊聊HTTPS和SSL_TLS协议
要说清楚 HTTPS 协议的实现原理,至少需要如下几个背景知识. 1. 大致了解几个基本术语(HTTPS.SSL.TLS)的含义 2. 大致了解 HTTP 和 TCP 的关系(尤其是“短连接”VS“长 ...
- 论Visual Studio和.NET Framework
今天在工作的时候听到一席谈话感觉有点不可思议,微软真的是把开发人员惯的有点傻了,微软流水线式的产品让很多开发者认定了"唯一",这当然也说明了微软的成功,不扯太多题外话,今天只是简单 ...
- iOS开发中的错误整理,线程之间通信练习,加载图片的练习中出现的错误 -- Http请求错误
控制台打印:Application Transport Security has blocked a cleartext HTTP (http://) resource load since it i ...
- .NET Core 工具从 project.json 移动到基于 MSBuild 的项目后的使用
.NET Core 从preview 4 开始弃用project.json 可以从这下载最新版本: https://github.com/dotnet/cli 使用VS2017 RC新建.net co ...
- Java基础-序列化
Java序列化是将一个对象编码成一个字节流,反序列化将字节流编码转换成一个对象. 序列化是Java中实现持久化存储的一种方法: 为数据传输提供了线路级对象表示法. Java的序列化机制是通过在运行时判 ...
- 解决Oracle忘记密码问题
在使用ORACLE的过程中,会出现各种各样的问题,各种各样的错误,其中ORA-12899就是前段时间我在将数据导入到我本地机器上的时候一直出现的问题.不过还好已经解决了这个问题,现在分享一下,解决方案 ...
- 21.Android之SQLite数据库学习
Google为Andriod的较大的数据处理提供了SQLite,他在数据存储.管理.维护等各方面都相当出色,功能也非常的强大.SQLite具备下列特点: 1.轻量级 使用 SQLite 只需要带一个动 ...