1、泛型-參數化類型
即:將類型由原來的具體的類型參數化
比如一個方法,方法參數是什麼類型,返回值就是什麼類型,由於寫方法之前並不知道調用者會傳入什麼類型的參數,所以就將參數的類型參數化;
A.帶泛型的方法-泛型方法
<E> 爲定義泛型,在修飾符與返回值之間
private <E> E getMethod(E e){
return e;
}
B.帶泛型的類-泛型類
<T> 爲定義泛型,在類名之後
public class MyDataList<T>{
private List<T> data;
}
C.帶泛型的接口-泛型接口
<T> 爲定義泛型,在類名之後
public interface myinterface<T>{
public void method1(T t);
}
實現接口的時候可以指定泛型的具體類型,也可以仍然使用泛型
2、泛型的好處
A.避免類型轉換
B.將運行期異常提前在編譯期檢查出來
3、特性
泛型只在編譯期有效,編譯之後程序會採取去泛型化的措施,泛型信息不會進入到運行階段。
4、注意:泛型的類型只能是類類型,不能是簡單類型,比如只能是Integer,不能夠是int。
5、泛型通配符-?
public void method1(?){
}
通配符-指定上限類型和下限類型(詳情見com.huangliwei.generic.GenericTest.method1Test)
泛型小demo——利用jdbc實現簡單的sql查詢和對象的自動封裝
查詢類:JDBCHandler
package com.huangliwei.generic;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JDBCHandler {
private String username;
private String password;
private String url;
private Connection connection;
static {
//加載jdbc驅動
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public JDBCHandler(String username, String password, String url) {
this.username = username;
this.password = password;
this.url = url;
//初始化連接
try {
connection = DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 執行查詢sql返回一個查詢對象
*
* @param sql
* @param clazz
* @param <T>
* @return
*/
public <T> T queryOne(String sql, Class<T> clazz) throws SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
return parseResultSetToObj(rs, clazz);
}
return null;
}
/**
* 執行查詢sql返回多個對象
*
* @param sql
* @param clazz
* @param <T>
* @return
* @throws SQLException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public <T> List<T> queryMany(String sql, Class<T> clazz) throws SQLException, IllegalAccessException, InstantiationException, InvocationTargetException {
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);
ArrayList<T> result = new ArrayList<>();
while (rs.next()) {
result.add(parseResultSetToObj(rs, clazz));
}
return result;
}
/**
* 查詢結果封裝成對象
*
* @param rs
* @param clazz
* @param <T>
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SQLException
* @throws InvocationTargetException
*/
private <T> T parseResultSetToObj(ResultSet rs, Class<T> clazz) throws IllegalAccessException, InstantiationException, SQLException, InvocationTargetException {
//實例化對象
T t = clazz.newInstance();
//獲取所有的public方法
Method[] methods = clazz.getMethods();
String[] columns = getColumns(rs);
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
String methodName = method.getName();
if (methodName.startsWith("set")) {
for (int j = 0; j < columns.length; j++) {
String columnName = columns[j];
if (methodName.equalsIgnoreCase("set" + columnName)) {
//假設簡單類型的封裝,粗糙處理
method.invoke(t, rs.getObject(columnName));
break;
}
}
}
}
return t;
}
/**
* 獲取查詢返回的所有列名
*
* @param rs
* @return
* @throws SQLException
*/
private String[] getColumns(ResultSet rs) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
String[] columns = new String[columnCount];
for (int i = 0; i < columnCount; i++) {
columns[i] = metaData.getColumnName(i + 1);
}
return columns;
}
}
測試類:JDBCHandlerTest
package com.huangliwei.generic;
import com.huangliwei.entity.UserInfo;
import org.junit.Test;
import java.util.List;
public class JDBCHandlerTest {
@Test
public void queryOneTest() throws Exception {
String username = "root";
String sql = "select * from userinfo limit 1;";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/yuleishangran?useUnicode=true&characterEncoding=utf8";
JDBCHandler handler = new JDBCHandler(username, password, url);
UserInfo userInfo = handler.queryOne(sql, UserInfo.class);
System.out.println(userInfo);
}
@Test
public void queryManyTest() throws Exception {
String username = "root";
String sql = "select * from userinfo;";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/yuleishangran?useUnicode=true&characterEncoding=utf8";
JDBCHandler handler = new JDBCHandler(username, password, url);
List<UserInfo> userInfos = handler.queryMany(sql, UserInfo.class);
System.out.println(userInfos);
}
}
實體:UserInfo
package com.huangliwei.entity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
public class UserInfo {
private String username;
private String password;
private Date birthday;
public UserInfo() {
}
public UserInfo(String username, String password, Date birthday) {
this.username = username;
this.password = password;
this.birthday = birthday;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserInfo userInfo = (UserInfo) o;
//用戶名相同就認爲對象一樣
return Objects.equals(username, userInfo.username);
}
@Override
public int hashCode() {
return Objects.hash(username, password, birthday);
}
@Override
public String toString() {
return "UserInfo{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(birthday) +
'}';
}
}
建表sql:
CREATE TABLE `userinfo` (
`username` VARCHAR ( 100 ) NOT NULL,
`password` VARCHAR ( 200 ) DEFAULT NULL,
`birthday` datetime DEFAULT NULL,
PRIMARY KEY ( `username` )
) ENGINE = INNODB DEFAULT CHARSET = utf8;
INSERT INTO userinfo
VALUES
( '張三', '123456', now( ) );
INSERT INTO userinfo
VALUES
( '李四', '654321', now( ) );
泛型通配符-GenericTest
package com.huangliwei.generic;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args) {
GenericClass<Integer> gc = new GenericClass<>();
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(123);
gc.setData(list1);
}
public void method1Test(){
GenericClass<String> gc1 = new GenericClass<String>();
GenericClass<Integer> gc2 = new GenericClass<Integer>();
//method1入參gc1、gc2都可以
method1(gc1);
method1(gc2);
//method2的參數只能是gc2,因爲方法入參指定了具體的類型爲Integer
//method2(gc1); 編譯報錯
method2(gc2);
}
// 泛型通配符-使用通配符
private static void method1(GenericClass<?> e){
}
// 泛型通配符-指定具體類型
private static void method2(GenericClass<Integer> e){
}
//泛型通配符-指定上限類型(必須是Number本身或其子類)
private static void method3(GenericClass<? extends Number> e){
}
//泛型通配符-指定下限類型(必須是Number本身或其父類)
private static void method4(GenericClass<? super Number> e){
}
}