[英]Can't register JDBC driver
我正在使用Java JDBC編寫應用程序,該應用程序查詢並將數據插入Oracle數據庫。
我正在使用來自springframework API的SimpleDriverDataSource來實現標准的JDBC DataSource接口。
這是我的代碼的一部分
dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(Class.forName(credentials.getDriverClass()));
我試圖使代碼獨立於所使用的DriverClass,而且我知道class.forName()
返回類字符串名稱的類對象。
問題是我收到一個編譯錯誤,說:
類型為SimpleDriverDataSource
setDriverClass(Class<? extends Driver>)
不適用於參數(Class<capture#1-of ?>
我不太了解這些符號的含義,或者是什么導致了錯誤?
SimpleDriverDataSource#setDriverClass(Class)
實現為
public void setDriverClass(Class<? extends Driver> driverClass) {
this.driver = BeanUtils.instantiateClass(driverClass);
}
因此,它期望的是Class
類型的對象,它是Driver
的子類型。
Class.forName(String)
方法實現為
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
換句話說,它返回Class<?>
對象,即。 任何類型的Class
對象,不一定是Driver
的子類型。 因此,返回對象的聲明類型不是setDriverClass()
方法的有效參數。
一種解決方案是自己實例化Driver
類,並改用setDriver(Driver)
方法
Class<?> clazz = Class.forName(credentials.getDriverClass());
Object driver = BeanUtils.instantiateClass(clazz);
dataSource.setDriver((Driver) driver);
請注意,如果您嘗試實例化的類不是Driver
的子類型,則以上內容將在運行時引發ClassCastException
。
另外, 根據BalusC的建議,您可以強制轉換 Class.forName()
返回的值。
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass((Class<Driver>)Class.forName("com.mysql.jdbc.Driver"));
如果您不喜歡IDE警告,請添加一些@SuppressWarnings
。
對於Java泛型來說,這是一個小技巧,值得一讀。
當您處理已知是一致的但在代碼中不是明確的類型參數時,就會發生問題。 如果要處理類型不完全的集合,這是很常見的。
為了使事情更清楚,我將使用以下示例:考慮一個將各種值從一個地方傳輸到另一個地方的系統(也許它是一個調度程序,用於在系統中發送不同類型的消息)。
我們可能有一個既可以提供也可以接收某些消息類型的接口:
public interface Connection<Type>
{
Type read();
void write(Type value);
}
我們的調度程序可能看起來像這樣:
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
for (Connection<?> cns: cnxs) {
cnx.write(cnx.read);
}
}
}
(請注意,這是簡寫形式,我們在這里使用它是因為cnxs集合包含具有各種不同類型參數的Connections)。
不幸的是,它將無法編譯! Eclipse與Java 1.6給出的錯誤是“連接類型中的方法write(capture#2-of?)不適用於參數(capture#3-of?)”。
無法編譯的原因是Connection所返回的值的type參數和它將接收的值的type參數被分別處理。 每個都被視為“捕獲?” 意思是“對象的某些子類”。 然后,編譯器(可以理解)說:“我無法將'對象的子類X'發送給需要'對象的子類Y'的方法,因為我不知道它們是否是相同的子類”。
為了完成這項工作,我們需要顯式引入公共類型參數。 不幸的是,以下代碼或類似的代碼不起作用(據我所知)。 沒有辦法在代碼塊的中間引入類型參數(我們真正想要的是更好地支持多態):
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
// syntax error!
for (<E> Connection<E> cns: cnxs) {
E value = cnx.read();
cnx.write(value);
}
}
}
但是我們可以做的是添加一個引入新類型參數的輔助方法:
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
for (Connection<?> cnx: cnxs) {
helper(cnx);
}
}
private <E> void helper(Connection<E> cnx)
{
E value = cnx.read();
cnx.write(value);
}
}
這就是我們想要的! 該代碼驗證,編譯和運行。
總而言之:有時您可以“刪除”一個顯式的泛型類型參數(通常是因為您要處理的是不同類型的集合)。 您可以通過添加額外的輔助方法來重新引入該類型參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.