簡體   English   中英

無法注冊JDBC驅動程序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM